chromium/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java

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

package org.chromium.chrome.browser.autofill;

import static org.chromium.base.ThreadUtils.runOnUiThreadBlocking;
import static org.chromium.base.test.util.Criteria.checkThat;
import static org.chromium.base.test.util.CriteriaHelper.pollUiThread;
import static org.chromium.base.test.util.Matchers.containsString;
import static org.chromium.base.test.util.Matchers.is;
import static org.chromium.chrome.browser.autofill.AutofillTestHelper.createCreditCard;
import static org.chromium.chrome.test.R.id.description_line_2;
import static org.chromium.chrome.test.R.id.main_text;
import static org.chromium.chrome.test.R.id.minor_text;
import static org.chromium.chrome.test.R.id.sheet_item_list;

import android.view.View;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.FakeTimeTestRule;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.password_manager.PasswordManagerTestUtilsBridge;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport;
import org.chromium.components.payments.InputProtector;
import org.chromium.content_public.browser.ImeAdapter;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.test.util.DOMUtils;
import org.chromium.content_public.browser.test.util.TestInputMethodManagerWrapper;
import org.chromium.content_public.browser.test.util.WebContentsUtils;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.net.test.ServerCertificate;
import org.chromium.ui.widget.ButtonCompat;

import java.util.concurrent.TimeoutException;

/** Integration tests for the payments bottom sheet. */
@RunWith(ChromeJUnit4ClassRunner.class)
@Batch(Batch.PER_CLASS)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "show-autofill-signatures"})
public class TouchToFillCreditCardTest {
    @Rule
    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();

    @Rule public FakeTimeTestRule mFakeTimeTestRule = new FakeTimeTestRule();

    private static final String FORM_URL =
            "/chrome/test/data/autofill/autofill_creditcard_form.html";
    private static final String CREDIT_CARD_NAME_FIELD_ID = "CREDIT_CARD_NAME_FULL";
    private static final String CREDIT_CARD_NUMBER_FIELD_ID = "CREDIT_CARD_NUMBER";
    private static final String CREDIT_CARD_EXP_MONTH_FIELD_ID = "CREDIT_CARD_EXP_MONTH";
    private static final String CREDIT_CARD_EXP_YEAR_FIELD_ID = "CREDIT_CARD_EXP_4_DIGIT_YEAR";

    private static final String CARD_NAME = "Visa";
    private static final String CARD_NUMBER = "4111111111111111";
    private static final String CARD_EXP_YEAR = "2050";
    private static final String CARD_EXP_2_DIGIT_YEAR = "50";
    private static final String CARD_EXP_MONTH = "05";
    private static final String MASKED_NUMBER = "• • • • 1111";
    private static final String NETWORK_NAME = "visa";
    private static final String CARD_NAME_FOR_AUTOFILL_DISPLAY = "Visa";
    private static final CreditCard VISA =
            createCreditCard(
                    CARD_NAME,
                    CARD_NUMBER,
                    CARD_EXP_MONTH,
                    CARD_EXP_YEAR,
                    /* isLocal= */ true,
                    CARD_NAME_FOR_AUTOFILL_DISPLAY,
                    MASKED_NUMBER,
                    0,
                    NETWORK_NAME);

    private BottomSheetController mBottomSheetController;
    private WebContents mWebContents;
    private EmbeddedTestServer mServer;
    TestInputMethodManagerWrapper mInputMethodWrapper;

    @Before
    public void setup() throws TimeoutException {
        mServer =
                EmbeddedTestServer.createAndStartHTTPSServer(
                        InstrumentationRegistry.getInstrumentation().getContext(),
                        ServerCertificate.CERT_OK);
        mActivityTestRule.startMainActivityWithURL(mServer.getURL(FORM_URL));
        PasswordManagerTestUtilsBridge.disableServerPredictions();
        new AutofillTestHelper().setCreditCard(VISA);

        runOnUiThreadBlocking(
                () -> {
                    mBottomSheetController =
                            BottomSheetControllerProvider.from(
                                    mActivityTestRule.getActivity().getWindowAndroid());
                });
        mWebContents = mActivityTestRule.getWebContents();

        ImeAdapter imeAdapter = WebContentsUtils.getImeAdapter(mWebContents);
        mInputMethodWrapper = TestInputMethodManagerWrapper.create(imeAdapter);
        imeAdapter.setInputMethodManagerWrapper(mInputMethodWrapper);
    }

    @Test
    @MediumTest
    public void testSelectingLocalCard() throws TimeoutException {
        // Focus the field to bring up the touch to fill for credit cards.
        DOMUtils.clickNode(mWebContents, CREDIT_CARD_NUMBER_FIELD_ID);
        // Wait for TTF.
        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
        // Check that keyboard is not displayed.
        pollUiThread(
                () -> {
                    checkThat(mInputMethodWrapper.getShowSoftInputCounter(), is(0));
                });

        // Wait minimum amount of time for input protector.
        mFakeTimeTestRule.advanceMillis(InputProtector.POTENTIALLY_UNINTENDED_INPUT_THRESHOLD);

        // The item with the index 1 in the recycler view is supposed to be the credit card.
        // Click on it to simulate user selection.
        runOnUiThreadBlocking(
                () -> {
                    View creditCardSuggestionItemLayout = getItemsList().getChildAt(1);
                    verifyCardSuggestionIsCorrectlyDisplayed(creditCardSuggestionItemLayout);
                    // Check that continue button is present
                    Assert.assertTrue(getItemsList().getChildAt(2) instanceof ButtonCompat);

                    creditCardSuggestionItemLayout.performClick();
                });
        // Wait until the bottom sheet is closed
        BottomSheetTestSupport.waitForState(mBottomSheetController, SheetState.HIDDEN);

        // Check that the form is filled with the card credentials
        checkThat(DOMUtils.getNodeValue(mWebContents, CREDIT_CARD_NAME_FIELD_ID), is(CARD_NAME));
        checkThat(
                DOMUtils.getNodeValue(mWebContents, CREDIT_CARD_NUMBER_FIELD_ID), is(CARD_NUMBER));
        checkThat(
                DOMUtils.getNodeValue(mWebContents, CREDIT_CARD_EXP_YEAR_FIELD_ID),
                is(CARD_EXP_YEAR));
        checkThat(
                DOMUtils.getNodeValue(mWebContents, CREDIT_CARD_EXP_MONTH_FIELD_ID),
                is(CARD_EXP_MONTH));
    }

    private RecyclerView getItemsList() {
        return mActivityTestRule.getActivity().findViewById(sheet_item_list);
    }

    private void verifyCardSuggestionIsCorrectlyDisplayed(View cardSuggestionItemLayout) {
        TextView mainTextLayout = cardSuggestionItemLayout.findViewById(main_text);
        TextView minorTextLayout = cardSuggestionItemLayout.findViewById(minor_text);
        TextView cardDescLayout = cardSuggestionItemLayout.findViewById(description_line_2);
        // Check that suggestion main text with the card name is displayed
        checkThat(mainTextLayout.getText().toString(), is(CARD_NAME));
        // Check that suggestion minor text with the last four digits of the card are displayed
        checkThat(
                minorTextLayout.getText().toString(),
                containsString(CARD_NUMBER.substring(CARD_NUMBER.length() - 4)));
        // Check that the expiration month and year are present in the card description
        checkThat(cardDescLayout.getText().toString(), containsString(CARD_EXP_MONTH));
        checkThat(cardDescLayout.getText().toString(), containsString(CARD_EXP_2_DIGIT_YEAR));
    }
}