chromium/ios/chrome/browser/default_promo/ui_bundled/generic/default_browser_generic_promo_coordinator_unittest.mm

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/default_promo/ui_bundled/generic/default_browser_generic_promo_coordinator.h"

#import "base/apple/foundation_util.h"
#import "base/memory/raw_ptr.h"
#import "base/test/metrics/histogram_tester.h"
#import "base/test/metrics/user_action_tester.h"
#import "base/test/scoped_feature_list.h"
#import "base/test/task_environment.h"
#import "components/feature_engagement/public/event_constants.h"
#import "components/feature_engagement/public/feature_constants.h"
#import "components/feature_engagement/test/mock_tracker.h"
#import "ios/chrome/browser/default_promo/ui_bundled/generic/default_browser_generic_promo_view_controller.h"
#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/chrome/test/scoped_key_window.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"

namespace {

// Create the Feature Engagement Mock Tracker.
std::unique_ptr<KeyedService> BuildFeatureEngagementMockTracker(
    web::BrowserState* browser_state) {
  return std::make_unique<feature_engagement::test::MockTracker>();
}

void ExpectTotalCountForTriggerCriteriaExperiment(
    base::HistogramTester* histogram_tester,
    const std::string& action_str,
    int count) {
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".PromoDisplayCount", count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".LastPromoInteractionNumDays",
      count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".ChromeColdStartCount", count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".ChromeWarmStartCount", count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".ChromeIndirectStartCount",
      count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".PasswordManagerUseCount",
      count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".OmniboxClipboardUseCount",
      count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".BookmarkUseCount", count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".AutofllUseCount", count);
  histogram_tester->ExpectTotalCount(
      "IOS.DefaultBrowserPromo." + action_str + ".SpecialTabsUseCount", count);
}

}  // namespace

#pragma mark - Fixture.

// Fixture to test DefaultBrowserGenericPromoCoordinator.
class DefaultBrowserGenericPromoCoordinatorTest : public PlatformTest {
 protected:
  void SetUp() override {
    PlatformTest::SetUp();

    TestChromeBrowserState::Builder builder;
    builder.AddTestingFactory(
        feature_engagement::TrackerFactory::GetInstance(),
        base::BindRepeating(&BuildFeatureEngagementMockTracker));

    browser_state_ = std::move(builder).Build();
    browser_ = std::make_unique<TestBrowser>(browser_state_.get());
    view_controller_ = [[UIViewController alloc] init];
    [scoped_key_window_.Get() setRootViewController:view_controller_];

    mock_tracker_ = static_cast<feature_engagement::test::MockTracker*>(
        feature_engagement::TrackerFactory::GetForBrowserState(
            browser_state_.get()));

    coordinator_ = [[DefaultBrowserGenericPromoCoordinator alloc]
        initWithBaseViewController:view_controller_
                           browser:browser_.get()];
  }

  void TearDown() override {
    [coordinator_ stop];
    PlatformTest::TearDown();
  }

  base::test::TaskEnvironment task_environment_;
  IOSChromeScopedTestingLocalState scoped_testing_local_state_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<TestBrowser> browser_;
   DefaultBrowserGenericPromoCoordinator* coordinator_;
  ScopedKeyWindow scoped_key_window_;
  UIViewController* view_controller_;
  raw_ptr<feature_engagement::test::MockTracker> mock_tracker_;
};

#pragma mark - Tests.

// Tests that the proper metrics and FET events are fired when tapping Remind Me
// Later.
TEST_F(DefaultBrowserGenericPromoCoordinatorTest, TestRemindMeLater) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitWithFeatures(
      {feature_engagement::kIPHiOSPromoDefaultBrowserReminderFeature}, {});
  base::UserActionTester user_action_tester;
  base::HistogramTester histogram_tester;

  EXPECT_NSEQ(nil, view_controller_.presentedViewController);

  coordinator_.promoWasFromRemindMeLater = NO;
  [coordinator_ start];
  EXPECT_EQ(1, user_action_tester.GetActionCount(
                   "IOS.DefaultBrowserVideoPromo.Appear"));

  // This should present a GenericDefaultBrowserPromoViewController.
  ASSERT_TRUE([view_controller_.presentedViewController
      isKindOfClass:[DefaultBrowserGenericPromoViewController class]]);
   DefaultBrowserGenericPromoViewController* generic_promo_view_controller =
      base::apple::ObjCCastStrict<DefaultBrowserGenericPromoViewController>(
          view_controller_.presentedViewController);

  EXPECT_EQ(YES, generic_promo_view_controller.hasRemindMeLater);

  // Prepare to tap tertiary action.
  EXPECT_CALL(
      *mock_tracker_,
      NotifyEvent(
          feature_engagement::events::kDefaultBrowserPromoRemindMeLater));

  [generic_promo_view_controller.actionHandler confirmationAlertTertiaryAction];

  EXPECT_EQ(1, user_action_tester.GetActionCount(
                   "IOS.DefaultBrowserVideoPromo.Fullscreen.RemindMeLater"));
  histogram_tester.ExpectBucketCount("IOS.DefaultBrowserVideoPromo.Fullscreen",
                                     3, 1);
}

// Tests that the right histograms are recorded for trigger criteria experiment.
TEST_F(DefaultBrowserGenericPromoCoordinatorTest,
       TestTriggerCriteriaExperimentCancelAction) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      feature_engagement::kDefaultBrowserTriggerCriteriaExperiment);
  base::HistogramTester histogram_tester;

  [coordinator_ start];

  // Check that histograms for appear action are recorded, but for other actions
  // there are not.
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Appear", 1);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester,
                                               "PrimaryAction", 0);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Cancel", 0);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Dismiss", 0);

  DefaultBrowserGenericPromoViewController* generic_promo_view_controller =
      base::apple::ObjCCastStrict<DefaultBrowserGenericPromoViewController>(
          view_controller_.presentedViewController);
  [generic_promo_view_controller
          .actionHandler confirmationAlertSecondaryAction];

  // Check that after dismissing the promo only histograms for cancel action are
  // recorded.
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Appear", 1);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester,
                                               "PrimaryAction", 0);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Cancel", 1);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Dismiss", 0);
}

// Tests that the right histograms are recorded for trigger criteria experiment.
TEST_F(DefaultBrowserGenericPromoCoordinatorTest,
       TestTriggerCriteriaExperimentPrimaryAction) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      feature_engagement::kDefaultBrowserTriggerCriteriaExperiment);
  base::HistogramTester histogram_tester;

  [coordinator_ start];

  // Mock the mediator which otherwise will open the iOS settings on primary
  // action. This can be a problem for next tests.
  id mock_mediator = OCMClassMock([DefaultBrowserGenericPromoMediator class]);
  coordinator_.mediator = mock_mediator;

  // Check that histograms for appear action are recorded, but for other actions
  // there are not.
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Appear", 1);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester,
                                               "PrimaryAction", 0);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Cancel", 0);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Dismiss", 0);

  DefaultBrowserGenericPromoViewController* generic_promo_view_controller =
      base::apple::ObjCCastStrict<DefaultBrowserGenericPromoViewController>(
          view_controller_.presentedViewController);
  [generic_promo_view_controller.actionHandler confirmationAlertPrimaryAction];

  // Check that after primaryaction the promo only histograms for primary action
  // action are recorded.
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Appear", 1);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester,
                                               "PrimaryAction", 1);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Cancel", 0);
  ExpectTotalCountForTriggerCriteriaExperiment(&histogram_tester, "Dismiss", 0);
}