chromium/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java

// Copyright 2016 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.payments;

import androidx.test.filters.MediumTest;

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.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.payments.PaymentRequestTestRule.AppPresence;
import org.chromium.chrome.browser.payments.PaymentRequestTestRule.FactorySpeed;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.R;
import org.chromium.components.autofill.AutofillProfile;

import java.util.ArrayList;
import java.util.concurrent.TimeoutException;

/**
 * A payment integration test for a merchant that requires shipping address to calculate shipping
 * and user that has 5 addresses stored in autofill settings.
 */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class PaymentRequestDynamicShippingMultipleAddressesTest {
    @Rule
    public PaymentRequestTestRule mPaymentRequestTestRule =
            new PaymentRequestTestRule("payment_request_dynamic_shipping_test.html");

    private static final AutofillProfile INCOMPLETE_PROFILE_NO_PHONE =
            AutofillProfile.builder()
                    .setFullName("Bart Simpson")
                    .setCompanyName("Acme Inc.")
                    .setStreetAddress("123 Main")
                    .setRegion("California")
                    .setLocality("Los Angeles")
                    .setPostalCode("90210")
                    .setCountryCode("US")
                    .setEmailAddress("[email protected]")
                    .build();

    private static final AutofillProfile INCOMPLETE_PROFILE_NO_STREET_ADDRESS =
            AutofillProfile.builder()
                    .setFullName("Homer Simpson")
                    .setCompanyName("Acme Inc.")
                    .setRegion("California")
                    .setLocality("Los Angeles")
                    .setPostalCode("90210")
                    .setCountryCode("US")
                    .setPhoneNumber("555 123-4567")
                    .setEmailAddress("[email protected]")
                    .build();

    private static final AutofillProfile COMPLETE_PROFILE =
            AutofillProfile.builder()
                    .setFullName("Lisa Simpson")
                    .setCompanyName("Acme Inc.")
                    .setStreetAddress("123 Main")
                    .setRegion("California")
                    .setLocality("Los Angeles")
                    .setPostalCode("90210")
                    .setCountryCode("US")
                    .setPhoneNumber("555 123-4567")
                    .setEmailAddress("[email protected]")
                    .build();

    private static final AutofillProfile COMPLETE_PROFILE_NON_US_COUNTRY =
            AutofillProfile.builder()
                    .setFullName("Maggie Simpson")
                    .setCompanyName("Acme Inc.")
                    .setStreetAddress("123 Main")
                    .setRegion("California")
                    .setLocality("Los Angeles")
                    .setPostalCode("90210")
                    .setCountryCode("Uzbekistan")
                    .setPhoneNumber("555 123-4567")
                    .setEmailAddress("[email protected]")
                    .build();

    private static final AutofillProfile INCOMPLETE_PROFILE_NO_CITY_NAME =
            AutofillProfile.builder()
                    .setFullName("Marge Simpson")
                    .setCompanyName("Acme Inc.")
                    .setStreetAddress("123 Main")
                    .setRegion("California")
                    .setPostalCode("90210")
                    .setCountryCode("US")
                    .setPhoneNumber("555 123-4567")
                    .setEmailAddress("[email protected]")
                    .build();

    private static final AutofillProfile INCOMPLETE_PROFILE_NO_NAME =
            AutofillProfile.builder()
                    .setCompanyName("Acme Inc.")
                    .setStreetAddress("123 Main")
                    .setRegion("California")
                    .setLocality("Los Angeles")
                    .setPostalCode("90210")
                    .setCountryCode("US")
                    .setPhoneNumber("555 123-4567")
                    .setEmailAddress("[email protected]")
                    .build();

    private static final AutofillProfile INCOMPLETE_PROFILE_NO_NAME_OR_LOCALITY =
            AutofillProfile.builder()
                    .setCompanyName("Acme Inc.")
                    .setStreetAddress("123 Main")
                    .setRegion("California")
                    .setPostalCode("90210")
                    .setCountryCode("US")
                    .setPhoneNumber("555 123-4567")
                    .setEmailAddress("[email protected]")
                    .build();

    // This profile has the same details as INCOMPLETE_PROFILE_NO_PHONE, except it has a different
    // name.
    private static final AutofillProfile INCOMPLETE_PROFILE_NO_PHONE_2 =
            AutofillProfile.builder()
                    .setFullName("John Smith")
                    .setCompanyName("Acme Inc.")
                    .setStreetAddress("123 Main")
                    .setRegion("California")
                    .setLocality("Los Angeles")
                    .setPostalCode("90210")
                    .setCountryCode("US")
                    .setEmailAddress("[email protected]")
                    .build();

    @Before
    public void setUp() throws TimeoutException {
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://bobpay.test", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);
    }

    private void setUpAutofillProfiles(
            AutofillProfile[] profiles, int[] counts, int[] daysSinceLastUsed)
            throws TimeoutException {
        AutofillTestHelper helper = new AutofillTestHelper();

        // Add the profiles.
        ArrayList<String> guids = new ArrayList<>();
        for (int i = 0; i < profiles.length; i++) {
            guids.add(helper.setProfile(profiles[i]));
        }

        // Set up the profile use stats.
        for (int i = 0; i < guids.size(); i++) {
            helper.setProfileUseStatsForTesting(guids.get(i), counts[i], daysSinceLastUsed[i]);
        }
    }

    /**
     * Make sure the address suggestions are in the correct order and that only the top 4
     * suggestions are shown. Complete profiles come first and ordered by frecency. Incomplete
     * profiles are ordered by their completeness score.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    public void testShippingAddressSuggestionOrdering() throws TimeoutException {
        // Create two complete and two incomplete profiles. Values are set so that complete profiles
        // are ordered by frecency, incomplete profiles are sorted by their completeness score.
        AutofillProfile[] profiles = {
            INCOMPLETE_PROFILE_NO_PHONE,
            COMPLETE_PROFILE,
            COMPLETE_PROFILE_NON_US_COUNTRY,
            INCOMPLETE_PROFILE_NO_CITY_NAME
        };
        int[] counts = new int[] {20, 15, 10, 25};
        int[] daysSinceLastUsed = new int[] {5, 5, 5, 5};

        setUpAutofillProfiles(profiles, counts, daysSinceLastUsed);

        mPaymentRequestTestRule.runJavaScriptAndWaitForUIEvent(
                "buyWithMethods([{supportedMethods:'https://bobpay.test'}]);",
                mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickInShippingAddressAndWait(
                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
        Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions());
        int i = 0;
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Lisa Simpson"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Maggie Simpson"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Bart Simpson"));
        // Even though Profile[4] (missing address) has higher frecency than Profile[0] (missing
        // phone number), it ranks lower than Profile[0] since its completeness score is lower.
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Marge Simpson"));
    }

    /** Make sure that equally incomplete profiles are ordered by their frecency. */
    @Test
    @MediumTest
    @Feature({"Payments"})
    public void testEquallyIncompleteSuggestionsOrdering() throws TimeoutException {
        // Create two profiles both with missing phone numbers.
        AutofillProfile[] profiles = {INCOMPLETE_PROFILE_NO_PHONE, INCOMPLETE_PROFILE_NO_PHONE_2};
        int[] counts = new int[] {20, 30};
        int[] daysSinceLastUsed = new int[] {5, 5};

        setUpAutofillProfiles(profiles, counts, daysSinceLastUsed);

        mPaymentRequestTestRule.runJavaScriptAndWaitForUIEvent(
                "buyWithMethods([{supportedMethods:'https://bobpay.test'}]);",
                mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickInShippingAddressAndWait(
                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
        Assert.assertEquals(2, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions());
        int i = 0;
        // Incomplete profile with higher frecency comes first.
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("John Smith"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Bart Simpson"));
    }

    /** Make sure that a maximum of four profiles are shown to the user. */
    @Test
    @MediumTest
    @Feature({"Payments"})
    public void testShippingAddressSuggestionLimit() throws TimeoutException {
        // Create five profiles that can be suggested to the user.
        AutofillProfile[] profiles = {
            INCOMPLETE_PROFILE_NO_PHONE,
            COMPLETE_PROFILE,
            COMPLETE_PROFILE_NON_US_COUNTRY,
            INCOMPLETE_PROFILE_NO_CITY_NAME,
            INCOMPLETE_PROFILE_NO_NAME
        };
        int[] counts = new int[] {20, 15, 10, 5, 2, 1};
        int[] daysSinceLastUsed = new int[] {5, 5, 5, 10, 15};

        setUpAutofillProfiles(profiles, counts, daysSinceLastUsed);

        mPaymentRequestTestRule.runJavaScriptAndWaitForUIEvent(
                "buyWithMethods([{supportedMethods:'https://bobpay.test'}]);",
                mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickInShippingAddressAndWait(
                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
        // Only four profiles should be suggested to the user.
        Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions());
        int i = 0;
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Lisa Simpson"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Maggie Simpson"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Bart Simpson"));
        // Profiles[5] is suggested as the last option since it is missing recipient name and ranks
        // above Profile[4] with missing address.
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i)
                        .contains("Los Angeles"));
        Assert.assertFalse(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i)
                        .contains("Marge Simpson"));
    }

    /** Make sure that only profiles with a street address are suggested to the user. */
    @Test
    @MediumTest
    @Feature({"Payments"})
    public void testShippingAddressSuggestion_OnlyIncludeProfilesWithStreetAddress()
            throws TimeoutException {
        // Create two complete profiles and two incomplete profiles, one of which has no street
        // address.
        AutofillProfile[] profiles = {
            INCOMPLETE_PROFILE_NO_PHONE,
            INCOMPLETE_PROFILE_NO_STREET_ADDRESS,
            COMPLETE_PROFILE,
            COMPLETE_PROFILE_NON_US_COUNTRY
        };
        int[] counts = new int[] {15, 10, 5, 1};
        int[] daysSinceLastUsed = new int[] {5, 5, 5, 10};

        setUpAutofillProfiles(profiles, counts, daysSinceLastUsed);

        mPaymentRequestTestRule.runJavaScriptAndWaitForUIEvent(
                "buyWithMethods([{supportedMethods:'https://bobpay.test'}]);",
                mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickInShippingAddressAndWait(
                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
        // Only 3 profiles should be suggested, the two complete ones and the incomplete one that
        // has a street address.
        Assert.assertEquals(3, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions());
        int i = 0;
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Lisa Simpson"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Maggie Simpson"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Bart Simpson"));
    }

    /**
     * Select a shipping address that the website refuses to accept, which should force the dialog
     * to show an error.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    public void testShippingAddressNotAcceptedByMerchant() throws TimeoutException {
        // Add a profile that is not accepted by the website.
        AutofillProfile[] profiles = {COMPLETE_PROFILE_NON_US_COUNTRY};
        int[] counts = new int[] {5};
        int[] daysSinceLastUsed = new int[] {5};

        setUpAutofillProfiles(profiles, counts, daysSinceLastUsed);

        // Click on the unacceptable shipping address.
        mPaymentRequestTestRule.runJavaScriptAndWaitForUIEvent(
                "buyWithMethods([{supportedMethods:'https://bobpay.test'}]);",
                mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickInShippingAddressAndWait(
                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(0)
                        .contains(COMPLETE_PROFILE_NON_US_COUNTRY.getFullName()));
        mPaymentRequestTestRule.clickOnShippingAddressSuggestionOptionAndWait(
                0, mPaymentRequestTestRule.getSelectionChecked());

        // The string should reflect the error sent from the merchant.
        CharSequence actualString =
                mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0).getLabelText();
        Assert.assertEquals("We do not ship to this address", actualString);
    }

    /**
     * Make sure the information required message has been displayed for incomplete profile
     * correctly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    public void testShippingAddressEditRequiredMessage() throws TimeoutException {
        // Create four incomplete profiles with different missing information. Profiles will be
        // sorted based on their missing fields.
        AutofillProfile[] profiles = {
            INCOMPLETE_PROFILE_NO_PHONE,
            INCOMPLETE_PROFILE_NO_CITY_NAME,
            INCOMPLETE_PROFILE_NO_NAME,
            INCOMPLETE_PROFILE_NO_NAME_OR_LOCALITY,
        };
        int[] counts = new int[] {15, 10, 5, 25};
        int[] daysSinceLastUsed = new int[] {5, 5, 5, 5};

        setUpAutofillProfiles(profiles, counts, daysSinceLastUsed);

        mPaymentRequestTestRule.runJavaScriptAndWaitForUIEvent(
                "buyWithMethods([{supportedMethods:'https://bobpay.test'}]);",
                mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickInShippingAddressAndWait(
                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());

        // Incomplete addresses are sorted by completeness score.
        Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions());
        int i = 0;
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Phone number required"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Name required"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("Enter a valid address"));
        Assert.assertTrue(
                mPaymentRequestTestRule
                        .getShippingAddressSuggestionLabel(i++)
                        .contains("More information required"));
    }
}