chromium/chrome/browser/ui/autofill/autofill_context_menu_manager_browsertest.cc

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

#include "chrome/browser/ui/autofill/autofill_context_menu_manager.h"

#include <array>
#include <memory>
#include <optional>
#include <string>

#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/notreached.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/run_until.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/autofill/autofill_uitest_util.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/password_manager/account_password_store_factory.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/password_manager/password_manager_uitest_util.h"
#include "chrome/browser/password_manager/passwords_navigation_observer.h"
#include "chrome/browser/password_manager/profile_password_store_factory.h"
#include "chrome/browser/plus_addresses/plus_address_service_factory.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
#include "chrome/browser/signin/signin_browser_test_base.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/ui/autofill/address_bubbles_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/content/browser/test_autofill_client_injector.h"
#include "components/autofill/content/browser/test_autofill_driver_injector.h"
#include "components/autofill/content/browser/test_content_autofill_client.h"
#include "components/autofill/core/browser/address_data_manager.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
#include "components/autofill/core/browser/metrics/address_save_metrics.h"
#include "components/autofill/core/browser/metrics/manual_fallback_metrics.h"
#include "components/autofill/core/browser/payments_data_manager.h"
#include "components/autofill/core/browser/payments_data_manager_test_api.h"
#include "components/autofill/core/browser/personal_data_manager_test_utils.h"
#include "components/autofill/core/browser/test_autofill_manager_waiter.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_test_api.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill_prediction_improvements/core/browser/autofill_prediction_improvements_features.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/manage_passwords_referrer.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_store/password_store_interface.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/plus_addresses/blocked_facets.pb.h"
#include "components/plus_addresses/features.h"
#include "components/plus_addresses/plus_address_blocklist_data.h"
#include "components/plus_addresses/plus_address_service.h"
#include "components/plus_addresses/plus_address_test_utils.h"
#include "components/plus_addresses/plus_address_types.h"
#include "components/signin/public/base/consent_level.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/base/features.h"
#include "components/sync/test/test_sync_service.h"
#include "components/sync/test/test_sync_user_settings.h"
#include "components/user_manager/user_names.h"
#include "components/variations/service/variations_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace autofill {

namespace {

ElementsAre;
IsEmpty;
Not;
Property;

ACTION_P(QuitMessageLoop, loop) {}

// Checks if the context menu model contains any entries with
// address/payments/plus address manual fallback labels or command ids. `arg`
// must be of type `ui::SimpleMenuModel`.
MATCHER(ContainsAnyAddressPaymentsOrPlusAddressFallbackEntries, "") {}

// Checks if the context menu model contains any entries with plus address
// manual fallback labels or command ids. `arg` must be of type
// `ui::SimpleMenuModel`.
MATCHER(ContainsAnyPlusAddressFallbackEntries, "") {}

// Checks if the context menu model contains the address manual fallback
// entries with correct UI strings. `arg` must be of type `ui::SimpleMenuModel`.
MATCHER(OnlyAddressFallbackAdded, "") {}

// Checks if the context menu model contains the prediction improvement
// entry with correct UI strings. `arg` must be of type `ui::SimpleMenuModel`.
MATCHER(ContainsPredictionImprovementsEntry, "") {}

// Checks if the context menu model contains the plus address manual fallback
// entries with correct UI strings. `arg` must be of type `ui::SimpleMenuModel`.
MATCHER(PlusAddressFallbackAdded, "") {}

// Checks if the context menu model contains the address and payments manual
// fallback entries with correct UI strings. `arg` must be of type
// `ui::SimpleMenuModel`.
MATCHER(AddressAndPaymentsFallbacksAdded, "") {}

// Checks if the context menu model contains the passwords manual fallback
// entries with correct UI strings. `arg` must be of type `ui::SimpleMenuModel`,
// `has_passwords_saved` and `is_password_generation_enabled_for_current_field`
// must be bool. `has_passwords_saved` is true if the user has any account or
// profile passwords stored. `is_password_generation_enabled_for_current_field`
// is true if the password generation feature is enabled for this user (note
// that some non-syncing users can also generate passwords, in special
// conditions) and for the current field.
MATCHER_P2(OnlyPasswordsFallbackAdded,
           has_passwords_saved,
           is_password_generation_enabled_for_current_field,
           "") {}

// Generates a ContextMenuParams for the Autofill context menu options.
content::ContextMenuParams CreateContextMenuParams(
    std::optional<autofill::FormRendererId> form_renderer_id = std::nullopt,
    autofill::FieldRendererId field_render_id = autofill::FieldRendererId(0),
    blink::mojom::FormControlType form_control_type =
        blink::mojom::FormControlType::kInputText) {}

class MockAutofillDriver : public ContentAutofillDriver {};

}  // namespace

