improve error parsing and add tests
This commit is contained in:
parent
16eb2f816c
commit
2185fe95cc
|
@ -446,6 +446,7 @@
|
|||
C15993451D8829C00047950D /* stp_shipping_form.png in Resources */ = {isa = PBXBuildFile; fileRef = C15993201D8807930047950D /* stp_shipping_form.png */; };
|
||||
C15993461D8829C00047950D /* stp_shipping_form@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15993211D8807930047950D /* stp_shipping_form@2x.png */; };
|
||||
C15993471D8829C00047950D /* stp_shipping_form@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15993221D8807930047950D /* stp_shipping_form@3x.png */; };
|
||||
C15B02731EA176090026E606 /* StripeErrorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C15B02721EA176090026E606 /* StripeErrorTest.m */; };
|
||||
C16F66AB1CA21BAC006A21B5 /* STPFormTextFieldTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C16F66AA1CA21BAC006A21B5 /* STPFormTextFieldTest.m */; };
|
||||
C1717DB11CC00ED60009CF4A /* STPAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = C1080F471CBECF7B007B2D89 /* STPAddress.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C17A030D1CBEE7A2006C819F /* STPAddressFieldTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = C17A030B1CBEE7A2006C819F /* STPAddressFieldTableViewCell.h */; };
|
||||
|
@ -973,6 +974,7 @@
|
|||
C15993301D8808680047950D /* STPShippingMethodsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPShippingMethodsViewController.m; sourceTree = "<group>"; };
|
||||
C15993311D8808680047950D /* STPShippingMethodTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPShippingMethodTableViewCell.h; sourceTree = "<group>"; };
|
||||
C15993321D8808680047950D /* STPShippingMethodTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPShippingMethodTableViewCell.m; sourceTree = "<group>"; };
|
||||
C15B02721EA176090026E606 /* StripeErrorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StripeErrorTest.m; sourceTree = "<group>"; };
|
||||
C16F66AA1CA21BAC006A21B5 /* STPFormTextFieldTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPFormTextFieldTest.m; sourceTree = "<group>"; };
|
||||
C17A030B1CBEE7A2006C819F /* STPAddressFieldTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPAddressFieldTableViewCell.h; sourceTree = "<group>"; };
|
||||
C17A030C1CBEE7A2006C819F /* STPAddressFieldTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPAddressFieldTableViewCell.m; sourceTree = "<group>"; };
|
||||
|
@ -1491,6 +1493,7 @@
|
|||
C124A1801CCAA1BF007D42EE /* NSMutableURLRequest+StripeTest.m */,
|
||||
C1EEDCC71CA2172700A54582 /* NSString+StripeTest.m */,
|
||||
04CB86B81BA89CD400E4F61E /* PKPayment+StripeTest.m */,
|
||||
C15B02721EA176090026E606 /* StripeErrorTest.m */,
|
||||
C13538071D2C2186003F6157 /* STPAddCardViewControllerTest.m */,
|
||||
C1080F4B1CBED48A007B2D89 /* STPAddressTests.m */,
|
||||
C12711091DBA7E490087840D /* STPAddressViewModelTest.m */,
|
||||
|
@ -2292,6 +2295,7 @@
|
|||
C13538081D2C2186003F6157 /* STPAddCardViewControllerTest.m in Sources */,
|
||||
04415C671A6605B5001225ED /* STPAPIClientTest.m in Sources */,
|
||||
045D71311CF514BB00F6CD65 /* STPBinRangeTest.m in Sources */,
|
||||
C15B02731EA176090026E606 /* StripeErrorTest.m in Sources */,
|
||||
C1EF044E1DD2397C00FBF452 /* STPShippingMethodsViewControllerLocalizationTests.m in Sources */,
|
||||
04415C681A6605B5001225ED /* STPFormEncoderTest.m in Sources */,
|
||||
C11810991CC6D46D0022FB55 /* NSDecimalNumber+StripeTest.m in Sources */,
|
||||
|
|
|
@ -24,8 +24,8 @@ typedef NS_ENUM(NSInteger, STPErrorCode) {
|
|||
#endif
|
||||
STPConnectionError = 40, // Trouble connecting to Stripe.
|
||||
STPInvalidRequestError = 50, // Your request had invalid parameters.
|
||||
STPAPIError = 60, // General-purpose API error (should be rare).
|
||||
STPCardError = 70, // Something was wrong with the given card (most common).
|
||||
STPAPIError = 60, // General-purpose API error.
|
||||
STPCardError = 70, // Something was wrong with the given card details.
|
||||
STPCancellationError = 80, // The operation was cancelled.
|
||||
STPCheckoutUnknownError = 5000, // Checkout failed
|
||||
STPCheckoutTooManyAttemptsError = 5001, // Too many incorrect code attempts
|
||||
|
@ -44,6 +44,14 @@ FOUNDATION_EXPORT NSString * __nonnull const STPCardErrorCodeKey;
|
|||
// right UI element.
|
||||
FOUNDATION_EXPORT NSString * __nonnull const STPErrorParameterKey;
|
||||
|
||||
// The error code returned by the Stripe API.
|
||||
// https://stripe.com/docs/api#errors-type
|
||||
FOUNDATION_EXPORT NSString * __nonnull const STPStripeErrorCodeKey;
|
||||
|
||||
// The error type returned by the Stripe API.
|
||||
// https://stripe.com/docs/api#errors-code
|
||||
FOUNDATION_EXPORT NSString * __nonnull const STPStripeErrorTypeKey;
|
||||
|
||||
#pragma mark STPCardErrorCodeKeys
|
||||
|
||||
typedef NSString * STPCardErrorCode
|
||||
|
|
|
@ -15,6 +15,8 @@ NSString *const StripeDomain = @"com.stripe.lib";
|
|||
NSString *const STPCardErrorCodeKey = @"com.stripe.lib:CardErrorCodeKey";
|
||||
NSString *const STPErrorMessageKey = @"com.stripe.lib:ErrorMessageKey";
|
||||
NSString *const STPErrorParameterKey = @"com.stripe.lib:ErrorParameterKey";
|
||||
NSString *const STPStripeErrorCodeKey = @"com.stripe.lib:StripeErrorCodeKey";
|
||||
NSString *const STPStripeErrorTypeKey = @"com.stripe.lib:StripeErrorTypeKey";
|
||||
NSString *const STPInvalidNumber = @"com.stripe.lib:InvalidNumber";
|
||||
NSString *const STPInvalidExpMonth = @"com.stripe.lib:InvalidExpiryMonth";
|
||||
NSString *const STPInvalidExpYear = @"com.stripe.lib:InvalidExpiryYear";
|
||||
|
@ -32,57 +34,58 @@ NSString *const STPIncorrectCVC = @"com.stripe.lib:IncorrectCVC";
|
|||
if (!errorDictionary) {
|
||||
return nil;
|
||||
}
|
||||
NSString *type = errorDictionary[@"type"];
|
||||
NSString *devMessage = errorDictionary[@"message"];
|
||||
NSString *parameter = errorDictionary[@"param"];
|
||||
NSString *errorType = errorDictionary[@"type"];
|
||||
NSString *errorParam = errorDictionary[@"param"];
|
||||
NSString *stripeErrorMessage = errorDictionary[@"message"];
|
||||
NSString *stripeErrorCode = errorDictionary[@"code"];
|
||||
NSInteger code = 0;
|
||||
|
||||
// There should always be a message and type for the error
|
||||
if (devMessage == nil || type == nil) {
|
||||
NSDictionary *userInfo = @{
|
||||
NSLocalizedDescriptionKey: [self stp_unexpectedErrorMessage],
|
||||
STPErrorMessageKey: @"Could not interpret the error response that was returned from Stripe."
|
||||
};
|
||||
return [[self alloc] initWithDomain:StripeDomain code:STPAPIError userInfo:userInfo];
|
||||
}
|
||||
|
||||
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
userInfo[STPErrorMessageKey] = devMessage;
|
||||
|
||||
if (parameter) {
|
||||
userInfo[STPErrorParameterKey] = [STPFormEncoder stringByReplacingSnakeCaseWithCamelCase:parameter];
|
||||
userInfo[STPStripeErrorCodeKey] = stripeErrorCode;
|
||||
userInfo[STPStripeErrorTypeKey] = errorType;
|
||||
if (errorParam) {
|
||||
userInfo[STPErrorParameterKey] = [STPFormEncoder stringByReplacingSnakeCaseWithCamelCase:errorParam];
|
||||
}
|
||||
|
||||
if ([type isEqualToString:@"api_error"]) {
|
||||
if (stripeErrorMessage) {
|
||||
userInfo[NSLocalizedDescriptionKey] = stripeErrorMessage;
|
||||
userInfo[STPErrorMessageKey] = stripeErrorMessage;
|
||||
} else {
|
||||
userInfo[NSLocalizedDescriptionKey] = [self stp_unexpectedErrorMessage];
|
||||
userInfo[STPErrorMessageKey] = @"Could not interpret the error response that was returned from Stripe.";
|
||||
}
|
||||
if ([errorType isEqualToString:@"api_error"]) {
|
||||
code = STPAPIError;
|
||||
userInfo[NSLocalizedDescriptionKey] = [self stp_unexpectedErrorMessage];
|
||||
} else if ([type isEqualToString:@"invalid_request_error"]) {
|
||||
code = STPInvalidRequestError;
|
||||
userInfo[NSLocalizedDescriptionKey] = devMessage;
|
||||
} else if ([type isEqualToString:@"card_error"]) {
|
||||
code = STPCardError;
|
||||
NSDictionary *errorCodes = @{
|
||||
@"incorrect_number": @{@"code": STPIncorrectNumber, @"message": [self stp_cardErrorInvalidNumberUserMessage]},
|
||||
@"invalid_number": @{@"code": STPInvalidNumber, @"message": [self stp_cardErrorInvalidNumberUserMessage]},
|
||||
@"invalid_expiry_month": @{@"code": STPInvalidExpMonth, @"message": [self stp_cardErrorInvalidExpMonthUserMessage]},
|
||||
@"invalid_expiry_year": @{@"code": STPInvalidExpYear, @"message": [self stp_cardErrorInvalidExpYearUserMessage]},
|
||||
@"invalid_cvc": @{@"code": STPInvalidCVC, @"message": [self stp_cardInvalidCVCUserMessage]},
|
||||
@"expired_card": @{@"code": STPExpiredCard, @"message": [self stp_cardErrorExpiredCardUserMessage]},
|
||||
@"incorrect_cvc": @{@"code": STPIncorrectCVC, @"message": [self stp_cardInvalidCVCUserMessage]},
|
||||
@"card_declined": @{@"code": STPCardDeclined, @"message": [self stp_cardErrorDeclinedUserMessage]},
|
||||
@"processing_error": @{@"code": STPProcessingError, @"message": [self stp_cardErrorProcessingErrorUserMessage]},
|
||||
};
|
||||
NSDictionary *codeMapEntry = errorCodes[errorDictionary[@"code"]];
|
||||
|
||||
if (codeMapEntry) {
|
||||
userInfo[STPCardErrorCodeKey] = codeMapEntry[@"code"];
|
||||
userInfo[NSLocalizedDescriptionKey] = codeMapEntry[@"message"];
|
||||
} else {
|
||||
if ([errorType isEqualToString:@"invalid_request_error"]) {
|
||||
code = STPInvalidRequestError;
|
||||
} else if ([errorType isEqualToString:@"card_error"]) {
|
||||
code = STPCardError;
|
||||
} else {
|
||||
userInfo[STPCardErrorCodeKey] = errorDictionary[@"code"];
|
||||
userInfo[NSLocalizedDescriptionKey] = devMessage;
|
||||
code = STPAPIError;
|
||||
}
|
||||
NSDictionary *codeMap = @{
|
||||
@"incorrect_number": @{@"code": STPIncorrectNumber, @"message": [self stp_cardErrorInvalidNumberUserMessage]},
|
||||
@"invalid_number": @{@"code": STPInvalidNumber, @"message": [self stp_cardErrorInvalidNumberUserMessage]},
|
||||
@"invalid_expiry_month": @{@"code": STPInvalidExpMonth, @"message": [self stp_cardErrorInvalidExpMonthUserMessage]},
|
||||
@"invalid_expiry_year": @{@"code": STPInvalidExpYear, @"message": [self stp_cardErrorInvalidExpYearUserMessage]},
|
||||
@"invalid_cvc": @{@"code": STPInvalidCVC, @"message": [self stp_cardInvalidCVCUserMessage]},
|
||||
@"expired_card": @{@"code": STPExpiredCard, @"message": [self stp_cardErrorExpiredCardUserMessage]},
|
||||
@"incorrect_cvc": @{@"code": STPIncorrectCVC, @"message": [self stp_cardInvalidCVCUserMessage]},
|
||||
@"card_declined": @{@"code": STPCardDeclined, @"message": [self stp_cardErrorDeclinedUserMessage]},
|
||||
@"processing_error": @{@"code": STPProcessingError, @"message": [self stp_cardErrorProcessingErrorUserMessage]},
|
||||
};
|
||||
NSDictionary *codeMapEntry = codeMap[stripeErrorCode];
|
||||
NSDictionary *cardErrorCode = codeMapEntry[@"code"];
|
||||
NSString *localizedMessage = codeMapEntry[@"message"];
|
||||
if (cardErrorCode) {
|
||||
userInfo[STPCardErrorCodeKey] = cardErrorCode;
|
||||
}
|
||||
if (localizedMessage) {
|
||||
userInfo[NSLocalizedDescriptionKey] = codeMapEntry[@"message"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return [[self alloc] initWithDomain:StripeDomain code:code userInfo:userInfo];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
//
|
||||
// StripeErrorTest.m
|
||||
// Stripe
|
||||
//
|
||||
// Created by Ben Guo on 4/14/17.
|
||||
// Copyright © 2017 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "StripeError.h"
|
||||
|
||||
@interface StripeErrorTest : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation StripeErrorTest
|
||||
|
||||
- (void)testEmptyResponse {
|
||||
NSDictionary *response = @{};
|
||||
NSError *error = [NSError stp_errorFromStripeResponse:response];
|
||||
XCTAssertNil(error);
|
||||
}
|
||||
|
||||
- (void)testResponseWithUnknownTypeAndNoMessage {
|
||||
NSDictionary *response = @{
|
||||
@"error": @{
|
||||
@"type": @"foo",
|
||||
@"code": @"error_code"
|
||||
}
|
||||
};
|
||||
NSError *error = [NSError stp_errorFromStripeResponse:response];
|
||||
XCTAssertEqual(error.domain, StripeDomain);
|
||||
XCTAssertEqual(error.code, STPAPIError);
|
||||
XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], [NSError stp_unexpectedErrorMessage]);
|
||||
XCTAssertEqual(error.userInfo[STPStripeErrorTypeKey], response[@"error"][@"type"]);
|
||||
XCTAssertEqual(error.userInfo[STPStripeErrorCodeKey], response[@"error"][@"code"]);
|
||||
XCTAssertTrue([error.userInfo[STPErrorMessageKey] hasPrefix:@"Could not interpret the error response"]);
|
||||
}
|
||||
|
||||
- (void)testAPIError {
|
||||
NSDictionary *response = @{
|
||||
@"error": @{
|
||||
@"type": @"api_error",
|
||||
@"message": @"some message"
|
||||
}
|
||||
};
|
||||
NSError *error = [NSError stp_errorFromStripeResponse:response];
|
||||
XCTAssertEqual(error.domain, StripeDomain);
|
||||
XCTAssertEqual(error.code, STPAPIError);
|
||||
XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], [NSError stp_unexpectedErrorMessage]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPErrorMessageKey], response[@"error"][@"message"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPStripeErrorTypeKey], response[@"error"][@"type"]);
|
||||
}
|
||||
|
||||
- (void)testInvalidRequestErrorMissingParameter {
|
||||
NSDictionary *response = @{
|
||||
@"error": @{
|
||||
@"type": @"invalid_request_error",
|
||||
@"message": @"The payment method `card` requires the parameter: card[exp_year].",
|
||||
@"param": @"card[exp_year]"
|
||||
}
|
||||
};
|
||||
NSError *error = [NSError stp_errorFromStripeResponse:response];
|
||||
XCTAssertEqual(error.domain, StripeDomain);
|
||||
XCTAssertEqual(error.code, STPInvalidRequestError);
|
||||
XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], response[@"error"][@"message"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPErrorMessageKey], response[@"error"][@"message"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPStripeErrorTypeKey], response[@"error"][@"type"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPErrorParameterKey], @"card[expYear]");
|
||||
}
|
||||
|
||||
- (void)testInvalidRequestErrorIncorrectNumber {
|
||||
NSDictionary *response = @{
|
||||
@"error": @{
|
||||
@"type": @"invalid_request_error",
|
||||
@"message": @"Your card number is incorrect.",
|
||||
@"code": @"incorrect_number"
|
||||
}
|
||||
};
|
||||
NSError *error = [NSError stp_errorFromStripeResponse:response];
|
||||
XCTAssertEqual(error.domain, StripeDomain);
|
||||
XCTAssertEqual(error.code, STPInvalidRequestError);
|
||||
XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], [NSError stp_cardErrorInvalidNumberUserMessage]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPCardErrorCodeKey], STPIncorrectNumber);
|
||||
XCTAssertEqualObjects(error.userInfo[STPStripeErrorTypeKey], response[@"error"][@"type"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPStripeErrorCodeKey], response[@"error"][@"code"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPErrorMessageKey], response[@"error"][@"message"]);
|
||||
}
|
||||
|
||||
- (void)testCardErrorIncorrectNumber {
|
||||
NSDictionary *response = @{
|
||||
@"error": @{
|
||||
@"type": @"card_error",
|
||||
@"message": @"Your card number is incorrect.",
|
||||
@"code": @"incorrect_number"
|
||||
}
|
||||
};
|
||||
NSError *error = [NSError stp_errorFromStripeResponse:response];
|
||||
XCTAssertEqual(error.domain, StripeDomain);
|
||||
XCTAssertEqual(error.code, STPCardError);
|
||||
XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], [NSError stp_cardErrorInvalidNumberUserMessage]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPCardErrorCodeKey], STPIncorrectNumber);
|
||||
XCTAssertEqualObjects(error.userInfo[STPStripeErrorTypeKey], response[@"error"][@"type"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPStripeErrorCodeKey], response[@"error"][@"code"]);
|
||||
XCTAssertEqualObjects(error.userInfo[STPErrorMessageKey], response[@"error"][@"message"]);
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in New Issue