chromium/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragmentTest.java

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

package org.chromium.chrome.browser.autofill.settings;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withText;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.quality.Strictness;

import org.chromium.base.BuildInfo;
import org.chromium.base.Callback;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Features;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.base.test.util.HistogramWatcher;
import org.chromium.base.test.util.JniMocker;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.autofill.PersonalDataManager.Iban;
import org.chromium.chrome.browser.device_reauth.ReauthenticatorBridge;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.chrome.browser.settings.SettingsActivity;
import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.R;
import org.chromium.components.autofill.IbanRecordType;
import org.chromium.components.autofill.MandatoryReauthAuthenticationFlowEvent;
import org.chromium.components.autofill.VirtualCardEnrollmentState;
import org.chromium.components.autofill.payments.BankAccount;
import org.chromium.components.autofill.payments.PaymentInstrument;
import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
import org.chromium.components.policy.test.annotations.Policies;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.ui.test.util.DeviceRestriction;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeoutException;

/** Instrumentation tests for AutofillPaymentMethodsFragment. */
@RunWith(ChromeJUnit4ClassRunner.class)
// TODO(crbug.com/344661357): Failing when batched, batch this again.
public class AutofillPaymentMethodsFragmentTest {
    @Rule public final AutofillTestRule rule = new AutofillTestRule();