// TODO(crbug.com/40286010): Simplify test setup.
class BaseAutofillContextMenuManagerTest : public InProcessBrowserTest {};

class AutocompleteUnrecognizedFieldsTest
    : public BaseAutofillContextMenuManagerTest {};

// Tests that when triggering the context menu on an unclassified field, the
// fallback entry is not part of the menu.
IN_PROC_BROWSER_TEST_F(AutocompleteUnrecognizedFieldsTest,
                       UnclassifiedFormShown_FallbackOptionsNotPresent) {}

// Tests that when triggering the context menu on an ac=unrecognized field, the
// fallback entry is not part of the menu if the user has no AutofillProfiles
// stored.
IN_PROC_BROWSER_TEST_F(
    AutocompleteUnrecognizedFieldsTest,
    AutocompleteUnrecognizedFormShown_NoAutofillProfiles_FallbackOptionsNotPresent) {}

// Tests that when triggering the context menu on an ac=unrecognized field, the
// fallback entry is not part of the menu if there's no suitable AutofillProfile
// data to fill in.
IN_PROC_BROWSER_TEST_F(
    AutocompleteUnrecognizedFieldsTest,
    AutocompleteUnrecognizedFormShown_NoSuitableData_FallbackOptionsNotPresent) {}

// Tests that when triggering the context menu on a classified field that
// has a profile, the fallback entry is not part of the menu if Autofill is
// disabled.
IN_PROC_BROWSER_TEST_F(
    AutocompleteUnrecognizedFieldsTest,
    AutocompleteUnrecognizedFormShown_AutofillDisabled_FallbackOptionsNotPresent) {}

// Tests that when triggering the context menu on a classified field, the
// fallback entry is part of the menu.
IN_PROC_BROWSER_TEST_F(AutocompleteUnrecognizedFieldsTest,
                       ClassifiedFormShown_FallbackOptionsNotPresent) {}

// Tests that when triggering the context menu on an ac=unrecognized field, the
// fallback entry is part of the menu.
IN_PROC_BROWSER_TEST_F(
    AutocompleteUnrecognizedFieldsTest,
    AutocompleteUnrecognizedFormShown_FallbackOptionsPresent) {}

// Tests that when the fallback entry for ac=unrecognized fields is selected,
// suggestions are triggered with suggestion trigger source
// `kManualFallbackAddress`.
IN_PROC_BROWSER_TEST_F(AutocompleteUnrecognizedFieldsTest,
                       AutocompleteUnrecognizedFallback_TriggerSuggestions) {}

class UnclassifiedFieldsTest : public BaseAutofillContextMenuManagerTest {};

// Tests that when triggering the context menu on an unclassified form the
// address manual fallback is added even if the user has no profile stored.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       NoUserData_AddressManualFallbackPresent) {}

// Tests that when triggering the context menu on an unclassified form, address
// manual fallback entries are not added when Autofill is disabled, even if the
// user has address data stored.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       HasAddressData_AddressManualFallbackAdded) {}

// Tests that when triggering the context menu on an unclassified form, address
// manual fallback entries are not added when Autofill is disabled, even if user
// has address data stored.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       AutofillDisabled_FallbackOptionsNotPresent) {}

// Tests that when triggering the context menu on an unclassified form the
// address manual fallback is not added in incognito mode.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       NoUserData_IncognitoMode_FallbackOptionsNotPresent) {}

// Tests that even in incognito mode, when triggering the context menu on an
// unclassified form, address manual fallback entries are added when the user
// has address data stored.
IN_PROC_BROWSER_TEST_F(
    UnclassifiedFieldsTest,
    HasAddressData_IncognitoMode_AddressManualFallbackAdded) {}

// Tests that when triggering the context menu on an unclassified form, payments
// manual fallback entries are added when the user has credit card data stored.
// Note that the address manual fallback option is always present, unless the
// user is in incognito mode.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       HasCreditCardData_PaymentsManualFallbackAdded) {}

