#include "chrome/browser/compose/compose_enabling.h"
#include <memory>
#include "base/json/values_util.h"
#include "base/memory/raw_ptr.h"
#include "base/test/gmock_expected_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/types/expected.h"
#include "chrome/browser/about_flags.h"
#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/autofill/core/common/aliases.h"
#include "components/compose/core/browser/compose_features.h"
#include "components/compose/core/browser/config.h"
#include "components/language/core/browser/language_model.h"
#include "components/optimization_guide/core/optimization_guide_proto_util.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/supervised_user/core/common/pref_names.h"
#include "components/supervised_user/core/common/supervised_user_constants.h"
#include "components/translate/core/browser/language_state.h"
#include "components/translate/core/browser/mock_translate_client.h"
#include "components/translate/core/browser/mock_translate_driver.h"
#include "components/translate/core/browser/mock_translate_ranker.h"
#include "components/translate/core/browser/translate_manager.h"
#include "components/unified_consent/pref_names.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::test::ErrorIs;
using base::test::FeatureRef;
using testing::_;
using testing::Return;
namespace {
constexpr char kEmail[] = "example@gmail.com";
constexpr char kExampleURL[] = "https://example.com";
constexpr char kExampleBadURL[] = "chrome://version";
using translate::testing::MockTranslateClient;
class TestLanguageModel : public language::LanguageModel {
std::vector<LanguageDetails> GetLanguages() override {
return {LanguageDetails("en", 1.0)};
}
};
class CustomMockOptimizationGuideKeyedService
: public MockOptimizationGuideKeyedService {
public:
CustomMockOptimizationGuideKeyedService() = default;
~CustomMockOptimizationGuideKeyedService() override = default;
MOCK_METHOD(void,
CanApplyOptimization,
(const GURL& url,
optimization_guide::proto::OptimizationType optimization_type,
optimization_guide::OptimizationGuideDecisionCallback callback));
MOCK_METHOD(
optimization_guide::OptimizationGuideDecision,
CanApplyOptimization,
(const GURL& url,
optimization_guide::proto::OptimizationType optimization_type,
optimization_guide::OptimizationMetadata* optimization_metadata));
MOCK_METHOD(void,
RegisterOptimizationTypes,
(const std::vector<optimization_guide::proto::OptimizationType>&
optimization_types));
MOCK_METHOD(
void,
CanApplyOptimizationOnDemand,
(const std::vector<GURL>& urls,
const base::flat_set<optimization_guide::proto::OptimizationType>&
optimization_types,
optimization_guide::proto::RequestContext request_context,
optimization_guide::OnDemandOptimizationGuideDecisionRepeatingCallback
callback,
std::optional<optimization_guide::proto::RequestContextMetadata>
request_context_metadata));
};
void RegisterMockOptimizationGuideKeyedServiceFactory(
content::BrowserContext* context) {
OptimizationGuideKeyedServiceFactory::GetInstance()->SetTestingFactory(
context, base::BindRepeating([](content::BrowserContext* context)
-> std::unique_ptr<KeyedService> {
return std::make_unique<
testing::NiceMock<CustomMockOptimizationGuideKeyedService>>();
}));
}
}
class ComposeEnablingTest : public BrowserWithTestWindowTest {
public:
ComposeEnablingTest() {
subscription_ =
BrowserContextDependencyManager::GetInstance()
->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
RegisterMockOptimizationGuideKeyedServiceFactory));
}
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
ResetFeaturesAndConfig(
{compose::features::kEnableCompose,
compose::features::kEnableComposeSavedStateNudge,
compose::features::kEnableComposeLanguageBypassForContextMenu,
compose::features::kEnableComposeSavedStateNotification},
{compose::features::kEnableComposeProactiveNudge});
mock_translate_ranker_ =
std::make_unique<translate::testing::MockTranslateRanker>();
mock_translate_client_ =
std::make_unique<MockTranslateClient>(&translate_driver_, nullptr);
translate_manager_ = std::make_unique<translate::TranslateManager>(
mock_translate_client_.get(), mock_translate_ranker_.get(),
language_model_.get());
AddTab(browser(), GURL(kExampleBadURL));
AddTab(browser(), GURL(kExampleURL));
context_menu_params_.is_content_editable_for_autofill = true;
context_menu_params_.frame_origin = GetOrigin();
opt_guide_ = static_cast<
testing::NiceMock<CustomMockOptimizationGuideKeyedService>*>(
OptimizationGuideKeyedServiceFactory::GetForProfile(GetProfile()));
ON_CALL(*opt_guide_,
CanApplyOptimization(
_, optimization_guide::proto::OptimizationType::COMPOSE,
testing::An<optimization_guide::OptimizationMetadata*>()))
.WillByDefault(
[](const GURL& url,
optimization_guide::proto::OptimizationType optimization_type,
optimization_guide::OptimizationMetadata* metadata)
-> optimization_guide::OptimizationGuideDecision {
*metadata = {};
compose::ComposeHintMetadata compose_hint_metadata;
compose_hint_metadata.set_decision(
compose::ComposeHintDecision::COMPOSE_HINT_DECISION_ENABLED);
metadata->set_any_metadata(
optimization_guide::AnyWrapProto(compose_hint_metadata));
return optimization_guide::OptimizationGuideDecision::kTrue;
});
ASSERT_TRUE(opt_guide_);
compose_enabling_ = std::make_unique<ComposeEnabling>(
GetProfile(), identity_test_env_.identity_manager(), &opt_guide());
scoped_skip_user_check_ = ComposeEnabling::ScopedSkipUserCheckForTesting();
scoped_country_override_ = ComposeEnabling::OverrideCountryForTesting("us");
}
void TearDown() override {
compose_enabling_ = nullptr;
opt_guide_ = nullptr;
scoped_feature_list_.Reset();
compose::ResetConfigForTesting();
BrowserWithTestWindowTest::TearDown();
}
void SetProactiveNudgePref(bool pref_value) {
PrefService* prefs = GetProfile()->GetPrefs();
prefs->SetBoolean(prefs::kEnableProactiveNudge, pref_value);
}
void AddDomainToProactiveNudgeDisabledSitesPref() {
ScopedDictPrefUpdate update(GetProfile()->GetPrefs(),
prefs::kProactiveNudgeDisabledSitesWithTime);
update->Set(GetOrigin().Serialize(), base::TimeToValue(base::Time::Now()));
}
void SignIn() {
identity_test_env_.MakePrimaryAccountAvailable(
kEmail, signin::ConsentLevel::kSignin);
identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
}
void ResetFeaturesAndConfig(
const std::vector<FeatureRef>& enabled_features,
const std::vector<FeatureRef>& disabled_features) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
compose::ResetConfigForTesting();
}
CustomMockOptimizationGuideKeyedService& opt_guide() { return *opt_guide_; }
protected:
void SetLanguage(std::string lang) {
translate_manager_->GetLanguageState()->SetSourceLanguage(lang);
}
url::Origin GetOrigin() {
return url::Origin::Create(browser()
->tab_strip_model()
->GetWebContentsAt(0)
->GetLastCommittedURL());
}
content::RenderFrameHost* GetRenderFrameHost() {
return browser()
->tab_strip_model()
->GetWebContentsAt(0)
->GetPrimaryMainFrame();
}
void CheckIsEnabledError(ComposeEnabling* compose_enabling,
compose::ComposeShowStatus error_show_status) {
EXPECT_EQ(compose_enabling->IsEnabled(),
base::unexpected(error_show_status));
}
base::test::ScopedFeatureList scoped_feature_list_;
signin::IdentityTestEnvironment identity_test_env_;
content::ContextMenuParams context_menu_params_;
base::CallbackListSubscription subscription_;
raw_ptr<testing::NiceMock<CustomMockOptimizationGuideKeyedService>>
opt_guide_;
translate::testing::MockTranslateDriver translate_driver_;
std::unique_ptr<translate::testing::MockTranslateClient>
mock_translate_client_;
std::unique_ptr<translate::testing::MockTranslateRanker>
mock_translate_ranker_;
std::unique_ptr<TestLanguageModel> language_model_;
std::unique_ptr<translate::TranslateManager> translate_manager_;
std::unique_ptr<ComposeEnabling> compose_enabling_;
ComposeEnabling::ScopedOverride scoped_skip_user_check_;
ComposeEnabling::ScopedOverride scoped_country_override_;
};
TEST_F(ComposeEnablingTest, EverythingDisabledTest) {
ResetFeaturesAndConfig({}, {compose::features::kEnableCompose});
EXPECT_NE(compose_enabling_->IsEnabled(), base::ok());
}
TEST_F(ComposeEnablingTest, FeatureNotEnabledTest) {
ResetFeaturesAndConfig({}, {compose::features::kEnableCompose});
SignIn();
CheckIsEnabledError(compose_enabling_.get(),
compose::ComposeShowStatus::kComposeFeatureFlagDisabled);
}
TEST_F(ComposeEnablingTest, NotSignedInTest) {
base::HistogramTester histogram_tester;
CheckIsEnabledError(compose_enabling_.get(),
compose::ComposeShowStatus::kSignedOut);
std::string autocomplete_attribute;
auto should_trigger = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL), true);
EXPECT_EQ(should_trigger.error(), compose::ComposeShowStatus::kSignedOut);
}
TEST_F(ComposeEnablingTest, SignedInErrorTest) {
AccountInfo account_info = identity_test_env_.MakePrimaryAccountAvailable(
kEmail, signin::ConsentLevel::kSignin);
identity_test_env_.UpdatePersistentErrorOfRefreshTokenForAccount(
account_info.account_id,
GoogleServiceAuthError(
GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
CheckIsEnabledError(compose_enabling_.get(),
compose::ComposeShowStatus::kSignedOut);
}
TEST_F(ComposeEnablingTest, ComposeEligibleTest) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures({compose::features::kEnableCompose},
{compose::features::kComposeEligible});
SignIn();
CheckIsEnabledError(compose_enabling_.get(),
compose::ComposeShowStatus::kNotComposeEligible);
}
TEST_F(ComposeEnablingTest, EverythingEnabledTest) {
SignIn();
EXPECT_EQ(compose_enabling_->IsEnabled(), base::ok());
}
TEST_F(ComposeEnablingTest, UserNotAllowedTest) {
SignIn();
scoped_skip_user_check_.reset();
EXPECT_THAT(
compose_enabling_->IsEnabled(),
ErrorIs(compose::ComposeShowStatus::kUserNotAllowedByOptimizationGuide));
}
TEST_F(ComposeEnablingTest, StaticMethodEverythingDisabledTest) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures({},
{compose::features::kEnableCompose});
EXPECT_FALSE(ComposeEnabling::IsEnabledForProfile(GetProfile()));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuDisabledTest) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures(
{compose::features::kEnableComposeSavedStateNudge},
{compose::features::kEnableCompose});
EXPECT_FALSE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(),
GetRenderFrameHost(), context_menu_params_));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuLanguageTest) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures(
{compose::features::kEnableCompose},
{compose::features::kEnableComposeLanguageBypassForContextMenu});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
SetLanguage("en");
EXPECT_TRUE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
EXPECT_TRUE(
compose_enabling_->IsPageLanguageSupported(translate_manager_.get()));
SetLanguage("eo");
EXPECT_FALSE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
EXPECT_FALSE(
compose_enabling_->IsPageLanguageSupported(translate_manager_.get()));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuLanguageBypassTest) {
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
SetLanguage("eo");
EXPECT_TRUE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
EXPECT_FALSE(
compose_enabling_->IsPageLanguageSupported(translate_manager_.get()));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuEmptyLanguageTest) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures(
{compose::features::kEnableCompose},
{compose::features::kEnableComposeLanguageBypassForContextMenu});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
SetLanguage("");
EXPECT_TRUE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
EXPECT_TRUE(
compose_enabling_->IsPageLanguageSupported(translate_manager_.get()));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuUndeterminedLangugeTest) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures(
{compose::features::kEnableCompose},
{compose::features::kEnableComposeLanguageBypassForContextMenu});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
SetLanguage("und");
EXPECT_TRUE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
EXPECT_TRUE(
compose_enabling_->IsPageLanguageSupported(translate_manager_.get()));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuFieldTypeTest) {
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
context_menu_params_.is_content_editable_for_autofill = false;
context_menu_params_.form_control_type =
blink::mojom::FormControlType::kInputButton;
EXPECT_FALSE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuIncorrectSchemeTest) {
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
auto* rfh =
browser()->tab_strip_model()->GetWebContentsAt(1)->GetPrimaryMainFrame();
EXPECT_FALSE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), rfh, context_menu_params_));
}
TEST_F(ComposeEnablingTest,
ShouldTriggerContextMenuAllEnabledContentEditableTest) {
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
EXPECT_TRUE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuAllEnabledTextAreaTest) {
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
context_menu_params_.is_content_editable_for_autofill = false;
context_menu_params_.form_control_type =
blink::mojom::FormControlType::kTextArea;
EXPECT_TRUE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
}
TEST_F(ComposeEnablingTest, ShouldTriggerPopupDefaultTest) {
std::string autocomplete_attribute;
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
EXPECT_FALSE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
}
TEST_F(ComposeEnablingTest, ShouldTriggerPopupDisabledTest) {
ResetFeaturesAndConfig({},
{
compose::features::kEnableComposeSavedStateNudge});
std::string autocomplete_attribute;
EXPECT_FALSE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
}
TEST_F(ComposeEnablingTest, ShouldTriggerPopupLanguageTests) {
ResetFeaturesAndConfig({compose::features::kEnableComposeProactiveNudge}, {});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute;
SetLanguage("eo");
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
EXPECT_FALSE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
SetLanguage("en");
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
EXPECT_TRUE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
SetLanguage("und");
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
EXPECT_TRUE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
}
TEST_F(ComposeEnablingTest, ShouldNotTriggerProactivePopupAutocompleteOffTest) {
ResetFeaturesAndConfig({compose::features::kEnableComposeProactiveNudge}, {});
base::HistogramTester histogram_tester;
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute("off");
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
auto should_trigger = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL),
true);
EXPECT_EQ(should_trigger.error(),
compose::ComposeShowStatus::kAutocompleteOff);
}
TEST_F(ComposeEnablingTest, ShouldNotTriggerProactivePopupIfMSBBDisabled) {
ResetFeaturesAndConfig({compose::features::kEnableComposeProactiveNudge}, {});
base::HistogramTester histogram_tester;
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute;
auto should_trigger = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL),
false);
ASSERT_EQ(should_trigger.error(),
compose::ComposeShowStatus::kProactiveNudgeDisabledByMSBB);
EXPECT_TRUE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
}
TEST_F(ComposeEnablingTest, ShouldTriggerPopupWithSavedStateTest) {
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute;
std::vector<std::pair<bool, bool>> tests = {
{true, true}, {true, false}, {false, true}, {false, false}};
for (auto [saved_state_nudge, proactive_nudge] : tests) {
compose::Config& config = compose::GetMutableConfigForTesting();
config.saved_state_nudge_enabled = saved_state_nudge;
config.proactive_nudge_enabled = proactive_nudge;
EXPECT_EQ(
saved_state_nudge,
compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
EXPECT_EQ(proactive_nudge,
compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
}
}
TEST_F(ComposeEnablingTest, ComposeSavedStateNotificationEnabledByDefault) {
std::string autocomplete_attribute;
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kComposeDialogLostFocus));
}
TEST_F(ComposeEnablingTest, SavedStateNotificationWithSavedStateNudgeDisabled) {
ResetFeaturesAndConfig({},
{compose::features::kEnableComposeSavedStateNudge});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute;
EXPECT_FALSE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kComposeDialogLostFocus));
}
TEST_F(ComposeEnablingTest,
ShouldTriggerPopupSavedStateNotificationDisabledTest) {
ResetFeaturesAndConfig(
{compose::features::kEnableComposeProactiveNudge},
{compose::features::kEnableComposeSavedStateNotification});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute;
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
EXPECT_FALSE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kComposeDialogLostFocus));
}
TEST_F(ComposeEnablingTest, ShouldTriggerPopupIncorrectSchemeTest) {
base::HistogramTester histogram_tester;
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
compose::Config& config = compose::GetMutableConfigForTesting();
config.saved_state_nudge_enabled = true;
config.proactive_nudge_enabled = true;
std::string autocomplete_attribute;
auto should_trigger = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
url::Origin(), GURL(kExampleBadURL),
true);
ASSERT_EQ(should_trigger.error(),
compose::ComposeShowStatus::kIncorrectScheme);
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
}
TEST_F(ComposeEnablingTest, ShouldTriggerPopupCrossOrigin) {
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
compose::Config& config = compose::GetMutableConfigForTesting();
config.proactive_nudge_enabled = true;
std::string autocomplete_attribute;
EXPECT_FALSE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), url::Origin(), GURL(kExampleURL),
true)
.has_value());
}
TEST_F(ComposeEnablingTest, ShouldTriggerContextMenuCrossOrigin) {
base::HistogramTester histogram_tester;
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
context_menu_params_.frame_origin = url::Origin();
EXPECT_FALSE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
histogram_tester.ExpectUniqueSample(
compose::kComposeShowStatus,
compose::ComposeShowStatus::kFormFieldInCrossOriginFrame, 1);
}
TEST_F(ComposeEnablingTest, GetOptimizationGuidanceShowNudgeTest) {
optimization_guide::OptimizationMetadata test_metadata;
compose::ComposeHintMetadata compose_hint_metadata;
compose_hint_metadata.set_decision(
compose::ComposeHintDecision::COMPOSE_HINT_DECISION_ENABLED);
test_metadata.set_any_metadata(
optimization_guide::AnyWrapProto(compose_hint_metadata));
EXPECT_CALL(opt_guide(),
CanApplyOptimization(
GURL(kExampleURL),
optimization_guide::proto::OptimizationType::COMPOSE,
::testing::An<optimization_guide::OptimizationMetadata*>()))
.WillRepeatedly(testing::DoAll(
testing::SetArgPointee<2>(test_metadata),
testing::Return(
optimization_guide::OptimizationGuideDecision::kTrue)));
GURL example(kExampleURL);
compose::ComposeHintDecision decision =
compose_enabling_->GetOptimizationGuidanceForUrl(example, GetProfile());
EXPECT_EQ(compose::ComposeHintDecision::COMPOSE_HINT_DECISION_ENABLED,
decision);
}
TEST_F(ComposeEnablingTest, GetOptimizationGuidanceNoFeedbackTest) {
optimization_guide::OptimizationMetadata test_metadata;
compose::ComposeHintMetadata compose_hint_metadata;
compose_hint_metadata.set_decision(
compose::ComposeHintDecision::COMPOSE_HINT_DECISION_ENABLED);
test_metadata.set_any_metadata(
optimization_guide::AnyWrapProto(compose_hint_metadata));
EXPECT_CALL(opt_guide(),
CanApplyOptimization(
GURL(kExampleURL),
optimization_guide::proto::OptimizationType::COMPOSE,
::testing::An<optimization_guide::OptimizationMetadata*>()))
.WillRepeatedly(testing::DoAll(
testing::SetArgPointee<2>(test_metadata),
testing::Return(
optimization_guide::OptimizationGuideDecision::kFalse)));
GURL example(kExampleURL);
compose::ComposeHintDecision decision =
compose_enabling_->GetOptimizationGuidanceForUrl(example, GetProfile());
EXPECT_EQ(compose::ComposeHintDecision::COMPOSE_HINT_DECISION_UNSPECIFIED,
decision);
}
TEST_F(ComposeEnablingTest, GetOptimizationGuidanceNoComposeMetadataTest) {
optimization_guide::OptimizationMetadata test_metadata;
compose::ComposeHintMetadata compose_hint_metadata;
test_metadata.set_any_metadata(
optimization_guide::AnyWrapProto(compose_hint_metadata));
EXPECT_CALL(opt_guide(),
CanApplyOptimization(
GURL(kExampleURL),
optimization_guide::proto::OptimizationType::COMPOSE,
::testing::An<optimization_guide::OptimizationMetadata*>()))
.WillRepeatedly(testing::DoAll(
testing::SetArgPointee<2>(test_metadata),
testing::Return(
optimization_guide::OptimizationGuideDecision::kTrue)));
GURL example(kExampleURL);
compose::ComposeHintDecision decision =
compose_enabling_->GetOptimizationGuidanceForUrl(example, GetProfile());
EXPECT_EQ(compose::ComposeHintDecision::COMPOSE_HINT_DECISION_UNSPECIFIED,
decision);
}
TEST_F(ComposeEnablingTest, ShouldTriggerDisableComposeByPolicyTest) {
ResetFeaturesAndConfig({compose::features::kEnableComposeProactiveNudge}, {});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
context_menu_params_.is_content_editable_for_autofill = false;
context_menu_params_.form_control_type =
blink::mojom::FormControlType::kTextArea;
std::string autocomplete_attribute;
base::HistogramTester histogram_tester;
optimization_guide::OptimizationMetadata test_metadata;
compose::ComposeHintMetadata compose_hint_metadata;
compose_hint_metadata.set_decision(
compose::ComposeHintDecision::COMPOSE_HINT_DECISION_COMPOSE_DISABLED);
test_metadata.set_any_metadata(
optimization_guide::AnyWrapProto(compose_hint_metadata));
EXPECT_CALL(opt_guide(),
CanApplyOptimization(
GURL(kExampleURL),
optimization_guide::proto::OptimizationType::COMPOSE,
::testing::An<optimization_guide::OptimizationMetadata*>()))
.WillRepeatedly(testing::DoAll(
testing::SetArgPointee<2>(test_metadata),
testing::Return(
optimization_guide::OptimizationGuideDecision::kTrue)));
EXPECT_FALSE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
EXPECT_FALSE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
histogram_tester.ExpectUniqueSample(
compose::kComposeShowStatus,
compose::ComposeShowStatus::kPerUrlChecksFailed, 1);
}
TEST_F(ComposeEnablingTest, ShouldTriggerDisableNudgeByPolicy) {
ResetFeaturesAndConfig({compose::features::kEnableComposeProactiveNudge}, {});
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
context_menu_params_.is_content_editable_for_autofill = false;
context_menu_params_.form_control_type =
blink::mojom::FormControlType::kTextArea;
std::string autocomplete_attribute;
optimization_guide::OptimizationMetadata test_metadata;
compose::ComposeHintMetadata compose_hint_metadata;
compose_hint_metadata.set_decision(
compose::ComposeHintDecision::COMPOSE_HINT_DECISION_DISABLE_NUDGE);
test_metadata.set_any_metadata(
optimization_guide::AnyWrapProto(compose_hint_metadata));
EXPECT_CALL(opt_guide(),
CanApplyOptimization(
GURL(kExampleURL),
optimization_guide::proto::OptimizationType::COMPOSE,
::testing::An<optimization_guide::OptimizationMetadata*>()))
.WillRepeatedly(testing::DoAll(
testing::SetArgPointee<2>(test_metadata),
testing::Return(
optimization_guide::OptimizationGuideDecision::kTrue)));
EXPECT_TRUE(compose_enabling_->ShouldTriggerContextMenu(
GetProfile(), translate_manager_.get(), GetRenderFrameHost(),
context_menu_params_));
EXPECT_TRUE(compose_enabling_->ShouldTriggerSavedStatePopup(
autofill::AutofillSuggestionTriggerSource::kTextFieldValueChanged));
EXPECT_FALSE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
compose::GetMutableConfigForTesting()
.proactive_nudge_bypass_optimization_guide = true;
EXPECT_TRUE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
}
TEST_F(ComposeEnablingTest, ProactiveNudgeGlobalPreferenceTest) {
ResetFeaturesAndConfig({compose::features::kEnableComposeProactiveNudge}, {});
base::HistogramTester histogram_tester;
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute;
EXPECT_TRUE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
SetProactiveNudgePref(false);
auto should_trigger = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL),
true);
EXPECT_EQ(should_trigger.error(),
compose::ComposeShowStatus::
kProactiveNudgeDisabledGloballyByUserPreference);
}
TEST_F(ComposeEnablingTest, ProactiveNudgeDisabledSitesPreferenceTest) {
ResetFeaturesAndConfig({compose::features::kEnableComposeProactiveNudge}, {});
base::HistogramTester histogram_tester;
auto scoped_compose_enabled =
ComposeEnabling::ScopedEnableComposeForTesting();
std::string autocomplete_attribute;
ASSERT_TRUE(compose_enabling_
->ShouldTriggerNoStatePopup(
autocomplete_attribute,
true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(),
GetOrigin(), GetOrigin(), GURL(kExampleURL),
true)
.has_value());
AddDomainToProactiveNudgeDisabledSitesPref();
auto should_trigger = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL),
true);
EXPECT_EQ(should_trigger.error(),
compose::ComposeShowStatus::
kProactiveNudgeDisabledForSiteByUserPreference);
}
TEST_F(ComposeEnablingTest, ClientCountryNotInFinchCountryListForCompose) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndEnableFeatureWithParameters(
compose::features::kEnableCompose, {{"enabled_countries", "a, b, c"}});
compose::ResetConfigForTesting();
EXPECT_THAT(compose_enabling_->IsEnabled(),
ErrorIs(compose::ComposeShowStatus::kComposeNotEnabledInCountry));
}
TEST_F(ComposeEnablingTest, ClientCountryUndefinedForCompose) {
scoped_country_override_.reset();
scoped_country_override_ = ComposeEnabling::OverrideCountryForTesting("");
EXPECT_THAT(compose_enabling_->IsEnabled(),
ErrorIs(compose::ComposeShowStatus::kUndefinedCountry));
}
TEST_F(ComposeEnablingTest, AnyAndAllCountriesAllowedForCompose) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndEnableFeatureWithParameters(
compose::features::kEnableCompose, {{"enabled_countries", "*"}});
compose::ResetConfigForTesting();
EXPECT_THAT(compose_enabling_->IsEnabled(),
ErrorIs(compose::ComposeShowStatus::kSignedOut));
scoped_country_override_.reset();
scoped_country_override_ = ComposeEnabling::OverrideCountryForTesting("aa");
EXPECT_THAT(compose_enabling_->IsEnabled(),
ErrorIs(compose::ComposeShowStatus::kSignedOut));
scoped_country_override_.reset();
scoped_country_override_ = ComposeEnabling::OverrideCountryForTesting("");
EXPECT_THAT(compose_enabling_->IsEnabled(),
ErrorIs(compose::ComposeShowStatus::kSignedOut));
}
TEST_F(ComposeEnablingTest,
ClientCountryNotInFinchCountryListForProactiveNudge) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeaturesAndParameters(
{{compose::features::kEnableComposeProactiveNudge,
{{"proactive_nudge_countries", "a, b, c"}}},
{compose::features::kEnableCompose, {{"enabled_countries", "*"}}}},
{});
compose::ResetConfigForTesting();
std::string autocomplete_attribute;
auto no_state_status = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL), true);
EXPECT_THAT(no_state_status,
ErrorIs(compose::ComposeShowStatus::kComposeNotEnabledInCountry));
}
TEST_F(ComposeEnablingTest, ClientCountryUndefinedForProactiveNudge) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndEnableFeatureWithParameters(
compose::features::kEnableCompose, {{"enabled_countries", "*"}});
compose::ResetConfigForTesting();
scoped_country_override_.reset();
scoped_country_override_ = ComposeEnabling::OverrideCountryForTesting("");
std::string autocomplete_attribute;
auto no_state_status = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL), true);
EXPECT_THAT(no_state_status,
ErrorIs(compose::ComposeShowStatus::kUndefinedCountry));
}
TEST_F(ComposeEnablingTest, AnyAndAllCountriesAllowedForProactiveNudge) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeaturesAndParameters(
{{compose::features::kEnableComposeProactiveNudge,
{{"proactive_nudge_countries", "*"}}},
{compose::features::kEnableCompose, {{"enabled_countries", "*"}}}},
{});
compose::ResetConfigForTesting();
std::string autocomplete_attribute;
auto no_state_status = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL), true);
EXPECT_THAT(no_state_status, ErrorIs(compose::ComposeShowStatus::kSignedOut));
scoped_country_override_.reset();
scoped_country_override_ = ComposeEnabling::OverrideCountryForTesting("aa");
no_state_status = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL), true);
EXPECT_THAT(no_state_status, ErrorIs(compose::ComposeShowStatus::kSignedOut));
scoped_country_override_.reset();
scoped_country_override_ = ComposeEnabling::OverrideCountryForTesting("");
no_state_status = compose_enabling_->ShouldTriggerNoStatePopup(
autocomplete_attribute, true, GetProfile(),
GetProfile()->GetPrefs(), translate_manager_.get(), GetOrigin(),
GetOrigin(), GURL(kExampleURL), true);
EXPECT_THAT(no_state_status, ErrorIs(compose::ComposeShowStatus::kSignedOut));
}