    @Rule
    public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.LENIENT);

    @Rule
    public final SettingsActivityTestRule<AutofillPaymentMethodsFragment>
            mSettingsActivityTestRule =
                    new SettingsActivityTestRule<>(AutofillPaymentMethodsFragment.class);

    @Rule public JniMocker mMocker = new JniMocker();

    @Mock private ReauthenticatorBridge mReauthenticatorMock;
    @Mock private AutofillPaymentMethodsDelegate.Natives mNativeMock;

    // Card Issuer values that map to the browser CreditCard.Issuer enum.
    private static final int CARD_ISSUER_UNKNOWN = 0;
    private static final long NATIVE_AUTOFILL_PAYMENTS_METHODS_DELEGATE = 100L;
    private static final List<String> CARD_ISSUER_NETWORKS = Arrays.asList("visa", "mastercard");

    private static final CreditCard SAMPLE_CARD_VISA =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "4444333322221111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "");
    private static final CreditCard SAMPLE_CARD_MASTERCARD =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "5454545454545454",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "12",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "mastercard",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "");
    private static final CreditCard SAMPLE_LOCAL_CARD =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ true,
                    /* name= */ "John Doe",
                    /* number= */ "4111111111111111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "");
    private static final CreditCard SAMPLE_VIRTUAL_CARD_UNENROLLED =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ false,
                    /* isVirtual= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "4444333322221111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "",
                    /* instrumentId= */ 0,
                    /* cardLabel= */ "",
                    /* nickname= */ "",
                    /* cardArtUrl= */ null,
                    /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState
                            .UNENROLLED_AND_ELIGIBLE,
                    /* productDescription= */ "",
                    /* cardNameForAutofillDisplay= */ "",
                    /* obfuscatedLastFourDigits= */ "",
                    /* cvc= */ "");
    private static final CreditCard SAMPLE_VIRTUAL_CARD_ENROLLED =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ false,
                    /* isVirtual= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "4444333322221111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "",
                    /* instrumentId= */ 0,
                    /* cardLabel= */ "",
                    /* nickname= */ "",
                    /* cardArtUrl= */ null,
                    /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState.ENROLLED,
                    /* productDescription= */ "",
                    /* cardNameForAutofillDisplay= */ "",
                    /* obfuscatedLastFourDigits= */ "",
                    /* cvc= */ "");
    private static final CreditCard SAMPLE_CARD_WITH_CVC =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ false,
                    /* isVirtual= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "4444333322221111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "",
                    /* instrumentId= */ 0,
                    /* cardLabel= */ "",
                    /* nickname= */ "",
                    /* cardArtUrl= */ null,
                    /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState
                            .UNENROLLED_AND_ELIGIBLE,
                    /* productDescription= */ "",
                    /* cardNameForAutofillDisplay= */ "",
                    /* obfuscatedLastFourDigits= */ "",
                    /* cvc= */ "123");
    private static final BankAccount PIX_BANK_ACCOUNT =
            new BankAccount.Builder()
                    .setPaymentInstrument(
                            new PaymentInstrument.Builder()
                                    .setInstrumentId(100L)
                                    .setNickname("nickname")
                                    .setSupportedPaymentRails(new int[] {1})
                                    .build())
                    .setBankName("bank_name")
                    .setAccountNumberSuffix("account_number_suffix")
                    .build();

    private static final Iban VALID_BELGIUM_IBAN =
            new Iban.Builder()
                    .setLabel("")
                    .setNickname("My IBAN")
                    .setRecordType(IbanRecordType.UNKNOWN)
                    .setValue("BE71096123456769")
                    .build();
    private static final Iban VALID_RUSSIA_IBAN =
            new Iban.Builder()
                    .setLabel("")
                    .setNickname("")
                    .setRecordType(IbanRecordType.UNKNOWN)
                    .setValue("RU0204452560040702810412345678901")
                    .build();

    private AutofillTestHelper mAutofillTestHelper;

    @Before
    public void setUp() {
        mAutofillTestHelper = new AutofillTestHelper();
        ReauthenticatorBridge.setInstanceForTesting(mReauthenticatorMock);
    }

    @After
    public void tearDown() throws TimeoutException {
        mAutofillTestHelper.clearAllDataForTesting();
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    @DisableFeatures({
        ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE,
        ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN
    })
    public void testTwoCreditCards_displaysTwoServerCards() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_VISA);
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_MASTERCARD);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preferences on the initial screen map to Save and Fill toggle + Mandatory
        // Reauth toggle + 2 Cards + Add Card button + Payment Apps.
        Assert.assertEquals(6, getPreferenceScreen(activity).getPreferenceCount());
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_AUTO)
    @DisableFeatures({
        ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE,
        ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN
    })
    public void testTwoCreditCards_displaysTwoServerCards_mandatoryReauthNotShownOnAutomotive()
            throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_VISA);
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_MASTERCARD);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preferences on the initial screen map to Save and Fill toggle + 2 Cards
        // + Add Card button + Payment Apps.
        Assert.assertEquals(5, getPreferenceScreen(activity).getPreferenceCount());
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_AUTO)
    @DisableFeatures(ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN)
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void
            testTwoCreditCards_displaysTwoServerCards_mandatoryReauthNotShownOnAutomotive_ButCvcStorageEnabled()
                    throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_VISA);
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_MASTERCARD);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preferences on the initial screen map to Save and Fill toggle + CVC
        // storage toggle + 2 Cards + Add Card button + Payment Apps.
        Assert.assertEquals(6, getPreferenceScreen(activity).getPreferenceCount());
    }

    @Test
    @MediumTest
    public void testCreditCardWithoutNickname_displayNetworkAndLastFourAsTitle() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_VISA);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Visa");
        assertThat(title).contains("1111");
    }

    @Test
    @MediumTest
    public void testCreditCardWithNickname_displaysNicknameAndLastFourAsTitle() throws Exception {
        mAutofillTestHelper.addServerCreditCard(
                SAMPLE_CARD_VISA, "Test nickname", CARD_ISSUER_UNKNOWN);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Test nickname");
        assertThat(title).contains("1111");
    }

    @Test
    @MediumTest
    public void testCreditCardWithLongNickname_displaysCompleteNicknameAndLastFourAsTitle()
            throws Exception {
        mAutofillTestHelper.addServerCreditCard(
                SAMPLE_CARD_VISA, "This is a long nickname", CARD_ISSUER_UNKNOWN);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("This is a long nickname");
        assertThat(title).contains("1111");
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_VIRTUAL_CARD_METADATA})
    public void testCreditCardSummary_displaysVirtualCardEnrolledStatus() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_VIRTUAL_CARD_ENROLLED);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String summary = cardPreference.getSummary().toString();
        assertThat(summary)
                .isEqualTo(activity.getString(R.string.autofill_virtual_card_enrolled_text));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_VIRTUAL_CARD_METADATA})
    public void testCreditCardSummary_displaysExpirationDateForUnenrolledCards() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_VIRTUAL_CARD_UNENROLLED);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String summary = cardPreference.getSummary().toString();
        // Verify that the summary (line below the card name and number) contains the expiration
        // date.
        assertThat(summary).contains(String.format("05/%s", AutofillTestHelper.twoDigitNextYear()));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_VIRTUAL_CARD_METADATA})
    public void testCreditCardSummary_displaysExpirationDateForNonVirtualCards() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_VISA);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String summary = cardPreference.getSummary().toString();
        assertThat(summary).contains(String.format("05/%s", AutofillTestHelper.twoDigitNextYear()));
    }

    @Test
    @MediumTest
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_VIRTUAL_CARD_METADATA})
    public void testCreditCardSummary_displaysExpirationDateForVirtualCardsWhenMetadataFlagOff()
            throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_VIRTUAL_CARD_ENROLLED);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String summary = cardPreference.getSummary().toString();
        assertThat(summary).contains(String.format("05/%s", AutofillTestHelper.twoDigitNextYear()));
    }

    @Test
    @MediumTest
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testCreditCardSummary_whenCvcExists_doesNotDisplayCvcSavedMessageWhenCvcFlagOff()
            throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_WITH_CVC);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String summary = cardPreference.getSummary().toString();
        assertThat(summary).contains(String.format("05/%s", AutofillTestHelper.twoDigitNextYear()));
        assertThat(summary)
                .doesNotContain(
                        activity.getString(R.string.autofill_settings_page_cvc_saved_label));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testCreditCardSummary_whenCvcExists_displayCvcSavedMessage() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_WITH_CVC);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getCardPreference(activity);
        String summary = cardPreference.getSummary().toString();
        assertThat(summary)
                .contains(
                        activity.getString(
                                R.string.autofill_settings_page_summary_separated_by_pipe,
                                String.format("05/%s", AutofillTestHelper.twoDigitNextYear()),
                                activity.getString(
                                        R.string.autofill_settings_page_cvc_saved_label)));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testCreditCardSummary_whenCvcDoesNotExist_doesNotDisplayCvcSavedMessage()
            throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_VISA);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getCardPreference(activity);

        String summary = cardPreference.getSummary().toString();
        assertThat(summary).contains(String.format("05/%s", AutofillTestHelper.twoDigitNextYear()));
        assertThat(summary)
                .doesNotContain(
                        activity.getString(R.string.autofill_settings_page_cvc_saved_label));
    }

    @Test
    @SmallTest
    @Policies.Add({@Policies.Item(key = "AutofillCreditCardEnabled", string = "false")})
    public void testAutofillToggleDisabledByPolicy() {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        ChromeSwitchPreference autofillTogglePreference =
                (ChromeSwitchPreference) getPreferenceScreen(activity).getPreference(0);
        Assert.assertFalse(autofillTogglePreference.isEnabled());
    }

    @Test
    @SmallTest
    @Policies.Add({@Policies.Item(key = "AutofillCreditCardEnabled", string = "true")})
    public void testAutofillToggleEnabledByPolicy() {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        ChromeSwitchPreference autofillTogglePreference =
                (ChromeSwitchPreference) getPreferenceScreen(activity).getPreference(0);
        Assert.assertTrue(autofillTogglePreference.isEnabled());
    }

    @Test
    @SmallTest
    public void testAutofillToggleEnabledByDefault() {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        ChromeSwitchPreference autofillTogglePreference =
                (ChromeSwitchPreference) getPreferenceScreen(activity).getPreference(0);
        Assert.assertTrue(autofillTogglePreference.isEnabled());
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    @DisableFeatures({
        ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE,
        ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN
    })
    public void testMandatoryReauthToggle_displayToggle() throws Exception {
        // Simulate the pref was enabled previously, to ensure the toggle value is set
        // correspondingly.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, true);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference on the initial screen map is only Save and Fill toggle +
        // Mandatory Reauth toggle + Add Card button + Payment Apps.
        Assert.assertEquals(4, getPreferenceScreen(activity).getPreferenceCount());
        ChromeSwitchPreference mandatoryReauthPreference =
                (ChromeSwitchPreference) getPreferenceScreen(activity).getPreference(1);
        Assert.assertEquals(
                mandatoryReauthPreference.getTitle(),
                activity.getString(
                        R.string
                                .autofill_settings_page_enable_payment_method_mandatory_reauth_label));
        Assert.assertTrue(mandatoryReauthPreference.isChecked());
        Assert.assertTrue(mandatoryReauthPreference.isEnabled());
    }

    @Test
    @MediumTest
    // Use the policy to simulate AutofillCreditCard is disabled.
    @Policies.Add({@Policies.Item(key = "AutofillCreditCardEnabled", string = "false")})
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testMandatoryReauthToggle_disabledWhenAutofillDisabled() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that Reauth toggle is shown but greyed out when Autofill toggle is disabled.
        Assert.assertFalse(getMandatoryReauthPreference(activity).isEnabled());
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testMandatoryReauthToggle_disabledWhenBothBiometricAndScreenLockAreDisabled()
            throws Exception {
        // Simulate the user can't authenticate with neither biometric nor screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock())
                .thenReturn(false);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Assert.assertFalse(getMandatoryReauthPreference(activity).isEnabled());
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testMandatoryReauthToggle_disabledWithCorrespondingPrefValue() throws Exception {
        // Simulate the pref was enabled previously, to ensure the toggle value is set
        // correspondingly.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, true);
                });
        // Simulate the user can't authenticate with neither biometric nor screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock())
                .thenReturn(false);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Assert.assertFalse(getMandatoryReauthPreference(activity).isEnabled());
        // Also verify that the Reauth toggle is disabled with the corresponding pref value (greyed
        // out whe pref = ON).
        Assert.assertTrue(getMandatoryReauthPreference(activity).isChecked());
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testMandatoryReauthToggle_switchValueOnClicked() throws Exception {
        var optInHistogram =
                HistogramWatcher.newBuilder()
                        .expectIntRecords(
                                AutofillPaymentMethodsFragment.MANDATORY_REAUTH_OPT_IN_HISTOGRAM,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_STARTED,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_SUCCEEDED)
                        .build();
        // Initial state, Reauth pref is disabled by default.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, false);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the Reauth preference is not checked, since Reauth pref is disabled.
        Assert.assertFalse(getMandatoryReauthPreference(activity).isChecked());

        // Simulate the biometric authentication will succeed.
        setUpBiometricAuthenticationResult(/* success= */ true);
        // Simulate click on the Reauth toggle, trying to toggle on. Now Chrome is waiting for OS
        // authentication which should succeed.
        ThreadUtils.runOnUiThreadBlocking(getMandatoryReauthPreference(activity)::performClick);

        verify(mReauthenticatorMock).reauthenticate(notNull());
        // Verify that the Reauth toggle is now checked.
        Assert.assertTrue(getMandatoryReauthPreference(activity).isChecked());
        optInHistogram.assertExpected();
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testMandatoryReauthToggle_stayAtOldValueIfBiometricAuthFails() throws Exception {
        var optOutHistogram =
                HistogramWatcher.newBuilder()
                        .expectIntRecords(
                                AutofillPaymentMethodsFragment.MANDATORY_REAUTH_OPT_OUT_HISTOGRAM,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_STARTED,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_FAILED)
                        .build();
        // Simulate Reauth pref is enabled previously.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, true);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the Reauth preference is checked.
        Assert.assertTrue(getMandatoryReauthPreference(activity).isChecked());

        // Simulate the biometric authentication will fail.
        setUpBiometricAuthenticationResult(/* success= */ false);
        // Simulate click on the Reauth toggle, trying to toggle off. Now Chrome is waiting for OS
        // authentication which should fail.
        ThreadUtils.runOnUiThreadBlocking(getMandatoryReauthPreference(activity)::performClick);

        verify(mReauthenticatorMock).reauthenticate(notNull());
        // Verify that the Reauth toggle is still checked since authentication failed.
        Assert.assertTrue(getMandatoryReauthPreference(activity).isChecked());
        optOutHistogram.assertExpected();
    }

    @Test
    @MediumTest
    public void testMandatoryReauthToggle_noFidoToggle() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference expectedNullFidoToggle =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_FIDO);
        Assert.assertNull(expectedNullFidoToggle);
    }

    @Test
    @MediumTest
    public void testLocalCardEditWithReauth_reauthOnClicked() throws Exception {
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        // Simulate Reauth pref is enabled.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, true);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);
        var editCardReauthHistogram =
                HistogramWatcher.newBuilder()
                        .expectIntRecords(
                                AutofillPaymentMethodsFragment.MANDATORY_REAUTH_EDIT_CARD_HISTOGRAM,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_STARTED,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_SUCCEEDED)
                        .build();

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the Reauth preference is checked on non-automotive devices.
        if (!BuildInfo.getInstance().isAutomotive) {
            Assert.assertTrue(getMandatoryReauthPreference(activity).isChecked());
        }

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Visa");
        assertThat(title).contains("1111");

        // Simulate the biometric authentication will success.
        setUpBiometricAuthenticationResult(/* success= */ true);
        // Simulate click on the local card widget. Now Chrome is waiting for OS authentication.
        ThreadUtils.runOnUiThreadBlocking(cardPreference::performClick);
        // Now mReauthenticatorMock simulate success auth, which will open local card dialog
        // afterwards. Wait for the new dialog to be rendered.
        rule.waitForFragmentToBeShown();

        verify(mReauthenticatorMock).reauthenticate(notNull());
        // Verify that the local card edit dialog was shown.
        Assert.assertTrue(rule.getLastestShownFragment() instanceof AutofillLocalCardEditor);
        editCardReauthHistogram.assertExpected();
    }

    @Test
    @MediumTest
    public void testLocalCardEditWithReauth_reauthOnClickedButFails() throws Exception {
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        // Simulate Reauth pref is enabled.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, true);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);
        var editCardReauthHistogram =
                HistogramWatcher.newBuilder()
                        .expectIntRecords(
                                AutofillPaymentMethodsFragment.MANDATORY_REAUTH_EDIT_CARD_HISTOGRAM,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_STARTED,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_FAILED)
                        .build();

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the Reauth preference is checked on non-automotive devices.
        if (!BuildInfo.getInstance().isAutomotive) {
            Assert.assertTrue(getMandatoryReauthPreference(activity).isChecked());
        }

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Visa");
        assertThat(title).contains("1111");

        // Simulate the biometric authentication will fails.
        setUpBiometricAuthenticationResult(/* success= */ false);
        // Simulate click on the local card widget. Now Chrome is waiting for OS authentication
        // which should fail and hence the payment methods page should still be open.
        ThreadUtils.runOnUiThreadBlocking(cardPreference::performClick);

        verify(mReauthenticatorMock).reauthenticate(notNull());
        // Verify that the local card edit dialog was NOT shown.
        Assert.assertNull(rule.getLastestShownFragment());
        editCardReauthHistogram.assertExpected();
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_AUTO)
    public void testLocalCardEditWithReauth_reauthOnClickedOnAuto() throws Exception {
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        // Simulate Reauth pref is enabled.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, true);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);
        var editCardReauthHistogram =
                HistogramWatcher.newBuilder()
                        .expectIntRecords(
                                AutofillPaymentMethodsFragment.MANDATORY_REAUTH_EDIT_CARD_HISTOGRAM,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_STARTED,
                                MandatoryReauthAuthenticationFlowEvent.FLOW_SUCCEEDED)
                        .build();

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Visa");
        assertThat(title).contains("1111");

        // Simulate the biometric authentication will success.
        setUpBiometricAuthenticationResult(/* success= */ true);
        // Simulate click on the local card widget. Now Chrome is waiting for OS authentication.
        ThreadUtils.runOnUiThreadBlocking(cardPreference::performClick);
        // Now mReauthenticatorMock simulate success auth, which will open local card dialog
        // afterwards. Wait for the new dialog to be rendered.
        rule.waitForFragmentToBeShown();

        verify(mReauthenticatorMock).reauthenticate(notNull());
        // Verify that the local card edit dialog was shown.
        Assert.assertTrue(rule.getLastestShownFragment() instanceof AutofillLocalCardEditor);
        editCardReauthHistogram.assertExpected();
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testLocalCardEditWithReauth_noReauthWhenReauthIsDisabled() throws Exception {
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        // Simulate Reauth pref is disabled.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, false);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the Reauth preference is not checked.
        Assert.assertFalse(getMandatoryReauthPreference(activity).isChecked());
        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Visa");
        assertThat(title).contains("1111");

        // Simulate click on the local card widget.
        ThreadUtils.runOnUiThreadBlocking(cardPreference::performClick);
        // Since reauth pref is disabled, we will directly open local card dialog. Wait for the new
        // dialog to be rendered.
        rule.waitForFragmentToBeShown();

        verify(mReauthenticatorMock, never()).reauthenticate(notNull());
        // Verify that the local card edit dialog was shown.
        Assert.assertTrue(rule.getLastestShownFragment() instanceof AutofillLocalCardEditor);
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testLocalCardEditWithReauth_turnOnReauthAndVerifyReauthOnClick() throws Exception {
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        // Initial state, Reauth pref is disabled by default.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, false);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Simulate the biometric authentication will succeed.
        setUpBiometricAuthenticationResult(/* success= */ true);
        // Simulate click on the Reauth toggle, trying to toggle on. Now Chrome is waiting for OS
        // authentication which should succeed.
        ThreadUtils.runOnUiThreadBlocking(getMandatoryReauthPreference(activity)::performClick);

        // Get the local card's widget.
        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Visa");
        assertThat(title).contains("1111");

        // Simulate click on the local card widget. Now Chrome is waiting for OS authentication.
        ThreadUtils.runOnUiThreadBlocking(cardPreference::performClick);
        // Now mReauthenticatorMock simulate success auth, which will open local card dialog
        // afterwards. Wait for the new dialog to be rendered.
        rule.waitForFragmentToBeShown();

        // Verify there were 2 biometric authentication attempts, once for enabling mandatory
        // reauth, and another time for opening the local card edit page.
        verify(mReauthenticatorMock, times(2)).reauthenticate(notNull());
        // Verify that the local card edit dialog was shown.
        Assert.assertTrue(rule.getLastestShownFragment() instanceof AutofillLocalCardEditor);
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    public void testLocalCardEditWithReauth_turnOffReauthAndVerifyNoReauthOnClick()
            throws Exception {
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        // Simulate Reauth pref is enabled.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService()
                            .setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, true);
                });
        // Simulate the user can authenticate with biometric or screen lock.
        when(mReauthenticatorMock.canUseAuthenticationWithBiometricOrScreenLock()).thenReturn(true);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Simulate the biometric authentication will succeed.
        setUpBiometricAuthenticationResult(/* success= */ true);
        // Simulate click on the Reauth toggle, trying to toggle off. Now Chrome is waiting for OS
        // authentication which should succeed.
        ThreadUtils.runOnUiThreadBlocking(getMandatoryReauthPreference(activity)::performClick);

        // Get the local card's widget.
        Preference cardPreference = getFirstPaymentMethodPreference(activity);
        String title = cardPreference.getTitle().toString();
        assertThat(title).contains("Visa");
        assertThat(title).contains("1111");

        // Simulate click on the local card widget.
        ThreadUtils.runOnUiThreadBlocking(cardPreference::performClick);
        // Since reauth pref is disabled, we will directly open local card dialog. Wait for the new
        // dialog to be rendered.
        rule.waitForFragmentToBeShown();

        // Verify there was only 1 biometric authentication attempt, for disabling mandatory reauth.
        // After disabling, biometric authentication challenge should not be presented to open the
        // local card edit page.
        verify(mReauthenticatorMock, times(1)).reauthenticate(notNull());
        // Verify that the local card edit dialog was shown.
        Assert.assertTrue(rule.getLastestShownFragment() instanceof AutofillLocalCardEditor);
    }

    @Test
    @MediumTest
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testSaveCvcToggle_shown() throws Exception {
        // Initial state, Save Cvc pref is enabled previously.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService().setBoolean(Pref.AUTOFILL_PAYMENT_CVC_STORAGE, true);
                });

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference on the initial screen map is only Save and Fill toggle +
        // Reauth toggle + CVC storage toggle + Add Card button + Payment Apps.
        Assert.assertEquals(5, getPreferenceScreen(activity).getPreferenceCount());

        ChromeSwitchPreference saveCvcToggle =
                findPreferenceByKey(activity, AutofillPaymentMethodsFragment.PREF_SAVE_CVC);
        Assert.assertTrue(saveCvcToggle.isEnabled());
        Assert.assertTrue(saveCvcToggle.isChecked());
    }

    @Test
    @MediumTest
    @DisableFeatures({
        ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE,
        ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN
    })
    public void testSaveCvcToggle_notShownWhenFeatureDisabled() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference on the initial screen map is only Save and Fill toggle +
        // Reauth toggle + Add Card button + Payment Apps.
        Assert.assertEquals(4, getPreferenceScreen(activity).getPreferenceCount());
        Preference expectedNullCvcStorageToggle =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_SAVE_CVC);
        Assert.assertNull(expectedNullCvcStorageToggle);
    }

    @Test
    @MediumTest
    @Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    // Use the policy to simulate AutofillCreditCard is disabled.
    @Policies.Add({@Policies.Item(key = "AutofillCreditCardEnabled", string = "false")})
    public void testSaveCvcToggle_disabledAndOffWhenAutofillDisabled() throws Exception {
        // Initial state, Save Cvc pref is enabled previously.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    getPrefService().setBoolean(Pref.AUTOFILL_PAYMENT_CVC_STORAGE, true);
                });

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that save cvc toggle is shown but greyed out with OFF (even if it's previously
        // turned on) when Autofill toggle is disabled.
        ChromeSwitchPreference saveCvcToggle =
                findPreferenceByKey(activity, AutofillPaymentMethodsFragment.PREF_SAVE_CVC);
        Assert.assertFalse(saveCvcToggle.isEnabled());
        Assert.assertFalse(saveCvcToggle.isChecked());
    }

    @Test
    @MediumTest
    @Features.DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testDeleteSavedCvcsButton_notShownWhenFeatureDisabled() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_WITH_CVC);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference expectedNullDeleteSavedCvcsToggle =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_DELETE_SAVED_CVCS);
        Assert.assertNull(expectedNullDeleteSavedCvcsToggle);
    }

    @Test
    @MediumTest
    @Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testDeleteSavedCvcsButton_whenCvcExists_shown() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_WITH_CVC);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference deleteSavedCvcsToggle =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_DELETE_SAVED_CVCS);
        Assert.assertNotNull(deleteSavedCvcsToggle);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testDeleteSavedCvcsButton_whenCvcDoesNotExist_notShown() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_VISA);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference deleteSavedCvcsToggle =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_DELETE_SAVED_CVCS);
        Assert.assertNull(deleteSavedCvcsToggle);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testDeleteSavedCvcsButton_whenClicked_confirmationDialogIsShown() throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_WITH_CVC);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        Preference deleteSavedCvcsToggle =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_DELETE_SAVED_CVCS);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    deleteSavedCvcsToggle.performClick();
                });

        onView(withText(R.string.autofill_delete_saved_cvcs_confirmation_dialog_title))
                .inRoot(isDialog())
                .check(matches(isDisplayed()));
        onView(withText(R.string.autofill_delete_saved_cvcs_confirmation_dialog_message))
                .check(matches(isDisplayed()));
        onView(
                        withText(
                                R.string
                                        .autofill_delete_saved_cvcs_confirmation_dialog_delete_button_label))
                .check(matches(isDisplayed()));
        onView(withText(android.R.string.cancel)).check(matches(isDisplayed()));
    }

    // TODO(crbug.com/40287195): Test to verify the visibility of the delete saved CVCs button when
    // the AutofillCreditCardEnabled policy is set to false. Currently, Android-x86-rel targets
    // are unable to store credit card information when the policy is set to false.

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testDeleteSavedCvcsConfirmationDialogDeleteButton_whenClicked_deleteCvcs()
            throws Exception {
        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_WITH_CVC);
        mMocker.mock(AutofillPaymentMethodsDelegateJni.TEST_HOOKS, mNativeMock);
        when(mNativeMock.init(any(Profile.class)))
                .thenReturn(NATIVE_AUTOFILL_PAYMENTS_METHODS_DELEGATE);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        Preference deleteSavedCvcsPreference =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_DELETE_SAVED_CVCS);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    deleteSavedCvcsPreference.performClick();
                });
        onView(
                        withText(
                                R.string
                                        .autofill_delete_saved_cvcs_confirmation_dialog_delete_button_label))
                .inRoot(isDialog())
                .perform(click());

        verify(mNativeMock).deleteSavedCvcs(NATIVE_AUTOFILL_PAYMENTS_METHODS_DELEGATE);
    }

    @Test
    @MediumTest
    @DisableFeatures({
        ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE,
    })
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    @Policies.Add({@Policies.Item(key = "AutofillCreditCardEnabled", string = "true")})
    public void testAddIbanButton_shownWhenAutofillEnabled() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference on the initial screen map is only Save and Fill toggle +
        // Reauth toggle + Add Card button + Add IBAN button + Payment Apps.
        Assert.assertEquals(5, getPreferenceScreen(activity).getPreferenceCount());
        Assert.assertNotNull(
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_ADD_IBAN));
    }

    @Test
    @MediumTest
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    @Policies.Add({@Policies.Item(key = "AutofillCreditCardEnabled", string = "true")})
    public void testAddIbanButton_notShownWhenAutofillEnabledButFeatureDisabled() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Assert.assertNull(
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_ADD_IBAN));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    @Policies.Add({@Policies.Item(key = "AutofillCreditCardEnabled", string = "false")})
    public void testAddIbanButton_notShownWhenAutofillDisabled() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Assert.assertNull(
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_ADD_IBAN));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    public void testAddIbanButtonClicked_opensLocalIbanEditor() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Preference addIbanPreference =
                getPreferenceScreen(activity)
                        .findPreference(AutofillPaymentMethodsFragment.PREF_ADD_IBAN);

        // Simulate click on the Add Iban button.
        ThreadUtils.runOnUiThreadBlocking(addIbanPreference::performClick);
        rule.waitForFragmentToBeShown();

        // Verify that the local IBAN editor was opened.
        Assert.assertTrue(rule.getLastestShownFragment() instanceof AutofillLocalIbanEditor);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    public void testAddTwoIbans_displaysTwoLocalIbans() throws Exception {
        mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);
        mAutofillTestHelper.addOrUpdateLocalIban(VALID_RUSSIA_IBAN);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        Assert.assertEquals(
                2, getPreferenceCountWithKey(activity, AutofillPaymentMethodsFragment.PREF_IBAN));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    public void testIbanWithNickname_displaysLabelAndNickname() throws Exception {
        mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        Preference ibanPreference = getFirstPaymentMethodPreference(activity);

        assertThat(ibanPreference.getTitle().toString()).contains("BE");
        assertThat(ibanPreference.getSummary().toString()).isEqualTo("My IBAN");
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN})
    public void testIbanWithoutNickname_displaysLabelOnly() throws Exception {
        mAutofillTestHelper.addOrUpdateLocalIban(VALID_RUSSIA_IBAN);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        Preference ibanPreference = getFirstPaymentMethodPreference(activity);

        assertThat(ibanPreference.getTitle().toString()).contains("RU");
        assertThat(ibanPreference.getSummary().toString()).contains("");
    }

    @Test
    @MediumTest
    @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
    @EnableFeatures({
        ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE,
        ChromeFeatureList.AUTOFILL_ENABLE_LOCAL_IBAN
    })
    public void testAllToggles_mandatoryReauthEnabled_cvcStorageEnabled_localIbanEnabled()
            throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference on the initial screen map is only Save and Fill toggle +
        // Mandatory Reauth toggle + CVC storage toggle + Add Card button + Add IBAN button +
        // Payment Apps.
        Assert.assertEquals(6, getPreferenceScreen(activity).getPreferenceCount());
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SYNCING_OF_PIX_BANK_ACCOUNTS})
    public void pixAccountAvailable_showPayWithPixPreference() throws Exception {
        AutofillTestHelper.addMaskedBankAccount(PIX_BANK_ACCOUNT);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference for 'Pay with Pix' is displayed.
        Preference otherFinancialAccountsPref =
                getPreferenceScreen(activity)
                        .findPreference(
                                AutofillPaymentMethodsFragment.PREF_FINANCIAL_ACCOUNTS_MANAGEMENT);
        assertThat(otherFinancialAccountsPref.getTitle().toString()).contains("Pix");
        // Verify that the second line on the preference has 'Pix' in it.
        assertThat(otherFinancialAccountsPref.getSummary().toString()).contains("Pix");
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SYNCING_OF_PIX_BANK_ACCOUNTS})
    public void pixAccountNotAvailable_doNotShowPayWithPixPreference() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference for 'Manage other financial accounts' is not displayed.
        Preference otherFinancialAccountsPref =
                getPreferenceScreen(activity)
                        .findPreference(
                                AutofillPaymentMethodsFragment.PREF_FINANCIAL_ACCOUNTS_MANAGEMENT);
        assertThat(otherFinancialAccountsPref).isNull();
    }

    @Test
    @MediumTest
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SYNCING_OF_PIX_BANK_ACCOUNTS})
    public void pixAccountAvailable_expOff_doNotShowPayWithPixPreference() throws Exception {
        AutofillTestHelper.addMaskedBankAccount(PIX_BANK_ACCOUNT);

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();

        // Verify that the preference for 'Manage other financial accounts' is not displayed.
        Preference otherFinancialAccountsPref =
                getPreferenceScreen(activity)
                        .findPreference(
                                AutofillPaymentMethodsFragment.PREF_FINANCIAL_ACCOUNTS_MANAGEMENT);
        assertThat(otherFinancialAccountsPref).isNull();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SYNCING_OF_PIX_BANK_ACCOUNTS})
    public void
            testOtherFinancialAccountsPreferenceClicked_opensFinancialAccountsManagementFragment()
                    throws Exception {
        AutofillTestHelper.addMaskedBankAccount(PIX_BANK_ACCOUNT);
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        Preference otherFinancialAccountsPref =
                getPreferenceScreen(activity)
                        .findPreference(
                                AutofillPaymentMethodsFragment.PREF_FINANCIAL_ACCOUNTS_MANAGEMENT);

        // Simulate click on the preference/.
        ThreadUtils.runOnUiThreadBlocking(otherFinancialAccountsPref::performClick);
        rule.waitForFragmentToBeShown();

        // Verify that the financial accounts management fragment is opened.
        Assert.assertTrue(
                rule.getLastestShownFragment() instanceof FinancialAccountsManagementFragment);
    }

    private void setUpBiometricAuthenticationResult(boolean success) {
        // We have to manually invoke the passed-in callback.
        doAnswer(
                        invocation -> {
                            Callback<Boolean> callback = invocation.getArgument(0);
                            callback.onResult(success);
                            return true;
                        })
                .when(mReauthenticatorMock)
                .reauthenticate(notNull());
    }

    private ChromeSwitchPreference getMandatoryReauthPreference(SettingsActivity activity) {
        return findPreferenceByKey(activity, AutofillPaymentMethodsFragment.PREF_MANDATORY_REAUTH);
    }

    /** Find preference by the provided key, fail if no matched preference is found. */
    private ChromeSwitchPreference findPreferenceByKey(SettingsActivity activity, String key) {
        ChromeSwitchPreference preference =
                (ChromeSwitchPreference) getPreferenceScreen(activity).findPreference(key);
        Assert.assertNotNull(preference);
        return preference;
    }

    private static PreferenceScreen getPreferenceScreen(SettingsActivity activity) {
        return ((AutofillPaymentMethodsFragment) activity.getMainFragment()).getPreferenceScreen();
    }

    private static PrefService getPrefService() {
        return UserPrefs.get(ProfileManager.getLastUsedRegularProfile());
    }

    private static Preference getFirstPaymentMethodPreference(SettingsActivity activity) {
        boolean mandatoryReauthToggleShown = !BuildInfo.getInstance().isAutomotive;
        boolean saveCvcToggleShown =
                ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE);
        // The first payment method will come after the general settings for enabling
        // autofill, enabling mandatory re-auth (if available), and enabling CVC storage (if
        // available).
        int firstPaymentMethodIndex =
                1 + (mandatoryReauthToggleShown ? 1 : 0) + (saveCvcToggleShown ? 1 : 0);
        return getPreferenceScreen(activity).getPreference(firstPaymentMethodIndex);
    }

    private Preference getCardPreference(SettingsActivity activity) {
        for (int i = 0; i < getPreferenceScreen(activity).getPreferenceCount(); i++) {
            Preference preference = getPreferenceScreen(activity).getPreference(i);
            if (preference.getTitle() != null
                    && CARD_ISSUER_NETWORKS.stream()
                            .anyMatch(
                                    issuer ->
                                            preference
                                                    .getTitle()
                                                    .toString()
                                                    .toLowerCase()
                                                    .contains(issuer))) {
                return preference;
            }
        }
        Assert.fail("Failed to find the card preference.");
        return null;
    }

    private int getPreferenceCountWithKey(SettingsActivity activity, String preferenceKey) {
        int matchingPreferenceCount = 0;

        for (int i = 0; i < getPreferenceScreen(activity).getPreferenceCount(); i++) {
            Preference preference = getPreferenceScreen(activity).getPreference(i);
            if (preference.getKey() != null && preference.getKey().equals(preferenceKey)) {
                matchingPreferenceCount++;
            }
        }
        return matchingPreferenceCount;
    }
}