// Tests if the prediction improvements entry is not added based on
// `ShouldProvidePredictionImprovements()` returning `false`.
class PredictionImprovementsDisabledTest
    : public BaseAutofillContextMenuManagerTest {};

// Tests that when triggering the context menu on any form field, the improved
// predictions fallback is not added when the feature is disabled.
IN_PROC_BROWSER_TEST_F(PredictionImprovementsDisabledTest,
                       PredictionImprovementsEntryNotAdded) {}

// Tests if the prediction improvements entry is added based on
// `ShouldProvidePredictionImprovements()` returning `true`.
class PredictionImprovementsEnabledTest
    : public BaseAutofillContextMenuManagerTest {};

// Tests that when triggering the context menu on any form field, the improved
// prediction entry point is added.
IN_PROC_BROWSER_TEST_F(PredictionImprovementsEnabledTest,
                       PredictionImprovementsEntryAdded) {}

// Tests that selecting the improved predictions triggers the right command.
IN_PROC_BROWSER_TEST_F(PredictionImprovementsEnabledTest,
                       ActionTriggersSuggestions) {}

// Tests that when triggering the context menu on an unclassified form, payments
// manual fallback entries are NOT added if Autofill for payments is disabled.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       PaymentsDisabled_PaymentsManualFallbackNotAdded) {}

// Tests that when triggering the context menu on an unclassified form, the
// fallback entry is part of the menu.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       UnclassifiedFormShown_ManualFallbacksPresent) {}

// Tests that when triggering the context menu on an autocomplete unrecognized
// field, the fallback entry is part of the menu.
IN_PROC_BROWSER_TEST_F(
    UnclassifiedFieldsTest,
    AutocompleteUnrecognizedFieldShown_ManualFallbacksPresent) {}

// Tests that when triggering the context menu on a classified form, the
// fallback entry is part of the menu.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       ClassifiedFormShown_ManualFallbacksPresent) {}

// Tests that when the address manual fallback entry for the unclassified fields
// is selected, suggestions are triggered.
IN_PROC_BROWSER_TEST_F(
    UnclassifiedFieldsTest,
    UnclassifiedFormShown_AddressFallbackTriggersSuggestion) {}

class AddNewAddressBubbleTest : public UnclassifiedFieldsTest {};

// Tests that when the address manual fallback entry is selected and there are
// no saved profiles, the "Add new address" bubble is triggered.
IN_PROC_BROWSER_TEST_F(
    AddNewAddressBubbleTest,
    UnclassifiedFormShown_AddressFallbackTriggersAddNewAddressBubble) {}

// Tests that the "Autofill.ManualFallback.AddNewAddressPromptShown" metric is
// sent when the user accepts the prompt and saves an address via the editor and
// the manual fallback suggestions are triggered.
IN_PROC_BROWSER_TEST_F(AddNewAddressBubbleTest,
                       UnclassifiedFormShown_AddAddressSave) {}

// Tests that the "Autofill.ManualFallback.AddNewAddressPromptShown" metric is
// sent when the user declines the prompt.
IN_PROC_BROWSER_TEST_F(AddNewAddressBubbleTest,
                       UnclassifiedFormShown_AddAddressMetricsAreSentOnCancel) {}

// Tests that when the payments manual fallback entry for the unclassified
// fields is selected, suggestions are triggered with correct field global id
// and suggestions trigger source.
IN_PROC_BROWSER_TEST_F(UnclassifiedFieldsTest,
                       UnclassifiedFormShown_PaymentsFallbackTriggersFallback) {}

class PasswordsFallbackTest : public BaseAutofillContextMenuManagerTest {};

IN_PROC_BROWSER_TEST_F(
    PasswordsFallbackTest,
    PasswordGenerationEnabled_NoPasswordsSaved_ManualFallbackAddedWithGeneratePasswordOptionAndImportPasswordsOption) {}

IN_PROC_BROWSER_TEST_F(
    PasswordsFallbackTest,
    PasswordGenerationDisabled_NoPasswordsSaved_ManualFallbackAddedWithImportPasswordsOption) {}

IN_PROC_BROWSER_TEST_F(
    PasswordsFallbackTest,
    PasswordGenerationEnabled_NonPasswordField_NoPasswordsSaved_ManualFallbackAddedWithImportPasswordsOptionAndWithoutGeneratePasswordOption) {}

