blob: 2309e5f90339b1d463c2acf092202b8cfc383139 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/store_kit/store_kit_coordinator.h"
#import <StoreKit/StoreKit.h>
#import "base/test/ios/wait_util.h"
#import "ios/chrome/test/fakes/fake_ui_view_controller.h"
#import "ios/chrome/test/scoped_key_window.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Test fixture for StoreKitCoordinator class.
class StoreKitCoordinatorTest : public PlatformTest {
protected:
StoreKitCoordinatorTest()
: root_view_controller_([[UIViewController alloc] init]),
base_view_controller_([[UIViewController alloc] init]),
coordinator_([[StoreKitCoordinator alloc]
initWithBaseViewController:base_view_controller_]) {
[scoped_key_window_.Get() setRootViewController:root_view_controller_];
[root_view_controller_ presentViewController:base_view_controller_
animated:NO
completion:nil];
}
~StoreKitCoordinatorTest() override {
// Make sure StoreKit has been dismissed.
if (base_view_controller_.presentedViewController) {
[coordinator_ stop];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return !base_view_controller_.presentedViewController;
}));
}
}
UIViewController* root_view_controller_;
UIViewController* base_view_controller_;
StoreKitCoordinator* coordinator_;
ScopedKeyWindow scoped_key_window_;
};
// Tests that StoreKitCoordinator presents SKStoreProductViewController when
// openAppStoreWithParameters is called.
TEST_F(StoreKitCoordinatorTest, OpenStoreWithParamsPresentViewController) {
NSDictionary* product_params = @{
SKStoreProductParameterITunesItemIdentifier : @"TestITunesItemIdentifier",
SKStoreProductParameterAffiliateToken : @"TestToken"
};
[coordinator_ openAppStoreWithParameters:product_params];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
EXPECT_NSEQ(product_params, coordinator_.iTunesProductParameters);
EXPECT_EQ([SKStoreProductViewController class],
[base_view_controller_.presentedViewController class]);
[coordinator_ stop];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return !base_view_controller_.presentedViewController;
}));
EXPECT_FALSE(base_view_controller_.presentedViewController);
}
// Tests that StoreKitCoordinator presents SKStoreProductViewController when
// openAppStore is called.
TEST_F(StoreKitCoordinatorTest, OpenStorePresentViewController) {
NSString* kTestITunesItemIdentifier = @"TestITunesItemIdentifier";
NSDictionary* product_params = @{
SKStoreProductParameterITunesItemIdentifier : kTestITunesItemIdentifier,
};
[coordinator_ openAppStore:kTestITunesItemIdentifier];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
EXPECT_NSEQ(product_params, coordinator_.iTunesProductParameters);
EXPECT_EQ([SKStoreProductViewController class],
[base_view_controller_.presentedViewController class]);
[coordinator_ stop];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return !base_view_controller_.presentedViewController;
}));
EXPECT_FALSE(base_view_controller_.presentedViewController);
}
// Tests that when there is a SKStoreProductViewController presented, starting
// the coordinator doesn't present new view controller.
TEST_F(StoreKitCoordinatorTest, NoOverlappingStoreKitsPresented) {
NSString* kTestITunesItemIdentifier = @"TestITunesItemIdentifier";
coordinator_.iTunesProductParameters = @{
SKStoreProductParameterITunesItemIdentifier : kTestITunesItemIdentifier,
};
[coordinator_ start];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
EXPECT_EQ([SKStoreProductViewController class],
[base_view_controller_.presentedViewController class]);
UIViewController* presented_controller =
base_view_controller_.presentedViewController;
[coordinator_ start];
// Verify that that presented view controlled is not changed.
EXPECT_NSEQ(presented_controller,
base_view_controller_.presentedViewController);
[coordinator_ stop];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return !base_view_controller_.presentedViewController;
}));
EXPECT_FALSE(base_view_controller_.presentedViewController);
[coordinator_ start];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
// After reseting the view controller, a new storekit view should be
// presented.
EXPECT_EQ([SKStoreProductViewController class],
[base_view_controller_.presentedViewController class]);
EXPECT_NSNE(presented_controller,
base_view_controller_.presentedViewController);
}
// Tests that if the base view controller is presenting any view controller,
// starting the coordinator doesn't present new view controller.
// TODO:(crbug.com/968514): Re-enable this test on devices.
#if TARGET_OS_SIMULATOR
#define MAYBE_NoOverlappingPresentedViewControllers \
NoOverlappingPresentedViewControllers
#else
#define MAYBE_NoOverlappingPresentedViewControllers \
FLAKY_NoOverlappingPresentedViewControllers
#endif
TEST_F(StoreKitCoordinatorTest, MAYBE_NoOverlappingPresentedViewControllers) {
NSString* kTestITunesItemIdentifier = @"TestITunesItemIdentifier";
coordinator_.iTunesProductParameters = @{
SKStoreProductParameterITunesItemIdentifier : kTestITunesItemIdentifier,
};
EXPECT_FALSE(base_view_controller_.presentedViewController);
UIViewController* dummy_view_controller = [[UIViewController alloc] init];
[base_view_controller_ presentViewController:dummy_view_controller
animated:NO
completion:nil];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
EXPECT_NSEQ(dummy_view_controller,
base_view_controller_.presentedViewController);
[coordinator_ start];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
// Verify that that presented view controlled is not changed.
EXPECT_NSEQ(dummy_view_controller,
base_view_controller_.presentedViewController);
[coordinator_ stop];
[dummy_view_controller dismissViewControllerAnimated:NO completion:nil];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return !base_view_controller_.presentedViewController;
}));
EXPECT_FALSE(base_view_controller_.presentedViewController);
[coordinator_ start];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
// After reseting the view controller, a new storekit view should be
// presented.
EXPECT_EQ([SKStoreProductViewController class],
[base_view_controller_.presentedViewController class]);
}
// iOS 13 dismisses SKStoreProductViewController when user taps "Done". This
// test makes sure that StoreKitCoordinator gracefully handles the situation.
TEST_F(StoreKitCoordinatorTest, StopAfterDismissingPresentedViewController) {
NSDictionary* product_params = @{
SKStoreProductParameterITunesItemIdentifier : @"TestITunesItemIdentifier",
};
[coordinator_ openAppStoreWithParameters:product_params];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return base_view_controller_.presentedViewController;
}));
// iOS 13 dismisses SKStoreProductViewController when user taps "Done".
[base_view_controller_.presentedViewController
dismissViewControllerAnimated:NO
completion:nil];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^{
return !base_view_controller_.presentedViewController;
}));
// Make sure that base view controller is not dismissed (crbug.com.1027058).
[coordinator_ stop];
EXPECT_FALSE(base::test::ios::WaitUntilConditionOrTimeout(1.0, ^{
return !root_view_controller_.presentedViewController;
}));
}