// 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/bring_android_tabs/ui_bundled/bring_android_tabs_prompt_mediator.h"
#import "base/memory/raw_ptr.h"
#import "base/test/metrics/histogram_tester.h"
#import "components/segmentation_platform/embedder/default_model/device_switcher_result_dispatcher.h"
#import "ios/chrome/browser/bring_android_tabs/model/bring_android_tabs_to_ios_service.h"
#import "ios/chrome/browser/bring_android_tabs/model/fake_bring_android_tabs_to_ios_service.h"
#import "ios/chrome/browser/bring_android_tabs/model/metrics.h"
#import "ios/chrome/browser/segmentation_platform/model/segmentation_platform_service_factory.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/sync/model/session_sync_service_factory.h"
#import "ios/chrome/browser/sync/model/sync_service_factory.h"
#import "ios/chrome/browser/synced_sessions/model/distant_tab.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/platform_test.h"
// Test fixture for BringAndroidTabsPromptMediator.
class BringAndroidTabsPromptMediatorTest : public PlatformTest {
public:
BringAndroidTabsPromptMediatorTest() : PlatformTest() {
// Environment setup.
TestChromeBrowserState::Builder builder;
builder.AddTestingFactory(
segmentation_platform::SegmentationPlatformServiceFactory::
GetInstance(),
segmentation_platform::SegmentationPlatformServiceFactory::
GetDefaultFactory());
browser_state_ = std::move(builder).Build();
// Create a tab in the mock BringAndroidTabsToIOS service.
std::vector<std::unique_ptr<synced_sessions::DistantTab>> tabs;
std::unique_ptr<synced_sessions::DistantTab> tab =
std::make_unique<synced_sessions::DistantTab>();
tabs.push_back(std::move(tab));
// Create the BringAndroidTabsToIOSService.
segmentation_platform::DeviceSwitcherResultDispatcher* dispatcher =
segmentation_platform::SegmentationPlatformServiceFactory::
GetDispatcherForBrowserState(browser_state_.get());
syncer::SyncService* sync_service =
SyncServiceFactory::GetForBrowserState(browser_state_.get());
sync_sessions::SessionSyncService* session_sync_service =
SessionSyncServiceFactory::GetForBrowserState(browser_state_.get());
PrefService* prefs = browser_state_->GetPrefs();
fake_bring_android_tabs_service_ = new FakeBringAndroidTabsToIOSService(
std::move(tabs), dispatcher, sync_service, session_sync_service, prefs);
// Create the mediator.
mediator_ = [[BringAndroidTabsPromptMediator alloc]
initWithBringAndroidTabsService:fake_bring_android_tabs_service_
URLLoader:nullptr];
}
// Property accessors.
id<BringAndroidTabsPromptViewControllerDelegate> delegate() {
return mediator_;
}
FakeBringAndroidTabsToIOSService* bring_android_tabs_service() {
return fake_bring_android_tabs_service_;
}
private:
// Environment mocks.
web::WebTaskEnvironment task_environment_;
raw_ptr<FakeBringAndroidTabsToIOSService> fake_bring_android_tabs_service_;
// Mediator dependencies.
std::unique_ptr<TestChromeBrowserState> browser_state_;
BringAndroidTabsPromptMediator* mediator_;
};
// Tests that when the prompt is displayed, the mediator logs histogram and
// updates the profile pref accordingly.
TEST_F(BringAndroidTabsPromptMediatorTest, ShowPrompt) {
base::HistogramTester histogram_tester;
[delegate() bringAndroidTabsPromptViewControllerDidShow];
EXPECT_TRUE(bring_android_tabs_service()->displayed());
EXPECT_FALSE(bring_android_tabs_service()->interacted());
// Verify that no duplicate metric is logged in histogram.
[delegate() bringAndroidTabsPromptViewControllerDidShow];
histogram_tester.ExpectUniqueSample(
bring_android_tabs::kTabCountHistogramName, 1, 1);
}
// Tests when the prompt is displayed and the user taps "open tabs", the
// mediator logs histogram, opens tabs on request, and that the prompt display
// is recorded.
TEST_F(BringAndroidTabsPromptMediatorTest, OpenTabs) {
base::HistogramTester histogram_tester;
[delegate() bringAndroidTabsPromptViewControllerDidShow];
[delegate() bringAndroidTabsPromptViewControllerDidTapOpenAllButton];
histogram_tester.ExpectUniqueSample(
bring_android_tabs::kPromptActionHistogramName,
bring_android_tabs::PromptActionType::kOpenTabs, 1);
EXPECT_TRUE(bring_android_tabs_service()->interacted());
std::vector<size_t> opened_tabs =
bring_android_tabs_service()->opened_tabs_at_indices();
ASSERT_EQ(opened_tabs.size(), 1u);
EXPECT_EQ(opened_tabs[0], 0u);
}
// Tests that mediator logs histogram when the user taps "reviews tabs", and the
// interaction is recorded so that it would not be displayed again.
TEST_F(BringAndroidTabsPromptMediatorTest, ReviewTabs) {
base::HistogramTester histogram_tester;
[delegate() bringAndroidTabsPromptViewControllerDidShow];
[delegate() bringAndroidTabsPromptViewControllerDidTapReviewButton];
histogram_tester.ExpectUniqueSample(
bring_android_tabs::kPromptActionHistogramName,
bring_android_tabs::PromptActionType::kReviewTabs, 1);
EXPECT_TRUE(bring_android_tabs_service()->interacted());
EXPECT_EQ(bring_android_tabs_service()->opened_tabs_at_indices().size(), 0u);
}
// Tests that mediator logs histogram when the user closes the prompt, and the
// interaction is recorded so that it would not be displayed again.
TEST_F(BringAndroidTabsPromptMediatorTest, TapCloseButton) {
base::HistogramTester histogram_tester;
[delegate() bringAndroidTabsPromptViewControllerDidShow];
[delegate() bringAndroidTabsPromptViewControllerDidDismissWithSwipe:NO];
histogram_tester.ExpectUniqueSample(
bring_android_tabs::kPromptActionHistogramName,
bring_android_tabs::PromptActionType::kCancel, 1);
EXPECT_TRUE(bring_android_tabs_service()->interacted());
EXPECT_EQ(bring_android_tabs_service()->opened_tabs_at_indices().size(), 0u);
}
// Tests that mediator logs histogram when the user swipes the prompt down, and
// the interaction is recorded so that it would not be displayed again.
TEST_F(BringAndroidTabsPromptMediatorTest, SwipeToDismiss) {
base::HistogramTester histogram_tester;
[delegate() bringAndroidTabsPromptViewControllerDidShow];
[delegate() bringAndroidTabsPromptViewControllerDidDismissWithSwipe:YES];
histogram_tester.ExpectUniqueSample(
bring_android_tabs::kPromptActionHistogramName,
bring_android_tabs::PromptActionType::kSwipeToDismiss, 1);
EXPECT_TRUE(bring_android_tabs_service()->interacted());
EXPECT_EQ(bring_android_tabs_service()->opened_tabs_at_indices().size(), 0u);
}