IN_PROC_BROWSER_TEST_F(PasswordsFallbackTest,
                       SelectPasswordTriggersSuggestions) {}

IN_PROC_BROWSER_TEST_F(
    PasswordsFallbackTest,
    ImportPasswordsTriggersOpeningPaswordManagerTabAndRecordsMetrics) {}

class PasswordsFallbackWithUIInteractionsTest
    : public BaseAutofillContextMenuManagerTest {};

IN_PROC_BROWSER_TEST_F(
    PasswordsFallbackWithUIInteractionsTest,
    SuggestPasswordTriggersPasswordGenerationAndRecordsMetrics) {}

enum class PasswordDatabaseEntryType {};

// Not all password database entries are autofillable. This tests fixture goes
// through all relevant categories of password database entries: normal
// credentials, blocklisted entries, federated credentials and username-only
// credentials. Only the first category is autofillable.
// The tests in this fixture test that the "Select password" entry is displayed
// if and only if they have at least one normal credential in the password
// database.
class PasswordsFallbackWithPasswordDatabaseEntriesTest
    : public PasswordsFallbackTest,
      public testing::WithParamInterface<
          std::tuple<bool, PasswordDatabaseEntryType>> {};

IN_PROC_BROWSER_TEST_P(
    PasswordsFallbackWithPasswordDatabaseEntriesTest,
    PasswordGenerationEnabled_HasPasswordDatabaseEntries_ManualFallbackAddedWithGeneratePasswordOption) {}

IN_PROC_BROWSER_TEST_P(
    PasswordsFallbackWithPasswordDatabaseEntriesTest,
    PasswordGenerationDisabled_HasPasswordDatabaseEntries_ManualFallbackAddedWithoutGeneratePasswordOption) {}

IN_PROC_BROWSER_TEST_P(
    PasswordsFallbackWithPasswordDatabaseEntriesTest,
    PasswordGenerationEnabled_NonPasswordField_HasPasswordDatabaseEntries_ManualFallbackAddedWithoutGeneratePasswordOption) {}

INSTANTIATE_TEST_SUITE_P();

class PasswordsFallbackWithGuestProfileTest : public PasswordsFallbackTest {};

// When filling is disabled (for example in guest profiles), manual fallback
// should not be offered.
IN_PROC_BROWSER_TEST_F(PasswordsFallbackWithGuestProfileTest,
                       NoManualFallback) {}

// Test parameter data for asserting metrics emission when triggering Autofill
// via manual fallback.
struct ManualFallbackMetricsTestParams {};

// Test fixture that covers metrics emitted when Autofill is triggered via the
// context menu.
class ManualFallbackMetricsTest
    : public BaseAutofillContextMenuManagerTest,
      public ::testing::WithParamInterface<ManualFallbackMetricsTestParams> {};

IN_PROC_BROWSER_TEST_P(ManualFallbackMetricsTest,
                       EmitExplicitlyTriggeredMetric) {}

INSTANTIATE_TEST_SUITE_P();

class PlusAddressContextMenuManagerTest
    : public SigninBrowserTestBaseT<BaseAutofillContextMenuManagerTest> {};

// Tests that Plus Address fallbacks are added to unclassified forms.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest, UnclassifiedForm) {}

// Tests that Plus Address fallbacks are added to classified forms.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest, ClassifiedForm) {}

// Tests that no Plus Address fallbacks are shown on password fields.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest, PasswordForm) {}

// Tests that Plus Address fallbacks are not added in incognito mode if the user
// does not have a Plus Address for the domain.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest,
                       IncognitoModeWithoutPlusAddress) {}

// Tests that Plus Address fallbacks are added in incognito mode if the user
// has a Plus Address for the domain.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest,
                       IncognitoModeWithPlusAddress) {}

// Tests that no Plus Address fallbacks are added on excluded domains.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest, ExcludedDomain) {}

// Tests that Plus Address fallbacks are added on non-excluded domains.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest, NonExcludedDomain) {}

// Tests that selecting the Plus Address manual fallback entry results in
// triggering suggestions with correct field global id and trigger source.
IN_PROC_BROWSER_TEST_F(PlusAddressContextMenuManagerTest,
                       ActionTriggersSuggestions) {}

}  // namespace autofill