1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.chrome.browser.payments;
6 
7 import androidx.test.filters.MediumTest;
8 
9 import org.junit.Assert;
10 import org.junit.ClassRule;
11 import org.junit.Rule;
12 import org.junit.Test;
13 import org.junit.runner.RunWith;
14 
15 import org.chromium.base.metrics.RecordHistogram;
16 import org.chromium.base.test.util.CommandLineFlags;
17 import org.chromium.base.test.util.Feature;
18 import org.chromium.chrome.R;
19 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
20 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
21 import org.chromium.chrome.browser.flags.ChromeSwitches;
22 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.AppPresence;
23 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.FactorySpeed;
24 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
25 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
26 import org.chromium.ui.test.util.DisableAnimationsTestRule;
27 
28 import java.util.ArrayList;
29 import java.util.concurrent.TimeoutException;
30 
31 /**
32  * A payment integration test for a merchant that requests contact details and a user that has
33  * multiple contact detail options.
34  */
35 @RunWith(ChromeJUnit4ClassRunner.class)
36 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
37 public class PaymentRequestMultipleContactDetailsTest implements MainActivityStartCallback {
38     // Disable animations to reduce flakiness.
39     @ClassRule
40     public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
41 
42     @Rule
43     public PaymentRequestTestRule mPaymentRequestTestRule =
44             new PaymentRequestTestRule("payment_request_contact_details_test.html", this);
45 
46     private static final AutofillProfile[] AUTOFILL_PROFILES = {
47             // 0 - Incomplete (no phone) profile.
48             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
49                     "" /* honorific prefix */, "Bart Simpson", "Acme Inc.", "123 Main",
50                     "California", "Los Angeles", "", "90210", "", "US", "", "bart@simpson.com", ""),
51 
52             // 1 - Incomplete (no email) profile.
53             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
54                     "" /* honorific prefix */, "Homer Simpson", "Acme Inc.", "123 Main",
55                     "California", "Los Angeles", "", "90210", "", "US", "555 123-4567", "", ""),
56 
57             // 2 - Complete profile.
58             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
59                     "" /* honorific prefix */, "Lisa Simpson", "Acme Inc.", "123 Main",
60                     "California", "Los Angeles", "", "90210", "", "US", "555 123-4567",
61                     "lisa@simpson.com", ""),
62 
63             // 3 - Complete profile.
64             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
65                     "" /* honorific prefix */, "Maggie Simpson", "Acme Inc.", "123 Main",
66                     "California", "Los Angeles", "", "90210", "", "US", "555 123-4567",
67                     "maggie@simpson.com", ""),
68 
69             // 4 - Incomplete (no phone and email) profile.
70             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
71                     "" /* honorific prefix */, "Marge Simpson", "Acme Inc.", "123 Main",
72                     "California", "Los Angeles", "", "90210", "", "US", "", "", ""),
73 
74             // 5 - Incomplete (no name) profile.
75             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
76                     "" /* honorific prefix */, "", "Acme Inc.", "123 Main", "California",
77                     "Los Angeles", "", "90210", "", "US", "555 123-4567", "marge@simpson.com", ""),
78 
79             // These profiles are used to test the dedupe of subset suggestions. They are based on
80             // The Lisa Simpson profile.
81 
82             // 6 - Same as original, but with no name.
83             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
84                     "" /* honorific prefix */, "" /* name */, "Acme Inc.", "123 Main", "California",
85                     "Los Angeles", "", "90210", "", "US", "555 123-4567", "lisa@simpson.com", ""),
86 
87             // 7 - Same as original, but with no phone.
88             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
89                     "" /* honorific prefix */, "Lisa Simpson", "Acme Inc.", "123 Main",
90                     "California", "Los Angeles", "", "90210", "", "US", "" /* phoneNumber */,
91                     "lisa@simpson.com", ""),
92 
93             // 8 - Same as original, but with no email.
94             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
95                     "" /* honorific prefix */, "Lisa Simpson", "Acme Inc.", "123 Main",
96                     "California", "Los Angeles", "", "90210", "", "US", "555 123-4567",
97                     "" /* emailAddress */, ""),
98 
99             // 9 - Same as original, but with no phone and no email.
100             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
101                     "" /* honorific prefix */, "Lisa Simpson", "Acme Inc.", "123 Main",
102                     "California", "Los Angeles", "", "90210", "", "US", "" /* phoneNumber */,
103                     "" /* emailAddress */, ""),
104 
105             // 10 - Has an email address that is a superset of the original profile's email.
106             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
107                     "" /* honorific prefix */, "Lisa Simpson", "Acme Inc.", "123 Main",
108                     "California", "Los Angeles", "", "90210", "", "US", "555 123-4567",
109                     "fakelisa@simpson.com", ""),
110 
111             // 11 - Has the same name as the original but with no capitalization in the name.
112             new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
113                     "" /* honorific prefix */, "lisa simpson", "Acme Inc.", "123 Main",
114                     "California", "Los Angeles", "", "90210", "", "US", "555 123-4567",
115                     "lisa@simpson.com", ""),
116 
117     };
118 
119     private AutofillProfile[] mProfilesToAdd;
120     private int[] mCountsToSet;
121     private int[] mDatesToSet;
122 
123     @Override
onMainActivityStarted()124     public void onMainActivityStarted() throws TimeoutException {
125         AutofillTestHelper helper = new AutofillTestHelper();
126 
127         // Add the profiles.
128         ArrayList<String> guids = new ArrayList<>();
129         for (int i = 0; i < mProfilesToAdd.length; i++) {
130             guids.add(helper.setProfile(mProfilesToAdd[i]));
131         }
132 
133         // Set up the profile use stats.
134         for (int i = 0; i < guids.size(); i++) {
135             helper.setProfileUseStatsForTesting(guids.get(i), mCountsToSet[i], mDatesToSet[i]);
136         }
137 
138         mPaymentRequestTestRule.addPaymentAppFactory(
139                 AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);
140     }
141 
142     /**
143      * Make sure the contact details suggestions are in the correct order and that only the top 4
144      * are shown. They should be ordered by frecency and complete contact details should be
145      * suggested first.
146      */
147     @Test
148     @MediumTest
149     @Feature({"Payments"})
testContactDetailsSuggestionOrdering()150     public void testContactDetailsSuggestionOrdering() throws TimeoutException {
151         // Set the use stats so that profile[0] has the highest frecency score, profile[1] the
152         // second highest, profile[2] the third lowest, profile[3] the second lowest and profile[4]
153         // the lowest.
154         mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[0], AUTOFILL_PROFILES[1],
155                 AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[3], AUTOFILL_PROFILES[4]};
156         mCountsToSet = new int[] {20, 15, 10, 5, 1};
157         mDatesToSet = new int[] {5000, 5000, 5000, 5000, 1};
158 
159         mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
160         mPaymentRequestTestRule.clickInContactInfoAndWait(
161                 R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
162         Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions());
163         Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com",
164                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0));
165         Assert.assertEquals("Maggie Simpson\n555 123-4567\nmaggie@simpson.com",
166                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(1));
167         Assert.assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required",
168                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(2));
169         Assert.assertEquals("Homer Simpson\n555 123-4567\nEmail required",
170                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(3));
171 
172         // Verify that no record is logged since there is at least one complete suggested contact
173         // details.
174         Assert.assertEquals(0,
175                 RecordHistogram.getHistogramTotalCountForTesting(
176                         "PaymentRequest.MissingContactFields"));
177     }
178 
179     /**
180      * Make sure the information required message has been displayed for incomplete contact details
181      * correctly.
182      */
183     @Test
184     @MediumTest
185     @Feature({"Payments"})
testContactDetailsEditRequiredMessage()186     public void testContactDetailsEditRequiredMessage() throws TimeoutException {
187         mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[0], AUTOFILL_PROFILES[1],
188                 AUTOFILL_PROFILES[4], AUTOFILL_PROFILES[5]};
189         mCountsToSet = new int[] {15, 10, 5, 1};
190         mDatesToSet = new int[] {5000, 5000, 5000, 5000};
191 
192         mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
193         mPaymentRequestTestRule.clickInContactInfoAndWait(
194                 R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
195         Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions());
196         Assert.assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required",
197                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0));
198         Assert.assertEquals("Homer Simpson\n555 123-4567\nEmail required",
199                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(1));
200         Assert.assertEquals("555 123-4567\nmarge@simpson.com\nName required",
201                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(2));
202         Assert.assertEquals("Marge Simpson\nMore information required",
203                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(3));
204 
205         // Verify that the missing fields of the most complete suggestion has been recorded.
206         Assert.assertEquals(1,
207                 RecordHistogram.getHistogramValueCountForTesting(
208                         "PaymentRequest.MissingContactFields", ContactEditor.INVALID_PHONE_NUMBER));
209     }
210 
211     /**
212      * Makes sure that suggestions that are subsets of other fields (empty values) are deduped.
213      */
214     @Test
215     @MediumTest
216     @Feature({"Payments"})
testContactDetailsDedupe_EmptyFields()217     public void testContactDetailsDedupe_EmptyFields() throws TimeoutException {
218         // Add the original profile and a bunch of similar profiles with missing fields.
219         // Make sure the original profile is suggested last, to test that the suggestions are
220         // sorted by completeness.
221         mProfilesToAdd = new AutofillProfile[] {
222                 AUTOFILL_PROFILES[2],
223                 AUTOFILL_PROFILES[6],
224                 AUTOFILL_PROFILES[7],
225                 AUTOFILL_PROFILES[8],
226                 AUTOFILL_PROFILES[9],
227         };
228         mCountsToSet = new int[] {1, 20, 15, 10, 5};
229         mDatesToSet = new int[] {1000, 4000, 3000, 2000, 1000};
230 
231         mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
232         mPaymentRequestTestRule.clickInContactInfoAndWait(
233                 R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
234 
235         // Only the original profile with all the fields should be suggested.
236         Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions());
237         Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com",
238                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0));
239     }
240 
241     /**
242      * Makes sure that suggestions where some fields values are equal but with different case are
243      * deduped.
244      */
245     @Test
246     @MediumTest
247     @Feature({"Payments"})
testContactDetailsDedupe_Capitalization()248     public void testContactDetailsDedupe_Capitalization() throws TimeoutException {
249         // Add the original profile and the one where the the name is not capitalized.
250         // Make sure the original profile is suggested first (no particular reason).
251         mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[11]};
252         mCountsToSet = new int[] {15, 5};
253         mDatesToSet = new int[] {5000, 2000};
254 
255         mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
256         mPaymentRequestTestRule.clickInContactInfoAndWait(
257                 R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
258         Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions());
259         Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com",
260                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0));
261     }
262 
263     /**
264      * Makes sure that suggestions where some fields values are subsets of the other are not
265      * deduped.
266      */
267     @Test
268     @MediumTest
269     @Feature({"Payments"})
testContactDetailsDontDedupe_FieldSubset()270     public void testContactDetailsDontDedupe_FieldSubset() throws TimeoutException {
271         // Add the original profile and the one where the email is a superset of the original.
272         // Make sure the one with the superset is suggested first, because to test the subset one
273         // needs to be added after.
274         mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[10]};
275         mCountsToSet = new int[] {15, 25};
276         mDatesToSet = new int[] {5000, 7000};
277 
278         mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
279         mPaymentRequestTestRule.clickInContactInfoAndWait(
280                 R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
281         Assert.assertEquals(2, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions());
282         Assert.assertEquals("Lisa Simpson\n555 123-4567\nfakelisa@simpson.com",
283                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0));
284         Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com",
285                 mPaymentRequestTestRule.getContactDetailsSuggestionLabel(1));
286     }
287 
288     /**
289      * Make sure all fields are recorded when no profile exists.
290      */
291     @Test
292     @MediumTest
293     @Feature({"Payments"})
testContactDetailsAllMissingFieldsRecorded()294     public void testContactDetailsAllMissingFieldsRecorded() throws TimeoutException {
295         // Don't add any profiles.
296         mProfilesToAdd = new AutofillProfile[] {};
297         mCountsToSet = new int[] {};
298         mDatesToSet = new int[] {};
299 
300         mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
301         Assert.assertEquals(0, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions());
302 
303         // Verify that all contact fields are recorded as missing when no suggestion exists.
304         Assert.assertEquals(1,
305                 RecordHistogram.getHistogramValueCountForTesting(
306                         "PaymentRequest.MissingContactFields",
307                         ContactEditor.INVALID_NAME | ContactEditor.INVALID_PHONE_NUMBER
308                                 | ContactEditor.INVALID_EMAIL));
309     }
310 }
311