From 12a23a06319ef4fe078c88869984328a3ce12387 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Tue, 6 Nov 2018 15:37:58 -0800 Subject: [PATCH 01/16] Remove `PaymentIntent.returnUrl` property Added TODOs to pull the replacement property in the right places. --- Stripe/PublicHeaders/STPPaymentIntent.h | 9 --------- Stripe/STPPaymentIntent.m | 3 --- Stripe/STPRedirectContext.m | 5 +++-- Tests/Tests/STPPaymentIntentFunctionalTest.m | 3 ++- Tests/Tests/STPPaymentIntentTest.m | 5 +++-- Tests/Tests/STPRedirectContextTest.m | 5 +++-- 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/Stripe/PublicHeaders/STPPaymentIntent.h b/Stripe/PublicHeaders/STPPaymentIntent.h index 942d0ec0f21..af01d2f13c9 100644 --- a/Stripe/PublicHeaders/STPPaymentIntent.h +++ b/Stripe/PublicHeaders/STPPaymentIntent.h @@ -83,15 +83,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, nullable, readonly) NSString *receiptEmail; -/** - The URL to redirect your customer back to after they authenticate or cancel their - payment on the payment method’s app or site. - - This should be a URL that your app handles if the PaymentIntent is going to - be confirmed in your app, and it has a redirect authorization flow. - */ -@property (nonatomic, nullable, readonly) NSURL *returnUrl; - /** The Stripe ID of the Source used in this PaymentIntent. */ diff --git a/Stripe/STPPaymentIntent.m b/Stripe/STPPaymentIntent.m index 591debc5eda..f780c4efec5 100644 --- a/Stripe/STPPaymentIntent.m +++ b/Stripe/STPPaymentIntent.m @@ -23,7 +23,6 @@ @interface STPPaymentIntent () @property (nonatomic, copy, nullable, readwrite) NSString *stripeDescription; @property (nonatomic, assign, readwrite) BOOL livemode; @property (nonatomic, copy, nullable, readwrite) NSString *receiptEmail; -@property (nonatomic, copy, nullable, readwrite) NSURL *returnUrl; @property (nonatomic, copy, nullable, readwrite) NSString *sourceId; @property (nonatomic, assign, readwrite) STPPaymentIntentStatus status; @@ -52,7 +51,6 @@ - (NSString *)description { [NSString stringWithFormat:@"livemode = %@", self.livemode ? @"YES" : @"NO"], [NSString stringWithFormat:@"nextSourceAction = %@", self.allResponseFields[@"next_source_action"]], [NSString stringWithFormat:@"receiptEmail = %@", self.receiptEmail], - [NSString stringWithFormat:@"returnUrl = %@", self.returnUrl], [NSString stringWithFormat:@"shipping = %@", self.allResponseFields[@"shipping"]], [NSString stringWithFormat:@"sourceId = %@", self.sourceId], [NSString stringWithFormat:@"status = %@", [self.allResponseFields stp_stringForKey:@"status"]], @@ -150,7 +148,6 @@ + (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)r // next_source_action is not being parsed. Today type=`authorize_with_url` is the only one // and STPRedirectContext reaches directly into it. Not yet sure how I want to model // this polymorphic object, so keeping it out of the public API. - paymentIntent.returnUrl = [dict stp_urlForKey:@"return_url"]; paymentIntent.receiptEmail = [dict stp_stringForKey:@"receipt_email"]; // FIXME: add support for `shipping` paymentIntent.sourceId = [dict stp_stringForKey:@"source"]; diff --git a/Stripe/STPRedirectContext.m b/Stripe/STPRedirectContext.m index f0b3b8077b8..c1064ecc35d 100644 --- a/Stripe/STPRedirectContext.m +++ b/Stripe/STPRedirectContext.m @@ -56,7 +56,8 @@ - (nullable instancetype)initWithSource:(STPSource *)source - (nullable instancetype)initWithPaymentIntent:(STPPaymentIntent *)paymentIntent completion:(STPRedirectContextPaymentIntentCompletionBlock)completion { - if (!(paymentIntent.returnUrl != nil + NSURL *returnUrl = nil; // FIXME + if (!(returnUrl != nil && paymentIntent.status == STPPaymentIntentStatusRequiresSourceAction && [paymentIntent.allResponseFields[@"next_source_action"] isKindOfClass: [NSDictionary class]])) { return nil; @@ -72,7 +73,7 @@ - (nullable instancetype)initWithPaymentIntent:(STPPaymentIntent *)paymentIntent NSString *redirectURL = nextSourceAction[@"value"][@"url"]; return [self initWithNativeRedirectURL:nil redirectURL:[NSURL URLWithString:redirectURL] - returnURL:paymentIntent.returnUrl + returnURL:returnUrl completion:^(NSError * _Nullable error) { completion(paymentIntent.clientSecret, error); }]; diff --git a/Tests/Tests/STPPaymentIntentFunctionalTest.m b/Tests/Tests/STPPaymentIntentFunctionalTest.m index db1275f9d1b..7e11ca25eca 100644 --- a/Tests/Tests/STPPaymentIntentFunctionalTest.m +++ b/Tests/Tests/STPPaymentIntentFunctionalTest.m @@ -32,7 +32,8 @@ - (void)testRetrievePreviousCreatedPaymentIntent { XCTAssertFalse(paymentIntent.livemode); XCTAssertNil(paymentIntent.sourceId); XCTAssertEqual(paymentIntent.status, STPPaymentIntentStatusCanceled); - XCTAssertEqualObjects(paymentIntent.returnUrl, [NSURL URLWithString:@"payments-example://stripe-redirect"]); + NSURL *returnUrl = nil; // FIXME + XCTAssertEqualObjects(returnUrl, [NSURL URLWithString:@"payments-example://stripe-redirect"]); [expectation fulfill]; }]; diff --git a/Tests/Tests/STPPaymentIntentTest.m b/Tests/Tests/STPPaymentIntentTest.m index bcc557aff56..5ada1a42dcd 100644 --- a/Tests/Tests/STPPaymentIntentTest.m +++ b/Tests/Tests/STPPaymentIntentTest.m @@ -159,8 +159,9 @@ - (void)testDecodedObjectFromAPIResponseMapping { XCTAssertEqualObjects(paymentIntent.stripeDescription, @"My Sample PaymentIntent"); XCTAssertFalse(paymentIntent.livemode); XCTAssertEqualObjects(paymentIntent.receiptEmail, @"danj@example.com"); - XCTAssertNotNil(paymentIntent.returnUrl); - XCTAssertEqualObjects(paymentIntent.returnUrl, [NSURL URLWithString:@"payments-example://stripe-redirect"]); + NSURL *returnUrl = nil; // FIXME + XCTAssertNotNil(returnUrl); + XCTAssertEqualObjects(returnUrl, [NSURL URLWithString:@"payments-example://stripe-redirect"]); XCTAssertEqualObjects(paymentIntent.sourceId, @"src_1Cl1AdIl4IdHmuTbseiDWq6m"); XCTAssertEqual(paymentIntent.status, STPPaymentIntentStatusRequiresSourceAction); diff --git a/Tests/Tests/STPRedirectContextTest.m b/Tests/Tests/STPRedirectContextTest.m index 457de211b4f..2b37b2baf5c 100644 --- a/Tests/Tests/STPRedirectContextTest.m +++ b/Tests/Tests/STPRedirectContextTest.m @@ -139,10 +139,11 @@ - (void)testInitWithPaymentIntent { XCTAssertNil(sut.nativeRedirectURL); XCTAssertEqualObjects(sut.redirectURL.absoluteString, @"https://hooks.stripe.com/redirect/authenticate/src_1Cl1AeIl4IdHmuTb1L7x083A?client_secret=src_client_secret_DBNwUe9qHteqJ8qQBwNWiigk"); - XCTAssertEqualObjects(sut.returnURL, paymentIntent.returnUrl); + NSURL *returnUrl = nil; // FIXME + XCTAssertEqualObjects(sut.returnURL, returnUrl); // and make sure the completion calls the completion block above - sut.completion(fakeError); + if (sut.completion) sut.completion(fakeError); // FIXME: HACK to avoid EXC_BAD_ACCESS when NULL XCTAssertTrue(completionCalled); } From 0e7501cf37d20893440bdc4f93523d884ee5883a Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 10:35:04 -0800 Subject: [PATCH 02/16] Add (empty) classes for next_source_action values --- Stripe.xcodeproj/project.pbxproj | 24 +++++++++++++++++++ .../STPPaymentIntentSourceAction.h | 15 ++++++++++++ ...aymentIntentSourceActionAuthorizeWithURL.h | 14 +++++++++++ Stripe/PublicHeaders/Stripe.h | 2 ++ Stripe/STPPaymentIntentSourceAction.m | 21 ++++++++++++++++ ...aymentIntentSourceActionAuthorizeWithURL.m | 21 ++++++++++++++++ 6 files changed, 97 insertions(+) create mode 100644 Stripe/PublicHeaders/STPPaymentIntentSourceAction.h create mode 100644 Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h create mode 100644 Stripe/STPPaymentIntentSourceAction.m create mode 100644 Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index 888bb4a768f..ee0283eacda 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -396,6 +396,14 @@ B3302F4C200700AB005DDBE9 /* STPLegalEntityParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */; }; B347DD481FE35423006B3BAC /* STPValidatedTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = B347DD461FE35423006B3BAC /* STPValidatedTextField.h */; }; B347DD491FE35423006B3BAC /* STPValidatedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = B347DD471FE35423006B3BAC /* STPValidatedTextField.m */; }; + B36C6D6D2193671400D17575 /* STPPaymentIntentSourceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = B36C6D6B2193671400D17575 /* STPPaymentIntentSourceAction.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B36C6D6E2193671400D17575 /* STPPaymentIntentSourceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = B36C6D6B2193671400D17575 /* STPPaymentIntentSourceAction.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B36C6D6F2193671400D17575 /* STPPaymentIntentSourceAction.m in Sources */ = {isa = PBXBuildFile; fileRef = B36C6D6C2193671400D17575 /* STPPaymentIntentSourceAction.m */; }; + B36C6D702193671400D17575 /* STPPaymentIntentSourceAction.m in Sources */ = {isa = PBXBuildFile; fileRef = B36C6D6C2193671400D17575 /* STPPaymentIntentSourceAction.m */; }; + B36C6D732193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h in Headers */ = {isa = PBXBuildFile; fileRef = B36C6D712193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B36C6D742193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h in Headers */ = {isa = PBXBuildFile; fileRef = B36C6D712193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B36C6D752193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m in Sources */ = {isa = PBXBuildFile; fileRef = B36C6D722193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m */; }; + B36C6D762193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m in Sources */ = {isa = PBXBuildFile; fileRef = B36C6D722193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m */; }; B382D6611FE8BEA0009B56AB /* STPValidatedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = B347DD471FE35423006B3BAC /* STPValidatedTextField.m */; }; B3A241391FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; B3A2413A1FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1101,6 +1109,10 @@ B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPLegalEntityParamsTest.m; sourceTree = "<group>"; }; B347DD461FE35423006B3BAC /* STPValidatedTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STPValidatedTextField.h; sourceTree = "<group>"; }; B347DD471FE35423006B3BAC /* STPValidatedTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPValidatedTextField.m; sourceTree = "<group>"; }; + B36C6D6B2193671400D17575 /* STPPaymentIntentSourceAction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPPaymentIntentSourceAction.h; path = PublicHeaders/STPPaymentIntentSourceAction.h; sourceTree = "<group>"; }; + B36C6D6C2193671400D17575 /* STPPaymentIntentSourceAction.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPPaymentIntentSourceAction.m; sourceTree = "<group>"; }; + B36C6D712193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPPaymentIntentSourceActionAuthorizeWithURL.h; path = PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h; sourceTree = "<group>"; }; + B36C6D722193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPPaymentIntentSourceActionAuthorizeWithURL.m; sourceTree = "<group>"; }; B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPConnectAccountParams.h; path = PublicHeaders/STPConnectAccountParams.h; sourceTree = "<group>"; }; B3A241381FFEB57400A2F00D /* STPConnectAccountParams.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPConnectAccountParams.m; sourceTree = "<group>"; }; B3A99BC11FEAF2CA003F6ED3 /* STPLegalEntityParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPLegalEntityParams.h; path = PublicHeaders/STPLegalEntityParams.h; sourceTree = "<group>"; }; @@ -2041,6 +2053,10 @@ B3BDCAC720EEF22D0034F7F5 /* STPPaymentIntentEnums.h */, B3BDCAD520EEF5EC0034F7F5 /* STPPaymentIntentParams.h */, B3BDCAD220EEF5E00034F7F5 /* STPPaymentIntentParams.m */, + B36C6D6B2193671400D17575 /* STPPaymentIntentSourceAction.h */, + B36C6D6C2193671400D17575 /* STPPaymentIntentSourceAction.m */, + B36C6D712193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h */, + B36C6D722193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m */, C1D7B51E1E36C32F002181F5 /* STPSource.h */, C1D7B51F1E36C32F002181F5 /* STPSource.m */, F19491DD1E5F6B8C001E1FC2 /* STPSourceCardDetails.h */, @@ -2198,6 +2214,7 @@ 04F94DAB1D229F3F004FC826 /* UIBarButtonItem+Stripe.h in Headers */, 04F94DC91D22A20A004FC826 /* STPSwitchTableViewCell.h in Headers */, 0433EB4B1BD06313003912B4 /* NSDictionary+Stripe.h in Headers */, + B36C6D6E2193671400D17575 /* STPPaymentIntentSourceAction.h in Headers */, 04F94DCB1D22A229004FC826 /* UIView+Stripe_FirstResponder.h in Headers */, 04F94DD11D22A239004FC826 /* STPPromise.h in Headers */, C1BD9B351E3940C400CEE925 /* STPSourceVerification.h in Headers */, @@ -2231,6 +2248,7 @@ C124A17D1CCAA0C2007D42EE /* NSMutableURLRequest+Stripe.h in Headers */, F1FA6F991E25970F00EB444D /* STPCoreTableViewController+Private.h in Headers */, C1BD9B2F1E3940A200CEE925 /* STPSourceRedirect.h in Headers */, + B36C6D742193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h in Headers */, 8B429AD91EF9D4B500F95F34 /* STPBankAccountParams+Private.h in Headers */, F1BEB2FE1F3508BB0043F48C /* NSError+Stripe.h in Headers */, 04E32AA01B7A9490009C9E35 /* STPPaymentCardTextField.h in Headers */, @@ -2317,6 +2335,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + B36C6D732193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h in Headers */, C15993361D8808680047950D /* STPShippingMethodsViewController.h in Headers */, F1A2F92C1EEB6A70006B0456 /* NSCharacterSet+Stripe.h in Headers */, F1D3A24E1EB012010095BFA9 /* STPMultipartFormDataPart.h in Headers */, @@ -2399,6 +2418,7 @@ 0426B9721CEAE3EB006AC8DD /* UITableViewCell+Stripe_Borders.h in Headers */, 04CDE5C91BC20B1D00548833 /* STPBankAccountParams.h in Headers */, 049A3F891CC73C7100F57DE7 /* STPPaymentContext.h in Headers */, + B36C6D6D2193671400D17575 /* STPPaymentIntentSourceAction.h in Headers */, 04E39F541CECF7A100AF3B96 /* STPPaymentMethodTuple.h in Headers */, F15232241EA9303800D65C67 /* STPURLCallbackHandler.h in Headers */, C18410761EC2529400178149 /* STPEphemeralKeyManager.h in Headers */, @@ -2944,6 +2964,7 @@ 0438EF451B74170D00D506CC /* STPCardValidator.m in Sources */, 04F94DBB1D229F8D004FC826 /* PKPaymentAuthorizationViewController+Stripe_Blocks.m in Sources */, C1271A3E1E3FA4E800F25DFE /* STPSectionHeaderView.m in Sources */, + B36C6D702193671400D17575 /* STPPaymentIntentSourceAction.m in Sources */, F12829DD1D7747E4008B10D6 /* STPBundleLocator.m in Sources */, 04F94DA91D229F32004FC826 /* STPPaymentMethodTuple.m in Sources */, C15608E01FE08F2E0032AE66 /* UIView+Stripe_SafeAreaBounds.m in Sources */, @@ -2994,6 +3015,7 @@ C159933A1D8808880047950D /* STPShippingAddressViewController.m in Sources */, 04F94DA41D229F1C004FC826 /* STPAddressViewModel.m in Sources */, 049880FF1CED5A2300EA4FFD /* STPPaymentConfiguration.m in Sources */, + B36C6D762193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m in Sources */, B3A99BC61FEAF2CA003F6ED3 /* STPLegalEntityParams.m in Sources */, C180211D1E3A58710089D712 /* STPSourcePoller.m in Sources */, 04F94DB91D229F86004FC826 /* STPApplePayPaymentMethod.m in Sources */, @@ -3075,6 +3097,7 @@ 04CDB5101A5F30A700B854EE /* STPCard.m in Sources */, 04CDB5001A5F30A700B854EE /* STPAPIClient.m in Sources */, C18410781EC2529400178149 /* STPEphemeralKeyManager.m in Sources */, + B36C6D6F2193671400D17575 /* STPPaymentIntentSourceAction.m in Sources */, 04CDB50C1A5F30A700B854EE /* STPBankAccount.m in Sources */, 049A3F7F1CC1920A00F57DE7 /* UIViewController+Stripe_KeyboardAvoiding.m in Sources */, 04F416271CA3639500486FB5 /* STPAddCardViewController.m in Sources */, @@ -3147,6 +3170,7 @@ 049A3F961CC75B2E00F57DE7 /* STPPromise.m in Sources */, B3BDCAD320EEF5E10034F7F5 /* STPPaymentIntentParams.m in Sources */, 04695AD41C77F9DB00E08063 /* NSString+Stripe.m in Sources */, + B36C6D752193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m in Sources */, F15232261EA9303800D65C67 /* STPURLCallbackHandler.m in Sources */, F1BEB2FF1F3508BB0043F48C /* NSError+Stripe.m in Sources */, 049952D01BCF13510088C703 /* STPAPIRequest.m in Sources */, diff --git a/Stripe/PublicHeaders/STPPaymentIntentSourceAction.h b/Stripe/PublicHeaders/STPPaymentIntentSourceAction.h new file mode 100644 index 00000000000..941a50b0f56 --- /dev/null +++ b/Stripe/PublicHeaders/STPPaymentIntentSourceAction.h @@ -0,0 +1,15 @@ +// +// STPPaymentIntentSourceAction.h +// Stripe +// +// Created by Daniel Jackson on 11/7/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import <Foundation/Foundation.h> + +#import "STPAPIResponseDecodable.h" + +@interface STPPaymentIntentSourceAction: NSObject<STPAPIResponseDecodable> + +@end diff --git a/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h b/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h new file mode 100644 index 00000000000..4fbcde7aa25 --- /dev/null +++ b/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h @@ -0,0 +1,14 @@ +// +// STPPaymentIntentSourceActionAuthorizeWithURL.h +// Stripe +// +// Created by Daniel Jackson on 11/7/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "STPAPIResponseDecodable.h" + +@interface STPPaymentIntentSourceActionAuthorizeWithURL: NSObject<STPAPIResponseDecodable> + +@end diff --git a/Stripe/PublicHeaders/Stripe.h b/Stripe/PublicHeaders/Stripe.h index 1f965905140..6e8cefea3d6 100644 --- a/Stripe/PublicHeaders/Stripe.h +++ b/Stripe/PublicHeaders/Stripe.h @@ -40,6 +40,8 @@ #import "STPPaymentIntent.h" #import "STPPaymentIntentEnums.h" #import "STPPaymentIntentParams.h" +#import "STPPaymentIntentSourceAction.h" +#import "STPPaymentIntentSourceActionAuthorizeWithURL.h" #import "STPPaymentMethod.h" #import "STPPaymentMethodsViewController.h" #import "STPPaymentResult.h" diff --git a/Stripe/STPPaymentIntentSourceAction.m b/Stripe/STPPaymentIntentSourceAction.m new file mode 100644 index 00000000000..6d9e935ca99 --- /dev/null +++ b/Stripe/STPPaymentIntentSourceAction.m @@ -0,0 +1,21 @@ +// +// STPPaymentIntentSourceAction.m +// Stripe +// +// Created by Daniel Jackson on 11/7/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "STPPaymentIntentSourceAction.h" + +@implementation STPPaymentIntentSourceAction + +@synthesize allResponseFields; + ++ (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)response { + // TODO + NSLog(@"%@", response); + return nil; +} + +@end diff --git a/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m b/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m new file mode 100644 index 00000000000..bd538f19f9e --- /dev/null +++ b/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m @@ -0,0 +1,21 @@ +// +// STPPaymentIntentSourceActionAuthorizeWithURL.m +// Stripe +// +// Created by Daniel Jackson on 11/7/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "STPPaymentIntentSourceActionAuthorizeWithURL.h" + +@implementation STPPaymentIntentSourceActionAuthorizeWithURL + +@synthesize allResponseFields; + ++ (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)response { + // TODO + NSLog(@"%@", response); + return nil; +} + +@end From 98a68e7b919a46a9cc4f26029c61cbbb1c5f4863 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 11:07:35 -0800 Subject: [PATCH 03/16] Fill out implementation of STPPaymentIntentSourceActionAuthorizeWithURL --- ...aymentIntentSourceActionAuthorizeWithURL.h | 26 ++++++++++++ ...aymentIntentSourceActionAuthorizeWithURL.m | 42 +++++++++++++++++-- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h b/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h index 4fbcde7aa25..536398c032a 100644 --- a/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h +++ b/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h @@ -7,8 +7,34 @@ // #import <Foundation/Foundation.h> + #import "STPAPIResponseDecodable.h" +NS_ASSUME_NONNULL_BEGIN + +/** + The `STPPaymentIntentSourceAction` details when type is `authorize_with_url`. + + These are created & owned by the containing `STPPaymentIntent`. + */ @interface STPPaymentIntentSourceActionAuthorizeWithURL: NSObject<STPAPIResponseDecodable> +/** + You cannot directly instantiate an `STPPaymentIntentSourceActionAuthorizeWithURL`. + */ +- (instancetype)init __attribute__((unavailable("You cannot directly instantiate an STPPaymentIntentSourceActionAuthorizeWithURL."))); + +/** + The URL where the user will authorize this charge. + */ +@property (nonatomic, readonly) NSURL *url; + +/** + The return URL that'll be redirected back to when the user is done + authorizing the charge. + */ +@property (nonatomic, nullable, readonly) NSURL *returnURL; + @end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m b/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m index bd538f19f9e..82fe6cab006 100644 --- a/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m +++ b/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m @@ -8,14 +8,50 @@ #import "STPPaymentIntentSourceActionAuthorizeWithURL.h" +#import "NSDictionary+Stripe.h" + +@interface STPPaymentIntentSourceActionAuthorizeWithURL() +@property (nonatomic, strong, nonnull, readwrite) NSURL *url; +@property (nonatomic, strong, nullable, readwrite) NSURL *returnURL; +@property (nonatomic, readwrite, nonnull, copy) NSDictionary *allResponseFields; +@end + @implementation STPPaymentIntentSourceActionAuthorizeWithURL @synthesize allResponseFields; +- (NSString *)description { + NSArray *props = @[ + // Object + [NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self], + + // AuthorizeWithURL details (alphabetical) + [NSString stringWithFormat:@"returnURL = %@", self.returnURL], + [NSString stringWithFormat:@"url = %@", self.url], + ]; + + return [NSString stringWithFormat:@"<%@>", [props componentsJoinedByString:@"; "]]; +} + + (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)response { - // TODO - NSLog(@"%@", response); - return nil; + NSDictionary *dict = [response stp_dictionaryByRemovingNulls]; + if (!dict) { + return nil; + } + + // required fields + NSURL *url = [response stp_urlForKey:@"url"]; + if (!url) { + return nil; + } + + STPPaymentIntentSourceActionAuthorizeWithURL *authorize = [self new]; + + authorize.url = url; + authorize.returnURL = [dict stp_urlForKey:@"return_url"]; + authorize.allResponseFields = dict; + + return authorize; } @end From d8cfcab588992eaa688894c5a08cb038957c2722 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 12:01:52 -0800 Subject: [PATCH 04/16] Add enum for nextSourceAction.type --- Stripe/PublicHeaders/STPPaymentIntentEnums.h | 20 ++++++++++++++++++++ Stripe/STPPaymentIntent+Private.h | 8 ++++++++ Stripe/STPPaymentIntent.m | 10 ++++++++++ 3 files changed, 38 insertions(+) diff --git a/Stripe/PublicHeaders/STPPaymentIntentEnums.h b/Stripe/PublicHeaders/STPPaymentIntentEnums.h index b8431d16570..0e5cb3e3a91 100644 --- a/Stripe/PublicHeaders/STPPaymentIntentEnums.h +++ b/Stripe/PublicHeaders/STPPaymentIntentEnums.h @@ -92,3 +92,23 @@ typedef NS_ENUM(NSInteger, STPPaymentIntentConfirmationMethod) { */ STPPaymentIntentConfirmationMethodSecret, }; + +/** + Types of Source Actions from a `STPPaymentIntent`, when the payment intent + status is `STPPaymentIntentStatusRequiresSourceAction`. + */ +typedef NS_ENUM(NSUInteger, STPPaymentIntentSourceActionType) { + /** + This is an unknown source action, that's been added since the SDK + was last updated. + Update your SDK, or use the `nextSourceAction.allResponseFields` + for custom handling. + */ + STPPaymentIntentSourceActionTypeUnknown, + + /** + The payment intent needs to be authorized by the user. We provide + `STPRedirectContext` to handle the url redirections necessary. + */ + STPPaymentIntentSourceActionTypeAuthorizeWithURL, +}; diff --git a/Stripe/STPPaymentIntent+Private.h b/Stripe/STPPaymentIntent+Private.h index 1dba1665b59..571980f6c75 100644 --- a/Stripe/STPPaymentIntent+Private.h +++ b/Stripe/STPPaymentIntent+Private.h @@ -44,6 +44,14 @@ NS_ASSUME_NONNULL_BEGIN */ + (STPPaymentIntentConfirmationMethod)confirmationMethodFromString:(NSString *)string; +/** + Parse the string and return the correct `STPPaymentIntentSourceActionType`, + or `STPPaymentIntentSourceActionTypeUnknown` if it's unrecognized by this version of the SDK. + + @param string the NSString with the `next_source_action.type` + */ ++ (STPPaymentIntentSourceActionType)sourceActionTypeFromString:(NSString *)string; + @end NS_ASSUME_NONNULL_END diff --git a/Stripe/STPPaymentIntent.m b/Stripe/STPPaymentIntent.m index f780c4efec5..6fe73391625 100644 --- a/Stripe/STPPaymentIntent.m +++ b/Stripe/STPPaymentIntent.m @@ -112,6 +112,16 @@ + (STPPaymentIntentConfirmationMethod)confirmationMethodFromString:(NSString *)s return statusNumber.integerValue; } ++ (STPPaymentIntentSourceActionType)sourceActionTypeFromString:(NSString *)string { + NSDictionary<NSString *, NSNumber *> *map = @{ + @"authorize_with_url": @(STPPaymentIntentSourceActionTypeAuthorizeWithURL), + }; + + NSString *key = string.lowercaseString; + NSNumber *statusNumber = map[key] ?: @(STPPaymentIntentSourceActionTypeUnknown); + return statusNumber.integerValue; +} + #pragma mark - STPAPIResponseDecodable From a842822fcbd129a253b6b07ffc882fc575eb0589 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 12:02:21 -0800 Subject: [PATCH 05/16] Fill out implementation of STPPaymentIntentSourceAction --- .../STPPaymentIntentSourceAction.h | 29 +++++++++ Stripe/STPPaymentIntentSourceAction.m | 62 ++++++++++++++++++- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/Stripe/PublicHeaders/STPPaymentIntentSourceAction.h b/Stripe/PublicHeaders/STPPaymentIntentSourceAction.h index 941a50b0f56..afccab72d92 100644 --- a/Stripe/PublicHeaders/STPPaymentIntentSourceAction.h +++ b/Stripe/PublicHeaders/STPPaymentIntentSourceAction.h @@ -9,7 +9,36 @@ #import <Foundation/Foundation.h> #import "STPAPIResponseDecodable.h" +#import "STPPaymentIntentEnums.h" +NS_ASSUME_NONNULL_BEGIN + +@class STPPaymentIntentSourceActionAuthorizeWithURL; + +/** + Source Action details for an STPPaymentIntent. This is a container for + the various types that are available. Check the `type` to see which one + it is, and then use the related property for the details necessary to handle + it. + */ @interface STPPaymentIntentSourceAction: NSObject<STPAPIResponseDecodable> +/** + You cannot directly instantiate an `STPPaymentIntentSourceAction`. + */ +- (instancetype)init __attribute__((unavailable("You cannot directly instantiate an STPPaymentIntentSourceAction."))); + +/** + The type of source action needed. The value of this field determines which + property of this object contains further details about the action. + */ +@property (nonatomic, readonly) STPPaymentIntentSourceActionType type; + +/** + The details for authorizing via URL, when `type == STPPaymentIntentSourceActionTypeAuthorizeWithURL` + */ +@property (nonatomic, nullable, readonly) STPPaymentIntentSourceActionAuthorizeWithURL* authorizeWithURL; + @end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/STPPaymentIntentSourceAction.m b/Stripe/STPPaymentIntentSourceAction.m index 6d9e935ca99..211fca3891c 100644 --- a/Stripe/STPPaymentIntentSourceAction.m +++ b/Stripe/STPPaymentIntentSourceAction.m @@ -8,14 +8,70 @@ #import "STPPaymentIntentSourceAction.h" +#import "STPPaymentIntent+Private.h" +#import "STPPaymentIntentSourceActionAuthorizeWithURL.h" + +#import "NSDictionary+Stripe.h" + +@interface STPPaymentIntentSourceAction() +@property (nonatomic, readwrite) STPPaymentIntentSourceActionType type; +@property (nonatomic, strong, nullable, readwrite) STPPaymentIntentSourceActionAuthorizeWithURL* authorizeWithURL; +@property (nonatomic, readwrite, nonnull, copy) NSDictionary *allResponseFields; +@end + @implementation STPPaymentIntentSourceAction @synthesize allResponseFields; +- (NSString *)description { + NSMutableArray *props = [@[ + // Object + [NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self], + + // Type + [NSString stringWithFormat:@"type = %@", [allResponseFields stp_stringForKey:@"type"]], + ] mutableCopy]; + + // omit properties that don't apply to this type + switch (self.type) { + case STPPaymentIntentSourceActionTypeAuthorizeWithURL: + [props addObject:[NSString stringWithFormat:@"authorizeWithURL = %@", self.authorizeWithURL]]; + break; + default: + // unrecognized type, just show the original dictionary for debugging help + [props addObject:[NSString stringWithFormat:@"allResponseFields = %@", self.allResponseFields]]; + } + + return [NSString stringWithFormat:@"<%@>", [props componentsJoinedByString:@"; "]]; +} + + (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)response { - // TODO - NSLog(@"%@", response); - return nil; + NSDictionary *dict = [response stp_dictionaryByRemovingNulls]; + NSString *rawType = [dict stp_stringForKey:@"type"]; + if (!dict || !rawType) { + return nil; + } + + STPPaymentIntentSourceActionType type = [STPPaymentIntent sourceActionTypeFromString:rawType]; + NSDictionary *authorizeDict = [dict stp_dictionaryForKey:@"authorize_with_url"]; + STPPaymentIntentSourceActionAuthorizeWithURL *authorize = [STPPaymentIntentSourceActionAuthorizeWithURL decodedObjectFromAPIResponse:authorizeDict]; + + STPPaymentIntentSourceAction *sourceAction = [self new]; + + // Only set the type to a recognized value if we *also* have the expected sub-details. + // ex: If the server said it was `.authorizeWithURL`, but decoding the + // STPPaymentIntentSourceActionAuthorizeWithURL object fails, map type to `.unknown` + if (type == STPPaymentIntentSourceActionTypeAuthorizeWithURL && authorize) { + sourceAction.type = type; + sourceAction.authorizeWithURL = authorize; + } + else { + sourceAction.type = STPPaymentIntentSourceActionTypeUnknown; + } + + sourceAction.allResponseFields = dict; + + return sourceAction; } @end From 975f56fa51cf4ba1ffac5161e41eeabdb6caa927 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 12:03:18 -0800 Subject: [PATCH 06/16] Add STPPaymentIntentSourceAction to STPPaymentIntent --- Stripe/PublicHeaders/STPPaymentIntent.h | 8 ++++++++ Stripe/STPPaymentIntent.m | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Stripe/PublicHeaders/STPPaymentIntent.h b/Stripe/PublicHeaders/STPPaymentIntent.h index af01d2f13c9..1ebea57cd93 100644 --- a/Stripe/PublicHeaders/STPPaymentIntent.h +++ b/Stripe/PublicHeaders/STPPaymentIntent.h @@ -13,6 +13,8 @@ NS_ASSUME_NONNULL_BEGIN +@class STPPaymentIntentSourceAction; + /** A PaymentIntent tracks the process of collecting a payment from your customer. @@ -78,6 +80,12 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, readonly) BOOL livemode; +/** + If `status == STPPaymentIntentStatusRequiresSourceAction`, this + property contains the next action to take for this PaymentIntent. + */ +@property (nonatomic, nullable, readonly) STPPaymentIntentSourceAction* nextSourceAction; + /** Email address that the receipt for the resulting payment will be sent to. */ diff --git a/Stripe/STPPaymentIntent.m b/Stripe/STPPaymentIntent.m index 6fe73391625..e68f77603a8 100644 --- a/Stripe/STPPaymentIntent.m +++ b/Stripe/STPPaymentIntent.m @@ -8,6 +8,7 @@ #import "STPPaymentIntent.h" #import "STPPaymentIntent+Private.h" +#import "STPPaymentIntentSourceAction.h" #import "NSDictionary+Stripe.h" @@ -22,6 +23,7 @@ @interface STPPaymentIntent () @property (nonatomic, copy, readwrite) NSString *currency; @property (nonatomic, copy, nullable, readwrite) NSString *stripeDescription; @property (nonatomic, assign, readwrite) BOOL livemode; +@property (nonatomic, strong, nullable, readwrite) STPPaymentIntentSourceAction* nextSourceAction; @property (nonatomic, copy, nullable, readwrite) NSString *receiptEmail; @property (nonatomic, copy, nullable, readwrite) NSString *sourceId; @property (nonatomic, assign, readwrite) STPPaymentIntentStatus status; @@ -49,7 +51,7 @@ - (NSString *)description { [NSString stringWithFormat:@"currency = %@", self.currency], [NSString stringWithFormat:@"description = %@", self.stripeDescription], [NSString stringWithFormat:@"livemode = %@", self.livemode ? @"YES" : @"NO"], - [NSString stringWithFormat:@"nextSourceAction = %@", self.allResponseFields[@"next_source_action"]], + [NSString stringWithFormat:@"nextSourceAction = %@", self.nextSourceAction], [NSString stringWithFormat:@"receiptEmail = %@", self.receiptEmail], [NSString stringWithFormat:@"shipping = %@", self.allResponseFields[@"shipping"]], [NSString stringWithFormat:@"sourceId = %@", self.sourceId], @@ -155,9 +157,8 @@ + (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)r paymentIntent.currency = currency; paymentIntent.stripeDescription = [dict stp_stringForKey:@"description"]; paymentIntent.livemode = [dict stp_boolForKey:@"livemode" or:YES]; - // next_source_action is not being parsed. Today type=`authorize_with_url` is the only one - // and STPRedirectContext reaches directly into it. Not yet sure how I want to model - // this polymorphic object, so keeping it out of the public API. + NSDictionary *nextSourceActionDict = [dict stp_dictionaryForKey:@"next_source_action"]; + paymentIntent.nextSourceAction = [STPPaymentIntentSourceAction decodedObjectFromAPIResponse:nextSourceActionDict]; paymentIntent.receiptEmail = [dict stp_stringForKey:@"receipt_email"]; // FIXME: add support for `shipping` paymentIntent.sourceId = [dict stp_stringForKey:@"source"]; From a211cd6752cecaa7c6ddf4d20d01e3c489b22230 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 13:16:02 -0800 Subject: [PATCH 07/16] Update STPPaymentIntent tests, and JSON for fixture --- Tests/Tests/PaymentIntent.json | 4 ++-- Tests/Tests/STPPaymentIntentFunctionalTest.m | 3 +-- Tests/Tests/STPPaymentIntentTest.m | 13 ++++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Tests/Tests/PaymentIntent.json b/Tests/Tests/PaymentIntent.json index 97bb95c05c8..2f6df0eea20 100644 --- a/Tests/Tests/PaymentIntent.json +++ b/Tests/Tests/PaymentIntent.json @@ -15,12 +15,12 @@ "livemode": false, "next_source_action": { "type": "authorize_with_url", - "value": { + "authorize_with_url": { + "return_url": "payments-example://stripe-redirect", "url": "https://hooks.stripe.com/redirect/authenticate/src_1Cl1AeIl4IdHmuTb1L7x083A?client_secret=src_client_secret_DBNwUe9qHteqJ8qQBwNWiigk" } }, "receipt_email": "danj@example.com", - "return_url": "payments-example://stripe-redirect", "shipping": { "address": { "city": "San Francisco", diff --git a/Tests/Tests/STPPaymentIntentFunctionalTest.m b/Tests/Tests/STPPaymentIntentFunctionalTest.m index 7e11ca25eca..5fbbc75f66b 100644 --- a/Tests/Tests/STPPaymentIntentFunctionalTest.m +++ b/Tests/Tests/STPPaymentIntentFunctionalTest.m @@ -32,8 +32,7 @@ - (void)testRetrievePreviousCreatedPaymentIntent { XCTAssertFalse(paymentIntent.livemode); XCTAssertNil(paymentIntent.sourceId); XCTAssertEqual(paymentIntent.status, STPPaymentIntentStatusCanceled); - NSURL *returnUrl = nil; // FIXME - XCTAssertEqualObjects(returnUrl, [NSURL URLWithString:@"payments-example://stripe-redirect"]); + XCTAssertNil(paymentIntent.nextSourceAction); [expectation fulfill]; }]; diff --git a/Tests/Tests/STPPaymentIntentTest.m b/Tests/Tests/STPPaymentIntentTest.m index 5ada1a42dcd..a853e59dc11 100644 --- a/Tests/Tests/STPPaymentIntentTest.m +++ b/Tests/Tests/STPPaymentIntentTest.m @@ -159,9 +159,16 @@ - (void)testDecodedObjectFromAPIResponseMapping { XCTAssertEqualObjects(paymentIntent.stripeDescription, @"My Sample PaymentIntent"); XCTAssertFalse(paymentIntent.livemode); XCTAssertEqualObjects(paymentIntent.receiptEmail, @"danj@example.com"); - NSURL *returnUrl = nil; // FIXME - XCTAssertNotNil(returnUrl); - XCTAssertEqualObjects(returnUrl, [NSURL URLWithString:@"payments-example://stripe-redirect"]); + XCTAssertNotNil(paymentIntent.nextSourceAction); + XCTAssertEqual(paymentIntent.nextSourceAction.type, STPPaymentIntentSourceActionTypeAuthorizeWithURL); + XCTAssertNotNil(paymentIntent.nextSourceAction.authorizeWithURL); + XCTAssertNotNil(paymentIntent.nextSourceAction.authorizeWithURL.url); + NSURL *returnURL = paymentIntent.nextSourceAction.authorizeWithURL.returnURL; + XCTAssertNotNil(returnURL); + XCTAssertEqualObjects(returnURL, [NSURL URLWithString:@"payments-example://stripe-redirect"]); + NSURL *url = paymentIntent.nextSourceAction.authorizeWithURL.url; + XCTAssertNotNil(url); + XCTAssertEqualObjects(url, [NSURL URLWithString:@"https://hooks.stripe.com/redirect/authenticate/src_1Cl1AeIl4IdHmuTb1L7x083A?client_secret=src_client_secret_DBNwUe9qHteqJ8qQBwNWiigk"]); XCTAssertEqualObjects(paymentIntent.sourceId, @"src_1Cl1AdIl4IdHmuTbseiDWq6m"); XCTAssertEqual(paymentIntent.status, STPPaymentIntentStatusRequiresSourceAction); From 8f8de9684b9384b9ca4e69deda592c9bd608a0e5 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 13:20:29 -0800 Subject: [PATCH 08/16] Adding test for new enum value from string --- Tests/Tests/STPPaymentIntentTest.m | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Tests/Tests/STPPaymentIntentTest.m b/Tests/Tests/STPPaymentIntentTest.m index a853e59dc11..778fd3b71fd 100644 --- a/Tests/Tests/STPPaymentIntentTest.m +++ b/Tests/Tests/STPPaymentIntentTest.m @@ -107,6 +107,18 @@ - (void)testConfirmationMethodFromString { STPPaymentIntentConfirmationMethodUnknown); } +- (void)testSourceActionFromString { + XCTAssertEqual([STPPaymentIntent sourceActionTypeFromString:@"authorize_with_url"], + STPPaymentIntentSourceActionTypeAuthorizeWithURL); + XCTAssertEqual([STPPaymentIntent confirmationMethodFromString:@"AUTHORIZE_WITH_URL"], + STPPaymentIntentSourceActionTypeAuthorizeWithURL); + + XCTAssertEqual([STPPaymentIntent confirmationMethodFromString:@"garbage"], + STPPaymentIntentSourceActionTypeUnknown); + XCTAssertEqual([STPPaymentIntent confirmationMethodFromString:@"GARBAGE"], + STPPaymentIntentSourceActionTypeUnknown); +} + #pragma mark - Description Tests - (void)testDescription { From 40ac1f4dbfe3bd6b45704656c53803a053ee888b Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 14:57:25 -0800 Subject: [PATCH 09/16] Add test for decoding `STPPaymentIntentSourceAction` --- Stripe.xcodeproj/project.pbxproj | 4 + .../Tests/STPPaymentIntentSourceActionTest.m | 94 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 Tests/Tests/STPPaymentIntentSourceActionTest.m diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index ee0283eacda..f5ea26b7060 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -404,6 +404,7 @@ B36C6D742193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h in Headers */ = {isa = PBXBuildFile; fileRef = B36C6D712193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h */; settings = {ATTRIBUTES = (Public, ); }; }; B36C6D752193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m in Sources */ = {isa = PBXBuildFile; fileRef = B36C6D722193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m */; }; B36C6D762193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m in Sources */ = {isa = PBXBuildFile; fileRef = B36C6D722193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m */; }; + B36C6D782193A16F00D17575 /* STPPaymentIntentSourceActionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B36C6D772193A16F00D17575 /* STPPaymentIntentSourceActionTest.m */; }; B382D6611FE8BEA0009B56AB /* STPValidatedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = B347DD471FE35423006B3BAC /* STPValidatedTextField.m */; }; B3A241391FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; B3A2413A1FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1113,6 +1114,7 @@ B36C6D6C2193671400D17575 /* STPPaymentIntentSourceAction.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPPaymentIntentSourceAction.m; sourceTree = "<group>"; }; B36C6D712193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPPaymentIntentSourceActionAuthorizeWithURL.h; path = PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h; sourceTree = "<group>"; }; B36C6D722193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPPaymentIntentSourceActionAuthorizeWithURL.m; sourceTree = "<group>"; }; + B36C6D772193A16F00D17575 /* STPPaymentIntentSourceActionTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPPaymentIntentSourceActionTest.m; sourceTree = "<group>"; }; B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPConnectAccountParams.h; path = PublicHeaders/STPConnectAccountParams.h; sourceTree = "<group>"; }; B3A241381FFEB57400A2F00D /* STPConnectAccountParams.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPConnectAccountParams.m; sourceTree = "<group>"; }; B3A99BC11FEAF2CA003F6ED3 /* STPLegalEntityParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPLegalEntityParams.h; path = PublicHeaders/STPLegalEntityParams.h; sourceTree = "<group>"; }; @@ -1707,6 +1709,7 @@ 8B013C881F1E784A00DD831B /* STPPaymentConfigurationTest.m */, F14C872E1D4FCDBA00C7CC6A /* STPPaymentContextApplePayTest.m */, B3BDCAD020EEF5B90034F7F5 /* STPPaymentIntentParamsTest.m */, + B36C6D772193A16F00D17575 /* STPPaymentIntentSourceActionTest.m */, B3BDCACC20EEF4540034F7F5 /* STPPaymentIntentTest.m */, F1DE87FF1F8D410D00602F4C /* STPPaymentMethodsViewControllerTest.m */, C1EEDCC91CA2186300A54582 /* STPPhoneNumberValidatorTest.m */, @@ -2948,6 +2951,7 @@ C1EF044D1DD2397500FBF452 /* STPShippingAddressViewControllerLocalizationTests.m in Sources */, C1080F4C1CBED48A007B2D89 /* STPAddressTests.m in Sources */, C1C02CCE1ECCE92900DF5643 /* STPEphemeralKeyTest.m in Sources */, + B36C6D782193A16F00D17575 /* STPPaymentIntentSourceActionTest.m in Sources */, C14C4DB11EC3B34500C2FDF6 /* STPAPIRequestTest.m in Sources */, F1D96F9B1DC7DCDE00477E64 /* STPLocalizationUtils+STPTestAdditions.m in Sources */, 04415C6F1A6605B5001225ED /* STPCertTest.m in Sources */, diff --git a/Tests/Tests/STPPaymentIntentSourceActionTest.m b/Tests/Tests/STPPaymentIntentSourceActionTest.m new file mode 100644 index 00000000000..5a9853303ce --- /dev/null +++ b/Tests/Tests/STPPaymentIntentSourceActionTest.m @@ -0,0 +1,94 @@ +// +// STPPaymentIntentSourceActionTest.m +// StripeiOS Tests +// +// Created by Daniel Jackson on 11/7/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import <XCTest/XCTest.h> + +#import "STPPaymentIntentSourceAction.h" +#import "STPPaymentIntentSourceActionAuthorizeWithURL.h" + +@interface STPPaymentIntentSourceActionTest : XCTestCase + +@end + +@implementation STPPaymentIntentSourceActionTest + +- (void)testDecodedObjectFromAPIResponseAuthorizeWithURL { + STPPaymentIntentSourceAction *(^decode)(NSDictionary *) = ^STPPaymentIntentSourceAction *(NSDictionary * dict) { + return [STPPaymentIntentSourceAction decodedObjectFromAPIResponse:dict]; + }; + + XCTAssertNil(decode(nil)); + XCTAssertNil(decode(@{})); + XCTAssertNil(decode(@{ @"authorize_with_url": @{@"url": @"http://stripe.com"} }), + @"fails without type"); + + STPPaymentIntentSourceAction *missingDetails = decode(@{ + @"type": @"authorize_with_url" + }); + XCTAssertNotNil(missingDetails); + XCTAssertEqual(missingDetails.type, STPPaymentIntentSourceActionTypeUnknown, + @"Type becomes unknown if the authorize_with_url details are missing"); + + STPPaymentIntentSourceAction *badURL = decode(@{ + @"type": @"authorize_with_url", + @"authorize_with_url": @{ + @"url": @"not a url" + } + }); + XCTAssertNotNil(badURL); + XCTAssertEqual(badURL.type, STPPaymentIntentSourceActionTypeUnknown, + @"Type becomes unknown if the authorize_with_url details don't have a valid URL"); + + STPPaymentIntentSourceAction *missingReturnURL = decode(@{ + @"type": @"authorize_with_url", + @"authorize_with_url": @{ + @"url": @"https://stripe.com/" + } + }); + XCTAssertNotNil(missingReturnURL); + XCTAssertEqual(missingReturnURL.type, STPPaymentIntentSourceActionTypeAuthorizeWithURL, + @"Missing return_url won't prevent it from decoding"); + XCTAssertNotNil(missingReturnURL.authorizeWithURL.url); + XCTAssertEqualObjects(missingReturnURL.authorizeWithURL.url, + [NSURL URLWithString:@"https://stripe.com/"]); + XCTAssertNil(missingReturnURL.authorizeWithURL.returnURL); + + STPPaymentIntentSourceAction *badReturnURL = decode(@{ + @"type": @"authorize_with_url", + @"authorize_with_url": @{ + @"url": @"https://stripe.com/", + @"return_url": @"not a url" + } + }); + XCTAssertNotNil(badReturnURL); + XCTAssertEqual(badReturnURL.type, STPPaymentIntentSourceActionTypeAuthorizeWithURL, + @"invalid return_url won't prevent it from decoding"); + XCTAssertNotNil(badReturnURL.authorizeWithURL.url); + XCTAssertEqualObjects(badReturnURL.authorizeWithURL.url, + [NSURL URLWithString:@"https://stripe.com/"]); + XCTAssertNil(badReturnURL.authorizeWithURL.returnURL); + + + STPPaymentIntentSourceAction *complete = decode(@{ + @"type": @"authorize_with_url", + @"authorize_with_url": @{ + @"url": @"https://stripe.com/", + @"return_url": @"my-app://payment-complete" + } + }); + XCTAssertNotNil(complete); + XCTAssertEqual(complete.type, STPPaymentIntentSourceActionTypeAuthorizeWithURL); + XCTAssertNotNil(complete.authorizeWithURL.url); + XCTAssertEqualObjects(complete.authorizeWithURL.url, + [NSURL URLWithString:@"https://stripe.com/"]); + XCTAssertNotNil(complete.authorizeWithURL.returnURL); + XCTAssertEqualObjects(complete.authorizeWithURL.returnURL, + [NSURL URLWithString:@"my-app://payment-complete"]); +} + +@end From 52f660618e90aa9e815ead7213b15eeb5f27a8e8 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 15:06:29 -0800 Subject: [PATCH 10/16] Convert enum value to a string, instead of using `type` from the server It's confusing to print `type = authorize_with_url` if decoding the source action details as a `STPPaymentIntentSourceActionAuthorizeWithURL` object fails. Instead, log the value that the enum currently has. --- Stripe/STPPaymentIntent+Private.h | 8 ++++++++ Stripe/STPPaymentIntent.m | 12 ++++++++++++ Stripe/STPPaymentIntentSourceAction.m | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Stripe/STPPaymentIntent+Private.h b/Stripe/STPPaymentIntent+Private.h index 571980f6c75..3f0df95d26e 100644 --- a/Stripe/STPPaymentIntent+Private.h +++ b/Stripe/STPPaymentIntent+Private.h @@ -52,6 +52,14 @@ NS_ASSUME_NONNULL_BEGIN */ + (STPPaymentIntentSourceActionType)sourceActionTypeFromString:(NSString *)string; +/** + Return the string representing the provided `STPPaymentIntentSourceActionType`. + + @param sourceActionType the enum value to convert to a string + @return the string, or @"unknown" if this was an unrecognized type + */ ++ (NSString *)stringFromSourceActionType:(STPPaymentIntentSourceActionType)sourceActionType; + @end NS_ASSUME_NONNULL_END diff --git a/Stripe/STPPaymentIntent.m b/Stripe/STPPaymentIntent.m index e68f77603a8..c2752ab18de 100644 --- a/Stripe/STPPaymentIntent.m +++ b/Stripe/STPPaymentIntent.m @@ -124,6 +124,18 @@ + (STPPaymentIntentSourceActionType)sourceActionTypeFromString:(NSString *)strin return statusNumber.integerValue; } ++ (NSString *)stringFromSourceActionType:(STPPaymentIntentSourceActionType)sourceActionType { + switch (sourceActionType) { + case STPPaymentIntentSourceActionTypeAuthorizeWithURL: + return @"authorize_with_url"; + case STPPaymentIntentSourceActionTypeUnknown: + break; + } + + // catch any unknown values here + return @"unknown"; +} + #pragma mark - STPAPIResponseDecodable diff --git a/Stripe/STPPaymentIntentSourceAction.m b/Stripe/STPPaymentIntentSourceAction.m index 211fca3891c..0c9277ade8b 100644 --- a/Stripe/STPPaymentIntentSourceAction.m +++ b/Stripe/STPPaymentIntentSourceAction.m @@ -29,7 +29,7 @@ - (NSString *)description { [NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self], // Type - [NSString stringWithFormat:@"type = %@", [allResponseFields stp_stringForKey:@"type"]], + [NSString stringWithFormat:@"type = %@", [STPPaymentIntent stringFromSourceActionType:self.type]], ] mutableCopy]; // omit properties that don't apply to this type From 4adcc957921c46422473ef045c95be0bd693e33c Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 15:48:12 -0800 Subject: [PATCH 11/16] Update disabled functional test for confirming to make sure the returnURL exists as desired --- Tests/Tests/STPPaymentIntentFunctionalTest.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Tests/Tests/STPPaymentIntentFunctionalTest.m b/Tests/Tests/STPPaymentIntentFunctionalTest.m index 5fbbc75f66b..b1d81d943e0 100644 --- a/Tests/Tests/STPPaymentIntentFunctionalTest.m +++ b/Tests/Tests/STPPaymentIntentFunctionalTest.m @@ -124,6 +124,8 @@ - (void)disabled_testConfirmPaymentIntentSucceeds { STPPaymentIntentParams *params = [[STPPaymentIntentParams alloc] initWithClientSecret:clientSecret]; params.sourceParams = [self cardSourceParams]; + // returnURL must be passed in while confirming (not creation time) + params.returnURL = @"example-app-scheme://authorized"; [client confirmPaymentIntentWithParams:params completion:^(STPPaymentIntent * _Nullable paymentIntent, NSError * _Nullable error) { XCTAssertNil(error, @"With valid key + secret, should be able to confirm the intent"); @@ -135,6 +137,11 @@ - (void)disabled_testConfirmPaymentIntentSucceeds { // sourceParams is the 3DS-required test card XCTAssertEqual(paymentIntent.status, STPPaymentIntentStatusRequiresSourceAction); + // STPRedirectContext is relying on receiving returnURL + XCTAssertNotNil(paymentIntent.nextSourceAction.authorizeWithURL.returnURL); + XCTAssertEqualObjects(paymentIntent.nextSourceAction.authorizeWithURL.returnURL, + [NSURL URLWithString:@"example-app-scheme://authorized"]); + // Going to log all the fields, so that you, the developer manually running this test can inspect them NSLog(@"Confirmed PaymentIntent: %@", paymentIntent.allResponseFields); From b4ccf91681a01229d9d8c3f4920e3095bbda2aa8 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 17:56:19 -0800 Subject: [PATCH 12/16] Use `STPPaymentIntentSourceActionAuthorizeWithURL.returnURL` in `STPRedirectContext` Also, since we're using our normal object parsing code, could simplify the whitebox test that tried unexpected types during deserialization - covered elsewhere. --- Stripe/STPRedirectContext.m | 23 +++++++-------- Tests/Tests/STPRedirectContextTest.m | 44 ++++++++++------------------ 2 files changed, 26 insertions(+), 41 deletions(-) diff --git a/Stripe/STPRedirectContext.m b/Stripe/STPRedirectContext.m index c1064ecc35d..5107721448b 100644 --- a/Stripe/STPRedirectContext.m +++ b/Stripe/STPRedirectContext.m @@ -12,6 +12,8 @@ #import "STPBlocks.h" #import "STPDispatchFunctions.h" #import "STPPaymentIntent.h" +#import "STPPaymentIntentSourceAction.h" +#import "STPPaymentIntentSourceActionAuthorizeWithURL.h" #import "STPSource.h" #import "STPURLCallbackHandler.h" #import "STPWeakStrongMacros.h" @@ -56,24 +58,19 @@ - (nullable instancetype)initWithSource:(STPSource *)source - (nullable instancetype)initWithPaymentIntent:(STPPaymentIntent *)paymentIntent completion:(STPRedirectContextPaymentIntentCompletionBlock)completion { - NSURL *returnUrl = nil; // FIXME - if (!(returnUrl != nil - && paymentIntent.status == STPPaymentIntentStatusRequiresSourceAction - && [paymentIntent.allResponseFields[@"next_source_action"] isKindOfClass: [NSDictionary class]])) { - return nil; - } + NSURL *redirectURL = paymentIntent.nextSourceAction.authorizeWithURL.url; + NSURL *returnURL = paymentIntent.nextSourceAction.authorizeWithURL.returnURL; - NSDictionary *nextSourceAction = paymentIntent.allResponseFields[@"next_source_action"]; - if (!([nextSourceAction[@"type"] isEqual:@"authorize_with_url"] - && [nextSourceAction[@"value"] isKindOfClass:[NSDictionary class]] - && [nextSourceAction[@"value"][@"url"] isKindOfClass:[NSString class]])) { + if (paymentIntent.status != STPPaymentIntentStatusRequiresSourceAction + || paymentIntent.nextSourceAction.type != STPPaymentIntentSourceActionTypeAuthorizeWithURL + || !redirectURL + || !returnURL) { return nil; } - NSString *redirectURL = nextSourceAction[@"value"][@"url"]; return [self initWithNativeRedirectURL:nil - redirectURL:[NSURL URLWithString:redirectURL] - returnURL:returnUrl + redirectURL:redirectURL + returnURL:returnURL completion:^(NSError * _Nullable error) { completion(paymentIntent.clientSecret, error); }]; diff --git a/Tests/Tests/STPRedirectContextTest.m b/Tests/Tests/STPRedirectContextTest.m index 2b37b2baf5c..98a2961922b 100644 --- a/Tests/Tests/STPRedirectContextTest.m +++ b/Tests/Tests/STPRedirectContextTest.m @@ -139,18 +139,18 @@ - (void)testInitWithPaymentIntent { XCTAssertNil(sut.nativeRedirectURL); XCTAssertEqualObjects(sut.redirectURL.absoluteString, @"https://hooks.stripe.com/redirect/authenticate/src_1Cl1AeIl4IdHmuTb1L7x083A?client_secret=src_client_secret_DBNwUe9qHteqJ8qQBwNWiigk"); - NSURL *returnUrl = nil; // FIXME - XCTAssertEqualObjects(sut.returnURL, returnUrl); + XCTAssertNotNil(paymentIntent.nextSourceAction.authorizeWithURL.returnURL); + XCTAssertEqualObjects(sut.returnURL, paymentIntent.nextSourceAction.authorizeWithURL.returnURL); // and make sure the completion calls the completion block above - if (sut.completion) sut.completion(fakeError); // FIXME: HACK to avoid EXC_BAD_ACCESS when NULL + sut.completion(fakeError); XCTAssertTrue(completionCalled); } - (void)testInitWithPaymentIntentFailures { NSMutableDictionary *json = [[STPTestUtils jsonNamed:STPTestJSONPaymentIntent] mutableCopy]; json[@"next_source_action"] = [json[@"next_source_action"] mutableCopy]; - json[@"next_source_action"][@"value"] = [json[@"next_source_action"][@"value"] mutableCopy]; + json[@"next_source_action"][@"authorize_with_url"] = [json[@"next_source_action"][@"authorize_with_url"] mutableCopy]; void (^unusedCompletion)(NSString *, NSError *) = ^(__unused NSString * _Nonnull clientSecret, __unused NSError * _Nullable error) { XCTFail(@"should not be constructed, definitely not completed"); @@ -164,37 +164,25 @@ - (void)testInitWithPaymentIntentFailures { XCTAssertNotNil(create(), @"before mutation of json, creation should succeed"); - // `next_source_action` is not (currently) represented in the public API, and so there aren't - // any tests on it's decoding *other* than these right here. This is a white-box test for each condition - // that might result in a nil `STPRedirectContext`, because `STPRedirectContext` is the only place that - // understands `next_source_action` right now. - - json[@"next_source_action"][@"value"][@"url"] = @"not a valid URL"; - XCTAssertNil(create(), @"not created with an invalid URL in next_source_action.value.url"); - - json[@"next_source_action"][@"value"][@"url"] = @[@"an array", @"not a string"]; - XCTAssertNil(create(), @"not created with a non-string next_source_action.value.url"); - - json[@"next_source_action"][@"value"] = @"not a dictionary"; - XCTAssertNil(create(), @"not created with a non-dictionary next_source_action.value"); + json[@"status"] = @"processing"; + XCTAssertNil(create(), @"not created with wrong status"); + json[@"status"] = @"requires_source_action"; - json[@"next_source_action"][@"value"] = @{ @"url": @"http://example.com/" }; json[@"next_source_action"][@"type"] = @"not_authorize_with_url"; XCTAssertNil(create(), @"not created with wrong next_source_action.type"); - json[@"next_source_action"][@"type"] = @"authorize_with_url"; - NSString *correctStatus = json[@"status"]; - json[@"status"] = @"processing"; - XCTAssertNil(create(), @"not created with wrong status"); - json[@"status"] = correctStatus; - NSDictionary *nextSourceAction = json[@"next_source_action"]; - json[@"next_source_action"] = @"not a dictionary"; - XCTAssertNil(create(), @"not created with a non-dictionary next_source_action"); + NSString *correctURL = json[@"next_source_action"][@"authorize_with_url"][@"url"]; + json[@"next_source_action"][@"authorize_with_url"][@"url"] = @"not a valid URL"; + XCTAssertNil(create(), @"not created with an invalid URL in next_source_action.authorize_with_url.url"); + json[@"next_source_action"][@"authorize_with_url"][@"url"] = correctURL; - json[@"next_source_action"] = nextSourceAction; - json[@"return_url"] = @"not a url"; + NSString *correctReturnURL = json[@"next_source_action"][@"authorize_with_url"][@"return_url"]; + json[@"next_source_action"][@"authorize_with_url"][@"return_url"] = @"not a url"; XCTAssertNil(create(), @"not created with invalid returnUrl"); + json[@"next_source_action"][@"authorize_with_url"][@"return_url"] = correctReturnURL; + + XCTAssertNotNil(create(), @"works again when everything is back to normal"); } /** From eba2751d7d94eb243cfe4543f71d3989a6e56137 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Wed, 7 Nov 2018 18:07:40 -0800 Subject: [PATCH 13/16] Update MIGRATING for removal of `STPPaymentIntent.returnUrl` --- MIGRATING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MIGRATING.md b/MIGRATING.md index 73ce864f328..549fd08b409 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -6,6 +6,7 @@ * Changes to the object returned by `STPPaymentCardTextField.cardParams` no longer mutate the object held by the `STPPaymentCardTextField` * This is a breaking change for code like: `paymentCardTextField.cardParams.name = @"Jane Doe";` * `STPPaymentIntentParams.returnUrl` has been renamed to `STPPaymentIntentParams.returnURL`. Xcode should offer a deprecation warning & fix-it to help you migrate. +* `STPPaymentIntent.returnUrl` has been removed, because it's no longer a property of the PaymentIntent. When the PaymentIntent status is `.requiresSourceAction`, and the `nextSourceAction.type` is `.authorizeWithURL`, you can find the return URL at `nextSourceAction.authorizeWithURL.returnURL`. ### Migrating from versions < 13.1.0 * The SDK now supports PaymentIntents with `STPPaymentIntent`, which use `STPRedirectContext` in the same way that `STPSource` does From 04d4d10ab5ebb92244f07cf43ff9e89fcd548a44 Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Thu, 8 Nov 2018 14:25:23 -0800 Subject: [PATCH 14/16] Use SDK's enum value instead of server's string constant in documentation --- .../STPPaymentIntentSourceActionAuthorizeWithURL.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h b/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h index 536398c032a..81b89d10fe0 100644 --- a/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h +++ b/Stripe/PublicHeaders/STPPaymentIntentSourceActionAuthorizeWithURL.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN /** - The `STPPaymentIntentSourceAction` details when type is `authorize_with_url`. + The `STPPaymentIntentSourceAction` details when type is `STPPaymentIntentSourceActionTypeAuthorizeWithURL`. These are created & owned by the containing `STPPaymentIntent`. */ From 40e9acf7c3ccfb0fb0aeb1a9b89abd11d332763c Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Thu, 8 Nov 2018 14:25:39 -0800 Subject: [PATCH 15/16] Use dict, not response, while decoding. --- Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m b/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m index 82fe6cab006..3c24de7e799 100644 --- a/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m +++ b/Stripe/STPPaymentIntentSourceActionAuthorizeWithURL.m @@ -40,7 +40,7 @@ + (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)r } // required fields - NSURL *url = [response stp_urlForKey:@"url"]; + NSURL *url = [dict stp_urlForKey:@"url"]; if (!url) { return nil; } From 09614b1359039e69476afaeb0f7e9e63f5479d8f Mon Sep 17 00:00:00 2001 From: Dan Jackson <danj@stripe.com> Date: Tue, 13 Nov 2018 15:43:43 -0800 Subject: [PATCH 16/16] Fix copy/paste error in failing test --- Tests/Tests/STPPaymentIntentTest.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Tests/STPPaymentIntentTest.m b/Tests/Tests/STPPaymentIntentTest.m index 778fd3b71fd..61f8b340b88 100644 --- a/Tests/Tests/STPPaymentIntentTest.m +++ b/Tests/Tests/STPPaymentIntentTest.m @@ -110,7 +110,7 @@ - (void)testConfirmationMethodFromString { - (void)testSourceActionFromString { XCTAssertEqual([STPPaymentIntent sourceActionTypeFromString:@"authorize_with_url"], STPPaymentIntentSourceActionTypeAuthorizeWithURL); - XCTAssertEqual([STPPaymentIntent confirmationMethodFromString:@"AUTHORIZE_WITH_URL"], + XCTAssertEqual([STPPaymentIntent sourceActionTypeFromString:@"AUTHORIZE_WITH_URL"], STPPaymentIntentSourceActionTypeAuthorizeWithURL); XCTAssertEqual([STPPaymentIntent confirmationMethodFromString:@"garbage"],