diff --git a/Tests/Tests/STPRedirectContextTest.m b/Tests/Tests/STPRedirectContextTest.m index 51ce59b9fb2..bc6d95113fb 100644 --- a/Tests/Tests/STPRedirectContextTest.m +++ b/Tests/Tests/STPRedirectContextTest.m @@ -107,6 +107,7 @@ - (void)testSafariViewControllerRedirectFlow_foregroundNotification { OCMVerify([mockVC presentViewController:[OCMArg checkWithBlock:checker] animated:YES completion:[OCMArg any]]); + [self unsubscribeContext:context]; } @@ -223,10 +224,55 @@ - (void)testSafariViewControllerRedirectFlow_didFinish { /** After starting a SafariViewController redirect flow, - when SafariViewController fails to load, RedirectContext's completion block - and dismiss method should be called. + when SafariViewController fails to load the initial page (on iOS < 11.0), + RedirectContext's completion block should not be called (SFVC keeps loading) */ -- (void)testSafariViewControllerRedirectFlow_failedToLoad { +- (void)testSafariViewControllerRedirectFlow_failedInitialLoad_preiOS11 { + if (@available(iOS 11, *)) { + // See testSafariViewControllerRedirectFlow_failedInitialLoad_iOS11Plus + // and testSafariViewControllerRedirectFlow_failedInitialLoadAfterRedirect_iOS11Plus + return; // Skipping + } + + id mockVC = OCMClassMock([UIViewController class]); + STPSource *source = [STPFixtures iDEALSource]; + STPRedirectContext *context = [[STPRedirectContext alloc] initWithSource:source completion:^(__unused NSString *sourceID, __unused NSString *clientSecret, __unused NSError *error) { + XCTFail(@"completion called"); + }]; + id sut = OCMPartialMock(context); + + OCMReject([sut unsubscribeFromNotifications]); + OCMReject([sut dismissPresentedViewController]); + + [sut startSafariViewControllerRedirectFlowFromViewController:mockVC]; + + BOOL(^checker)(id) = ^BOOL(id vc) { + if ([vc isKindOfClass:[SFSafariViewController class]]) { + SFSafariViewController *sfvc = (SFSafariViewController *)vc; + // Tell the delegate that the initial load failed. on iOS 10, this is a no-op + [sfvc.delegate safariViewController:sfvc didCompleteInitialLoad:NO]; + return YES; + } + return NO; + }; + OCMVerify([mockVC presentViewController:[OCMArg checkWithBlock:checker] + animated:YES + completion:[OCMArg any]]); + [self unsubscribeContext:context]; +} + +/** + After starting a SafariViewController redirect flow, + when SafariViewController fails to load the initial page (on iOS 11+ & without redirects), + RedirectContext's completion block and dismiss method should be called. + */ +- (void)testSafariViewControllerRedirectFlow_failedInitialLoad_iOS11Plus API_AVAILABLE(ios(11)) { + if (@available(iOS 11, *)) {} + else { + // see testSafariViewControllerRedirectFlow_failedInitialLoad_preiOS11 + return; // Skipping + } + id mockVC = OCMClassMock([UIViewController class]); STPSource *source = [STPFixtures iDEALSource]; XCTestExpectation *exp = [self expectationWithDescription:@"completion"]; @@ -258,6 +304,51 @@ - (void)testSafariViewControllerRedirectFlow_failedToLoad { [self waitForExpectationsWithTimeout:2 handler:nil]; } +/** + After starting a SafariViewController redirect flow, + when SafariViewController fails to load the initial page (on iOS 11+ after redirecting to non-Stripe page), + RedirectContext's completion block should not be called (SFVC keeps loading) + */ + +- (void)testSafariViewControllerRedirectFlow_failedInitialLoadAfterRedirect_iOS11Plus API_AVAILABLE(ios(11)) { + if (@available(iOS 11, *)) {} + else { + // see testSafariViewControllerRedirectFlow_failedInitialLoad_preiOS11 + return; // Skipping + } + + id mockVC = OCMClassMock([UIViewController class]); + STPSource *source = [STPFixtures iDEALSource]; + STPRedirectContext *context = [[STPRedirectContext alloc] initWithSource:source completion:^(__unused NSString *sourceID, __unused NSString *clientSecret, __unused NSError *error) { + XCTFail(@"completion called"); + }]; + id sut = OCMPartialMock(context); + + OCMReject([sut unsubscribeFromNotifications]); + OCMReject([sut dismissPresentedViewController]); + + [sut startSafariViewControllerRedirectFlowFromViewController:mockVC]; + + BOOL(^checker)(id) = ^BOOL(id vc) { + if ([vc isKindOfClass:[SFSafariViewController class]]) { + SFSafariViewController *sfvc = (SFSafariViewController *)vc; + // before initial load is done, SFVC was redirected to a non-stripe.com domain + [sfvc.delegate safariViewController:sfvc + initialLoadDidRedirectToURL:[NSURL URLWithString:@"https://girogate.de"]]; + // Tell the delegate that the initial load failed. + // on iOS 11, with the redirect, this is a no-op + [sfvc.delegate safariViewController:sfvc didCompleteInitialLoad:NO]; + return YES; + } + return NO; + }; + OCMVerify([mockVC presentViewController:[OCMArg checkWithBlock:checker] + animated:YES + completion:[OCMArg any]]); + + [self unsubscribeContext:context]; +} + /** After starting a SafariViewController redirect flow, when the RedirectContext is cancelled, its dismiss method should be called.