Skip to content

Commit

Permalink
Add tests for changes from #937: ignoring 3rd party load failures whi…
Browse files Browse the repository at this point in the history
…le redirecting

I didn't realize that `STPRedirectContext` was as well tested as it is. I ran into test
failures when executing on iOS 10 (our CI executes against iOS 11), and realized this
needed to be updated.

Recap of behavior change: only report errors in initial load on iOS 11+, and only if
the latest URL was a `stripe.com` URL.

When unit tests were run against iOS 11, this was still true, and the existing test passed.

This adds two more tests: for pre-iOS 11 and for iOS 11 with a redirect to non-stripe.com.
Both of those cases should not report an error, and should not close the Safari View
Controller.

We don't have `guard-let` in Obj-C, nor can we check `!@available(...)`, but I have
emulated that structure at the beginning of these tests. I think it's worth it, and
Joey didn't think it was unreasonable.
  • Loading branch information
danj-stripe committed May 23, 2018
1 parent 08f6a79 commit 5817024
Showing 1 changed file with 92 additions and 3 deletions.
95 changes: 92 additions & 3 deletions Tests/Tests/STPRedirectContextTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,54 @@ - (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]]);
}

/**
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"];
Expand Down Expand Up @@ -258,6 +302,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.
Expand Down

0 comments on commit 5817024

Please sign in to comment.