Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / android / javatests / src / org / chromium / chrome / browser / autofill / AutofillPopupTest.java
1 // Copyright 2013 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.autofill;
6
7 import android.test.suitebuilder.annotation.MediumTest;
8 import android.text.TextUtils;
9 import android.view.View;
10 import android.view.ViewGroup;
11
12 import org.chromium.base.ThreadUtils;
13 import org.chromium.base.test.util.Feature;
14 import org.chromium.base.test.util.UrlUtils;
15 import org.chromium.chrome.R;
16 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
17 import org.chromium.chrome.shell.ChromeShellTestBase;
18 import org.chromium.content.browser.ContentViewCore;
19 import org.chromium.content.browser.test.util.Criteria;
20 import org.chromium.content.browser.test.util.CriteriaHelper;
21 import org.chromium.content.browser.test.util.DOMUtils;
22 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper;
23 import org.chromium.content.browser.test.util.TouchCommon;
24 import org.chromium.ui.autofill.AutofillPopup;
25
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.TimeoutException;
30
31 /**
32  * Integration tests for the AutofillPopup.
33  */
34 public class AutofillPopupTest extends ChromeShellTestBase {
35
36     private static final String FIRST_NAME = "John";
37     private static final String LAST_NAME = "Smith";
38     private static final String COMPANY_NAME = "Acme Inc.";
39     private static final String ADDRESS_LINE1 = "1 Main";
40     private static final String ADDRESS_LINE2 = "Apt A";
41     private static final String STREET_ADDRESS_TEXTAREA = ADDRESS_LINE1 + "\n" + ADDRESS_LINE2;
42     private static final String CITY = "San Francisco";
43     private static final String DEPENDENT_LOCALITY = "";
44     private static final String STATE = "CA";
45     private static final String ZIP_CODE = "94102";
46     private static final String SORTING_CODE = "";
47     private static final String COUNTRY = "US";
48     private static final String PHONE_NUMBER = "4158889999";
49     private static final String EMAIL = "john@acme.inc";
50     private static final String LANGUAGE_CODE = "";
51     private static final String ORIGIN = "https://www.example.com";
52
53     private static final String BASIC_PAGE_DATA = UrlUtils.encodeHtmlDataUri(
54             "<html><head><meta name=\"viewport\"" +
55             "content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" /></head>" +
56             "<body><form method=\"POST\">" +
57             "<input type=\"text\" id=\"fn\" autocomplete=\"given-name\" /><br>" +
58             "<input type=\"text\" id=\"ln\" autocomplete=\"family-name\" /><br>" +
59             "<textarea id=\"sa\" autocomplete=\"street-address\"></textarea><br>" +
60             "<input type=\"text\" id=\"a1\" autocomplete=\"address-line1\" /><br>" +
61             "<input type=\"text\" id=\"a2\" autocomplete=\"address-line2\" /><br>" +
62             "<input type=\"text\" id=\"ct\" autocomplete=\"locality\" /><br>" +
63             "<input type=\"text\" id=\"zc\" autocomplete=\"postal-code\" /><br>" +
64             "<input type=\"text\" id=\"em\" autocomplete=\"email\" /><br>" +
65             "<input type=\"text\" id=\"ph\" autocomplete=\"tel\" /><br>" +
66             "<input type=\"text\" id=\"fx\" autocomplete=\"fax\" /><br>" +
67             "<select id=\"co\" autocomplete=\"country\"><br>" +
68             "<option value=\"BR\">Brazil</option>" +
69             "<option value=\"US\">United States</option>" +
70             "</select>" +
71             "<input type=\"submit\" />" +
72             "</form></body></html>");
73
74     private static final String INITIATING_ELEMENT_FILLED = UrlUtils.encodeHtmlDataUri(
75             "<html><head><meta name=\"viewport\"" +
76             "content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" /></head>" +
77             "<body><form method=\"POST\">" +
78             "<input type=\"text\" id=\"fn\" autocomplete=\"given-name\" value=\"J\"><br>" +
79             "<input type=\"text\" id=\"ln\" autocomplete=\"family-name\"><br>" +
80             "<input type=\"text\" id=\"em\" autocomplete=\"email\"><br>" +
81             "<select id=\"co\" autocomplete=\"country\"><br>" +
82             "<option value=\"US\">United States</option>" +
83             "<option value=\"BR\">Brazil</option>" +
84             "</select>" +
85             "<input type=\"submit\" />" +
86             "</form></body></html>");
87
88     private static final String ANOTHER_ELEMENT_FILLED = UrlUtils.encodeHtmlDataUri(
89             "<html><head><meta name=\"viewport\"" +
90             "content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" /></head>" +
91             "<body><form method=\"POST\">" +
92             "<input type=\"text\" id=\"fn\" autocomplete=\"given-name\"><br>" +
93             "<input type=\"text\" id=\"ln\" autocomplete=\"family-name\"><br>" +
94             "<input type=\"text\" id=\"em\" autocomplete=\"email\" value=\"foo@example.com\"><br>" +
95             "<select id=\"co\" autocomplete=\"country\"><br>" +
96             "<option></option>" +
97             "<option value=\"BR\">Brazil</option>" +
98             "<option value=\"US\">United States</option>" +
99             "</select>" +
100             "<input type=\"submit\" />" +
101             "</form></body></html>");
102
103     private static final String INVALID_OPTION = UrlUtils.encodeHtmlDataUri(
104             "<html><head><meta name=\"viewport\"" +
105             "content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" /></head>" +
106             "<body><form method=\"POST\">" +
107             "<input type=\"text\" id=\"fn\" autocomplete=\"given-name\" value=\"J\"><br>" +
108             "<input type=\"text\" id=\"ln\" autocomplete=\"family-name\"><br>" +
109             "<input type=\"text\" id=\"em\" autocomplete=\"email\"><br>" +
110             "<select id=\"co\" autocomplete=\"country\"><br>" +
111             "<option value=\"GB\">Great Britain</option>" +
112             "<option value=\"BR\">Brazil</option>" +
113             "</select>" +
114             "<input type=\"submit\" />" +
115             "</form></body></html>");
116
117     private AutofillTestHelper mHelper;
118     private List<AutofillLogger.LogEntry> mAutofillLoggedEntries;
119
120     @Override
121     public void setUp() throws Exception {
122         super.setUp();
123         clearAppData();
124         mAutofillLoggedEntries = new ArrayList<AutofillLogger.LogEntry>();
125         AutofillLogger.setLogger(
126             new AutofillLogger.Logger() {
127                 @Override
128                 public void didFillField(AutofillLogger.LogEntry logEntry) {
129                     mAutofillLoggedEntries.add(logEntry);
130                 }}
131         );
132     }
133
134     private void loadAndFillForm(
135             final String formDataUrl, final String inputText)
136             throws InterruptedException, ExecutionException, TimeoutException {
137         launchChromeShellWithUrl(formDataUrl);
138         assertTrue(waitForActiveShellToBeDoneLoading());
139         mHelper = new AutofillTestHelper();
140
141         // The TestInputMethodManagerWrapper intercepts showSoftInput so that a keyboard is never
142         // brought up.
143         final ContentViewCore viewCore = getActivity().getActiveContentViewCore();
144         final ViewGroup view = viewCore.getContainerView();
145         final TestInputMethodManagerWrapper immw =
146                 new TestInputMethodManagerWrapper(viewCore);
147         viewCore.getImeAdapterForTest().setInputMethodManagerWrapper(immw);
148
149         // Add an Autofill profile.
150         AutofillProfile profile = new AutofillProfile(
151                 "" /* guid */, ORIGIN, FIRST_NAME + " " + LAST_NAME, COMPANY_NAME,
152                 STREET_ADDRESS_TEXTAREA,
153                 STATE, CITY, DEPENDENT_LOCALITY,
154                 ZIP_CODE, SORTING_CODE, COUNTRY, PHONE_NUMBER, EMAIL,
155                 LANGUAGE_CODE);
156         mHelper.setProfile(profile);
157         assertEquals(1, mHelper.getNumberOfProfiles());
158
159         // Click the input field for the first name.
160         assertTrue(DOMUtils.waitForNonZeroNodeBounds(viewCore, "fn"));
161         DOMUtils.clickNode(this, viewCore, "fn");
162
163         waitForKeyboardShowRequest(immw, 1);
164
165         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
166             @Override
167             public void run() {
168                 viewCore.getInputConnectionForTest().setComposingText(
169                         inputText, 1);
170             }
171         });
172
173         waitForAnchorViewAdd(view);
174         View anchorView = view.findViewById(R.id.dropdown_popup_window);
175
176         assertTrue(anchorView.getTag() instanceof AutofillPopup);
177         final AutofillPopup popup = (AutofillPopup) anchorView.getTag();
178
179         waitForAutofillPopopShow(popup);
180
181         TouchCommon touchCommon = new TouchCommon(this);
182         touchCommon.singleClickViewRelative(popup.getListView(), 10, 10);
183
184         waitForInputFieldFill(viewCore);
185     }
186
187     /**
188      * Tests that bringing up an Autofill and clicking on the first entry fills out the expected
189      * Autofill information.
190      */
191     @MediumTest
192     @Feature({"autofill"})
193     public void testClickAutofillPopupSuggestion()
194             throws InterruptedException, ExecutionException, TimeoutException {
195         loadAndFillForm(BASIC_PAGE_DATA, "J");
196         final ContentViewCore viewCore = getActivity().getActiveContentViewCore();
197
198         assertEquals("First name did not match",
199                 FIRST_NAME, DOMUtils.getNodeValue(viewCore, "fn"));
200         assertEquals("Last name did not match",
201                 LAST_NAME, DOMUtils.getNodeValue(viewCore, "ln"));
202         assertEquals("Street address (textarea) did not match",
203                 STREET_ADDRESS_TEXTAREA, DOMUtils.getNodeValue(viewCore, "sa"));
204         assertEquals("Address line 1 did not match",
205                 ADDRESS_LINE1, DOMUtils.getNodeValue(viewCore, "a1"));
206         assertEquals("Address line 2 did not match",
207                 ADDRESS_LINE2, DOMUtils.getNodeValue(viewCore, "a2"));
208         assertEquals("City did not match",
209                 CITY, DOMUtils.getNodeValue(viewCore, "ct"));
210         assertEquals("Zip code did not match",
211                 ZIP_CODE, DOMUtils.getNodeValue(viewCore, "zc"));
212         assertEquals("Country did not match",
213                 COUNTRY, DOMUtils.getNodeValue(viewCore, "co"));
214         assertEquals("Email did not match",
215                 EMAIL, DOMUtils.getNodeValue(viewCore, "em"));
216         assertEquals("Phone number did not match",
217                 PHONE_NUMBER, DOMUtils.getNodeValue(viewCore, "ph"));
218
219         final String profileFullName = FIRST_NAME + " " + LAST_NAME;
220         final int loggedEntries = 10;
221         assertEquals("Mismatched number of logged entries",
222                 loggedEntries, mAutofillLoggedEntries.size());
223         assertLogged(FIRST_NAME, profileFullName);
224         assertLogged(LAST_NAME, profileFullName);
225         assertLogged(STREET_ADDRESS_TEXTAREA, profileFullName);
226         assertLogged(ADDRESS_LINE1, profileFullName);
227         assertLogged(ADDRESS_LINE2, profileFullName);
228         assertLogged(CITY, profileFullName);
229         assertLogged(ZIP_CODE, profileFullName);
230         assertLogged(COUNTRY, profileFullName);
231         assertLogged(EMAIL, profileFullName);
232         assertLogged(PHONE_NUMBER, profileFullName);
233     }
234
235     /**
236      * Tests that bringing up an Autofill and clicking on the partially filled first
237      * element will still fill the entire form (including the initiating element itself).
238      */
239     @MediumTest
240     @Feature({"autofill"})
241     public void testLoggingInitiatedElementFilled()
242             throws InterruptedException, ExecutionException, TimeoutException {
243         loadAndFillForm(INITIATING_ELEMENT_FILLED, "o");
244         final String profileFullName = FIRST_NAME + " " + LAST_NAME;
245         final int loggedEntries = 4;
246         assertEquals("Mismatched number of logged entries",
247                 loggedEntries, mAutofillLoggedEntries.size());
248         assertLogged(FIRST_NAME, profileFullName);
249         assertLogged(LAST_NAME, profileFullName);
250         assertLogged(EMAIL, profileFullName);
251         assertLogged(COUNTRY, profileFullName);
252     }
253
254     /**
255      * Tests that bringing up an Autofill and clicking on the empty first element
256      * will fill the all other elements except the previously filled email.
257      */
258     @MediumTest
259     @Feature({"autofill"})
260     public void testLoggingAnotherElementFilled()
261             throws InterruptedException, ExecutionException, TimeoutException {
262         loadAndFillForm(ANOTHER_ELEMENT_FILLED, "J");
263         final String profileFullName = FIRST_NAME + " " + LAST_NAME;
264         final int loggedEntries = 3;
265         assertEquals("Mismatched number of logged entries",
266                 loggedEntries, mAutofillLoggedEntries.size());
267         assertLogged(FIRST_NAME, profileFullName);
268         assertLogged(LAST_NAME, profileFullName);
269         assertLogged(COUNTRY, profileFullName);
270         // Email will not be logged since it already had some data.
271     }
272
273     /**
274      * Tests that selecting a value not present in <option> will not be filled.
275      */
276     @MediumTest
277     @Feature({"autofill"})
278     public void testNotLoggingInvalidOption()
279             throws InterruptedException, ExecutionException, TimeoutException {
280         loadAndFillForm(INVALID_OPTION, "o");
281         final String profileFullName = FIRST_NAME + " " + LAST_NAME;
282         final int loggedEntries = 3;
283         assertEquals("Mismatched number of logged entries",
284                 loggedEntries, mAutofillLoggedEntries.size());
285         assertLogged(FIRST_NAME, profileFullName);
286         assertLogged(LAST_NAME, profileFullName);
287         assertLogged(EMAIL, profileFullName);
288         // Country will not be logged since "US" is not a valid <option>.
289     }
290
291     // Wait and assert helper methods -------------------------------------------------------------
292
293     private void waitForKeyboardShowRequest(final TestInputMethodManagerWrapper immw,
294             final int count) throws InterruptedException {
295         assertTrue("Keyboard was never requested to be shown.",
296                 CriteriaHelper.pollForCriteria(new Criteria() {
297                     @Override
298                     public boolean isSatisfied() {
299                         return immw.getShowSoftInputCounter() == count;
300                     }
301                 }));
302     }
303
304     private void waitForAnchorViewAdd(final ViewGroup view) throws InterruptedException {
305         assertTrue("Autofill Popup anchor view was never added.",
306                 CriteriaHelper.pollForCriteria(new Criteria() {
307                     @Override
308                     public boolean isSatisfied() {
309                         return view.findViewById(R.id.dropdown_popup_window) != null;
310                     }
311                 }));
312     }
313
314     private void waitForAutofillPopopShow(final AutofillPopup popup) throws InterruptedException {
315         assertTrue("Autofill Popup anchor view was never added.",
316                 CriteriaHelper.pollForCriteria(new Criteria() {
317                     @Override
318                     public boolean isSatisfied() {
319                         return popup.isShowing();
320                     }
321                 }));
322     }
323
324     private void waitForInputFieldFill(final ContentViewCore viewCore) throws InterruptedException {
325         assertTrue("First name field was never filled.",
326                 CriteriaHelper.pollForCriteria(new Criteria() {
327                     @Override
328                     public boolean isSatisfied() {
329                         try {
330                             return TextUtils.equals(FIRST_NAME,
331                                     DOMUtils.getNodeValue(viewCore, "fn"));
332                         } catch (InterruptedException e) {
333                             return false;
334                         } catch (TimeoutException e) {
335                             return false;
336                         }
337
338                     }
339                 }));
340     }
341
342     private void assertLogged(String autofilledValue, String profileFullName) {
343         for (AutofillLogger.LogEntry entry : mAutofillLoggedEntries) {
344             if (entry.getAutofilledValue().equals(autofilledValue) &&
345                 entry.getProfileFullName().equals(profileFullName)) {
346                 return;
347             }
348         }
349         fail("Logged entry not found [" + autofilledValue + "," + profileFullName + "]");
350     }
351 }