blob: b8777ded9af2949c23fc3865cd42c2c6ae1a1c32 [file] [log] [blame]
// 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 "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/public/tracker.h"
#import "components/feature_engagement/test/scoped_iph_feature_list.h"
#import "components/feature_engagement/test/test_tracker.h"
#import "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// The minimum number of times Chrome must be opened in order for the Reading
// List Badge to be shown.
const int kMinChromeOpensRequiredForReadingList = 5;
// The minimum number of times Chrome must be opened in order for the New Tab
// Tip to be shown.
const int kMinChromeOpensRequiredForNewTabTip = 3;
} // namespace
// Unittests related to the triggering of In Product Help features. Anything
// that tests what events cause a feature to trigger should be tested there.
class FeatureEngagementTest : public PlatformTest {
public:
FeatureEngagementTest();
~FeatureEngagementTest() override;
std::map<std::string, std::string> BadgedReadingListParams() {
std::map<std::string, std::string> params;
params["event_1"] =
"name:chrome_opened;comparator:>=5;window:90;storage:90";
params["event_trigger"] =
"name:badged_reading_list_trigger;comparator:==0;window:1095;storage:"
"1095";
params["event_used"] =
"name:viewed_reading_list;comparator:==0;window:90;storage:90";
params["session_rate"] = "==0";
params["availability"] = "any";
return params;
}
std::map<std::string, std::string> BadgedTranslateManualTriggerParams() {
std::map<std::string, std::string> params;
params["availability"] = "any";
params["session_rate"] = "==0";
params["event_used"] = "name:triggered_translate_infobar;comparator:==0;"
"window:360;storage:360";
params["event_trigger"] = "name:badged_translate_manual_trigger_trigger;"
"comparator:==0;window:360;"
"storage:360";
return params;
}
std::map<std::string, std::string> NewTabTipPromoParams() {
std::map<std::string, std::string> params;
params["event_1"] =
"name:chrome_opened;comparator:>=3;window:90;storage:90";
params["event_trigger"] =
"name:new_tab_tip_trigger;comparator:<2;window:1095;storage:"
"1095";
params["event_used"] =
"name:new_tab_opened;comparator:==0;window:90;storage:90";
params["session_rate"] = "==0";
params["availability"] = "any";
return params;
}
std::map<std::string, std::string> BottomToolbarTipParams() {
std::map<std::string, std::string> params;
params["availability"] = "any";
params["session_rate"] = "==0";
params["event_used"] =
"name:bottom_toolbar_opened;comparator:any;window:90;storage:90";
params["event_trigger"] =
"name:bottom_toolbar_trigger;comparator:==0;window:90;storage:90";
return params;
}
std::map<std::string, std::string> LongPressTipParams() {
std::map<std::string, std::string> params;
params["availability"] = "any";
params["session_rate"] = "<=1";
params["event_used"] =
"name:long_press_toolbar_opened;comparator:any;window:90;storage:90";
params["event_trigger"] =
"name:long_press_toolbar_trigger;comparator:==0;window:90;storage:90";
params["event_1"] =
"name:bottom_toolbar_opened;comparator:>=1;window:90;storage:90";
return params;
}
std::map<std::string, std::string> DefaultSiteViewTipParams() {
std::map<std::string, std::string> params;
params["availability"] = "any";
params["session_rate"] = "<3";
params["event_used"] =
"name:default_site_view_used;comparator:==0;window:720;storage:720";
params["event_trigger"] =
"name:default_site_view_shown;comparator:==0;window:720;storage:720";
params["event_1"] =
"name:desktop_version_requested;comparator:>=3;window:60;storage:60";
return params;
}
std::map<std::string, std::string> TabPinnedTipParams() {
std::map<std::string, std::string> params;
params["availability"] = "any";
params["session_rate"] = "any";
params["event_used"] = "name:popup_menu_tip_used;comparator:==0;window:180;"
"storage:180";
params["event_trigger"] =
"name:tab_pinned_tip_triggered;comparator:==0;window:1825;"
"storage:1825";
return params;
}
base::RepeatingCallback<void(bool)> BoolArgumentQuitClosure() {
return base::IgnoreArgs<bool>(run_loop_.QuitClosure());
}
protected:
base::test::TaskEnvironment task_environment_;
base::RunLoop run_loop_;
};
FeatureEngagementTest::FeatureEngagementTest() {}
FeatureEngagementTest::~FeatureEngagementTest() {}
// Tests the Badged Reading List promo triggers if the user has opened Chrome
// enough times.
TEST_F(FeatureEngagementTest, TestBadgedReadingListTriggers) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHBadgedReadingListFeature,
BadgedReadingListParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Ensure that Chrome has been launched enough times for the Badged Reading
// List to appear.
for (int index = 0; index < kMinChromeOpensRequiredForReadingList; index++) {
tracker->NotifyEvent(feature_engagement::events::kChromeOpened);
}
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedReadingListFeature));
}
// Tests the Badged Reading List promo does not trigger if the user has opened
// Chrome too few times.
TEST_F(FeatureEngagementTest, TestBadgedReadingListTooFewChromeOpens) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHBadgedReadingListFeature,
BadgedReadingListParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Only open Chrome once
tracker->NotifyEvent(feature_engagement::events::kChromeOpened);
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedReadingListFeature));
}
// Tests the Badged Reading List promo does not trigger a second time after it
// has already triggered once
TEST_F(FeatureEngagementTest, TestBadgedReadingListAlreadyUsed) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHBadgedReadingListFeature,
BadgedReadingListParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Ensure that Chrome has been launched enough times for the Badged Reading
// List to appear.
for (int index = 0; index < kMinChromeOpensRequiredForReadingList; index++) {
tracker->NotifyEvent(feature_engagement::events::kChromeOpened);
}
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedReadingListFeature));
// Dismiss IPH.
tracker->Dismissed(feature_engagement::kIPHBadgedReadingListFeature);
// The IPH should not trigger the second time
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedReadingListFeature));
}
// Verifies that the Badged Manual Translate Trigger feature shows only once
// when the triggering conditions are met.
TEST_F(FeatureEngagementTest, TestBadgedTranslateManualTriggerShouldShowOnce) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHBadgedTranslateManualTriggerFeature,
BadgedTranslateManualTriggerParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedTranslateManualTriggerFeature));
// Dismiss IPH.
tracker->Dismissed(
feature_engagement::kIPHBadgedTranslateManualTriggerFeature);
// The IPH should not trigger the second time
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedTranslateManualTriggerFeature));
}
// Verifes that the New Tab Tip Promo is triggered after the proper conditions
// are met.
TEST_F(FeatureEngagementTest, TestNewTabTipPromoShouldShow) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHNewTabTipFeature, NewTabTipPromoParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Ensure that Chrome has been launched enough times to meet the trigger
// condition.
for (int index = 0; index < kMinChromeOpensRequiredForNewTabTip; index++) {
tracker->NotifyEvent(feature_engagement::events::kChromeOpened);
}
EXPECT_TRUE(
tracker->ShouldTriggerHelpUI(feature_engagement::kIPHNewTabTipFeature));
}
// Verifies that the bottom toolbar tip triggers.
TEST_F(FeatureEngagementTest, TestBottomToolbarTipTriggers) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHBottomToolbarTipFeature,
BottomToolbarTipParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBottomToolbarTipFeature));
}
// Verifies that the longpress toolbar tip is displayed after the bottom toolbar
// tip is opened
TEST_F(FeatureEngagementTest, TestLongPressTipAppearAfterBottomToolbar) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHLongPressToolbarTipFeature,
LongPressTipParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Open the bottom toolbar.
tracker->NotifyEvent(feature_engagement::events::kBottomToolbarOpened);
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHLongPressToolbarTipFeature));
}
// Verifies that the IPH for Request desktop is triggered after 3 requests of
// the desktop version of a website.
TEST_F(FeatureEngagementTest, TestRequestDesktopTip) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHDefaultSiteViewFeature,
DefaultSiteViewTipParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Request the desktop version of a website, this should not trigger the tip.
tracker->NotifyEvent(feature_engagement::events::kDesktopVersionRequested);
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHDefaultSiteViewFeature));
// Second time, still no tip.
tracker->NotifyEvent(feature_engagement::events::kDesktopVersionRequested);
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHDefaultSiteViewFeature));
// Third time, this should trigger the tip.
tracker->NotifyEvent(feature_engagement::events::kDesktopVersionRequested);
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHDefaultSiteViewFeature));
tracker->Dismissed(feature_engagement::kIPHDefaultSiteViewFeature);
// Fourth time, the tip should no longer trigger.
tracker->NotifyEvent(feature_engagement::events::kDesktopVersionRequested);
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHDefaultSiteViewFeature));
}
// Verifies that the IPH for Request desktop is not triggered if the user
// interacted with the default page mode.
TEST_F(FeatureEngagementTest,
TestRequestDesktopTipAfterChangingDefaultPageMode) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHDefaultSiteViewFeature,
DefaultSiteViewTipParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Interact with the default page mode.
tracker->NotifyEvent(feature_engagement::events::kDefaultSiteViewUsed);
// Request the desktop version of a website, this should not trigger the tip.
tracker->NotifyEvent(feature_engagement::events::kDesktopVersionRequested);
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHDefaultSiteViewFeature));
// Second time, still no tip.
tracker->NotifyEvent(feature_engagement::events::kDesktopVersionRequested);
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHDefaultSiteViewFeature));
// Third time, the tip should still not be shown.
tracker->NotifyEvent(feature_engagement::events::kDesktopVersionRequested);
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHDefaultSiteViewFeature));
}
// Verifies that the IPH for Pinned tab triggers after pinning a tab from
// the overflow menu.
TEST_F(FeatureEngagementTest, TestPinTabFromOverflowMenu) {
feature_engagement::test::ScopedIphFeatureList list;
list.InitAndEnableFeaturesWithParameters(
{{feature_engagement::kIPHTabPinnedFeature, TabPinnedTipParams()}});
std::unique_ptr<feature_engagement::Tracker> tracker =
feature_engagement::CreateTestTracker();
// Make sure tracker is initialized.
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
run_loop_.Run();
// Check that the badge is initially displayed.
EXPECT_TRUE(
tracker->ShouldTriggerHelpUI(feature_engagement::kIPHTabPinnedFeature));
tracker->Dismissed(feature_engagement::kIPHTabPinnedFeature);
// Check that the badge is not displayed a second time.
EXPECT_FALSE(
tracker->ShouldTriggerHelpUI(feature_engagement::kIPHTabPinnedFeature));
}