• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 #include <string>
6 
7 #include "base/basictypes.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/string16.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/autofill/autofill_common_test.h"
13 #include "chrome/browser/autofill/autofill_profile.h"
14 #include "chrome/browser/autofill/personal_data_manager.h"
15 #include "chrome/browser/net/predictor_api.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/translate/translate_infobar_delegate.h"
18 #include "chrome/browser/translate/translate_manager.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
22 #include "chrome/common/net/test_url_fetcher_factory.h"
23 #include "chrome/common/render_messages.h"
24 #include "chrome/renderer/translate_helper.h"
25 #include "chrome/test/in_process_browser_test.h"
26 #include "chrome/test/ui_test_utils.h"
27 #include "content/browser/renderer_host/mock_render_process_host.h"
28 #include "content/browser/renderer_host/render_view_host.h"
29 #include "content/browser/tab_contents/tab_contents.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "ui/base/keycodes/keyboard_codes.h"
32 
33 static const char* kDataURIPrefix = "data:text/html;charset=utf-8,";
34 static const char* kTestFormString =
35     "<form action=\"http://www.example.com/\" method=\"POST\">"
36     "<label for=\"firstname\">First name:</label>"
37     " <input type=\"text\" id=\"firstname\""
38     "        onFocus=\"domAutomationController.send(true)\" /><br />"
39     "<label for=\"lastname\">Last name:</label>"
40     " <input type=\"text\" id=\"lastname\" /><br />"
41     "<label for=\"address1\">Address line 1:</label>"
42     " <input type=\"text\" id=\"address1\" /><br />"
43     "<label for=\"address2\">Address line 2:</label>"
44     " <input type=\"text\" id=\"address2\" /><br />"
45     "<label for=\"city\">City:</label>"
46     " <input type=\"text\" id=\"city\" /><br />"
47     "<label for=\"state\">State:</label>"
48     " <select id=\"state\">"
49     " <option value=\"\" selected=\"yes\">--</option>"
50     " <option value=\"CA\">California</option>"
51     " <option value=\"TX\">Texas</option>"
52     " </select><br />"
53     "<label for=\"zip\">ZIP code:</label>"
54     " <input type=\"text\" id=\"zip\" /><br />"
55     "<label for=\"country\">Country:</label>"
56     " <select id=\"country\">"
57     " <option value=\"\" selected=\"yes\">--</option>"
58     " <option value=\"CA\">Canada</option>"
59     " <option value=\"US\">United States</option>"
60     " </select><br />"
61     "<label for=\"phone\">Phone number:</label>"
62     " <input type=\"text\" id=\"phone\" /><br />"
63     "</form>";
64 
65 class AutofillTest : public InProcessBrowserTest {
66  protected:
AutofillTest()67   AutofillTest() {
68     set_show_window(true);
69     EnableDOMAutomation();
70   }
71 
SetUpInProcessBrowserTestFixture()72   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
73     URLFetcher::set_factory(&url_fetcher_factory_);
74   }
75 
CreateTestProfile()76   void CreateTestProfile() {
77     autofill_test::DisableSystemServices(browser()->profile());
78 
79     AutofillProfile profile;
80     autofill_test::SetProfileInfo(
81         &profile, "Milton", "C.", "Waddams",
82         "red.swingline@initech.com", "Initech", "4120 Freidrich Lane",
83         "Basement", "Austin", "Texas", "78744", "United States", "5125551234",
84         "5125550000");
85 
86     PersonalDataManager* personal_data_manager =
87         browser()->profile()->GetPersonalDataManager();
88     ASSERT_TRUE(personal_data_manager);
89 
90     std::vector<AutofillProfile> profiles(1, profile);
91     personal_data_manager->SetProfiles(&profiles);
92   }
93 
ExpectFieldValue(const std::wstring & field_name,const std::string & expected_value)94   void ExpectFieldValue(const std::wstring& field_name,
95                         const std::string& expected_value) {
96     std::string value;
97     ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
98         browser()->GetSelectedTabContents()->render_view_host(), L"",
99         L"window.domAutomationController.send("
100         L"document.getElementById('" + field_name + L"').value);", &value));
101     EXPECT_EQ(expected_value, value);
102   }
103 
render_view_host()104   RenderViewHost* render_view_host() {
105     return browser()->GetSelectedTabContents()->render_view_host();
106   }
107 
SimulateURLFetch(bool success)108   void SimulateURLFetch(bool success) {
109     TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
110     ASSERT_TRUE(fetcher);
111     net::URLRequestStatus status;
112     status.set_status(success ? net::URLRequestStatus::SUCCESS :
113                                 net::URLRequestStatus::FAILED);
114 
115     std::string script = " var google = {};"
116         "google.translate = (function() {"
117         "  return {"
118         "    TranslateService: function() {"
119         "      return {"
120         "        isAvailable : function() {"
121         "          return true;"
122         "        },"
123         "        restore : function() {"
124         "          return;"
125         "        },"
126         "        getDetectedLanguage : function() {"
127         "          return \"ja\";"
128         "        },"
129         "        translatePage : function(originalLang, targetLang,"
130         "                                 onTranslateProgress) {"
131         "          document.getElementsByTagName(\"body\")[0].innerHTML = '" +
132         std::string(kTestFormString) +
133         "              ';"
134         "          onTranslateProgress(100, true, false);"
135         "        }"
136         "      };"
137         "    }"
138         "  };"
139         "})();";
140 
141     fetcher->delegate()->OnURLFetchComplete(fetcher, fetcher->original_url(),
142         status, success ? 200 : 500,
143         ResponseCookies(),
144         script);
145   }
146 
FocusFirstNameField()147   void FocusFirstNameField() {
148     ASSERT_NO_FATAL_FAILURE(ui_test_utils::ClickOnView(browser(),
149                                                        VIEW_ID_TAB_CONTAINER));
150     ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(),
151                                              VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
152 
153     bool result = false;
154     ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
155         render_view_host(), L"",
156         L"document.getElementById('firstname').focus();", &result));
157     ASSERT_TRUE(result);
158   }
159 
ExpectFilledTestForm()160   void ExpectFilledTestForm() {
161     ExpectFieldValue(L"firstname", "Milton");
162     ExpectFieldValue(L"lastname", "Waddams");
163     ExpectFieldValue(L"address1", "4120 Freidrich Lane");
164     ExpectFieldValue(L"address2", "Basement");
165     ExpectFieldValue(L"city", "Austin");
166     ExpectFieldValue(L"state", "TX");
167     ExpectFieldValue(L"zip", "78744");
168     ExpectFieldValue(L"country", "US");
169     ExpectFieldValue(L"phone", "5125551234");
170   }
171 
TryBasicFormFill()172   void TryBasicFormFill() {
173     FocusFirstNameField();
174 
175     // Start filling the first name field with "M" and wait for the popup to be
176     // shown.
177     ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
178         browser(), ui::VKEY_M, false, true, false, false,
179         NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS,
180         Source<RenderViewHost>(render_view_host())));
181 
182     // Press the down arrow to select the suggestion and preview the autofilled
183     // form.
184     ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
185         browser(), ui::VKEY_DOWN, false, false, false, false,
186         NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
187         Source<RenderViewHost>(render_view_host())));
188 
189     // The previewed values should not be accessible to JavaScript.
190     ExpectFieldValue(L"firstname", "M");
191     ExpectFieldValue(L"lastname", "");
192     ExpectFieldValue(L"address1", "");
193     ExpectFieldValue(L"address2", "");
194     ExpectFieldValue(L"city", "");
195     ExpectFieldValue(L"state", "");
196     ExpectFieldValue(L"zip", "");
197     ExpectFieldValue(L"country", "");
198     ExpectFieldValue(L"phone", "");
199     // TODO(isherman): It would be nice to test that the previewed values are
200     // displayed: http://crbug.com/57220
201 
202     // Press Enter to accept the autofill suggestions.
203     ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
204         browser(), ui::VKEY_RETURN, false, false, false, false,
205         NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
206         Source<RenderViewHost>(render_view_host())));
207 
208     // The form should be filled.
209     ExpectFilledTestForm();
210   }
211 
212  private:
213   TestURLFetcherFactory url_fetcher_factory_;
214 };
215 
216 // Test that basic form fill is working.
IN_PROC_BROWSER_TEST_F(AutofillTest,BasicFormFill)217 IN_PROC_BROWSER_TEST_F(AutofillTest, BasicFormFill) {
218   CreateTestProfile();
219 
220   // Load the test page.
221   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
222   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
223       GURL(std::string(kDataURIPrefix) + kTestFormString)));
224 
225   // Invoke Autofill.
226   TryBasicFormFill();
227 }
228 
229 // Test that form filling can be initiated by pressing the down arrow.
IN_PROC_BROWSER_TEST_F(AutofillTest,AutofillViaDownArrow)230 IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillViaDownArrow) {
231   CreateTestProfile();
232 
233   // Load the test page.
234   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
235   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
236       GURL(std::string(kDataURIPrefix) + kTestFormString)));
237 
238   // Focus a fillable field.
239   FocusFirstNameField();
240 
241   // Press the down arrow to initiate Autofill and wait for the popup to be
242   // shown.
243   ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
244       browser(), ui::VKEY_DOWN, false, false, false, false,
245       NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS,
246       Source<RenderViewHost>(render_view_host())));
247 
248   // Press the down arrow to select the suggestion and preview the autofilled
249   // form.
250   ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
251       browser(), ui::VKEY_DOWN, false, false, false, false,
252       NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
253       Source<RenderViewHost>(render_view_host())));
254 
255   // Press Enter to accept the autofill suggestions.
256   ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
257       browser(), ui::VKEY_RETURN, false, false, false, false,
258       NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
259       Source<RenderViewHost>(render_view_host())));
260 
261   // The form should be filled.
262   ExpectFilledTestForm();
263 }
264 
265 // Test that a JavaScript onchange event is fired after auto-filling a form.
IN_PROC_BROWSER_TEST_F(AutofillTest,OnChangeAfterAutofill)266 IN_PROC_BROWSER_TEST_F(AutofillTest, OnChangeAfterAutofill) {
267   CreateTestProfile();
268 
269   const char* kOnChangeScript =
270       "<script>"
271       "focused_fired = false;"
272       "unfocused_fired = false;"
273       "changed_select_fired = false;"
274       "unchanged_select_fired = false;"
275       "document.getElementById('firstname').onchange = function() {"
276       "  focused_fired = true;"
277       "};"
278       "document.getElementById('lastname').onchange = function() {"
279       "  unfocused_fired = true;"
280       "};"
281       "document.getElementById('state').onchange = function() {"
282       "  changed_select_fired = true;"
283       "};"
284       "document.getElementById('country').onchange = function() {"
285       "  unchanged_select_fired = true;"
286       "};"
287       "document.getElementById('country').value = 'US';"
288       "</script>";
289 
290   // Load the test page.
291   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
292   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
293       GURL(std::string(kDataURIPrefix) + kTestFormString + kOnChangeScript)));
294 
295   // Invoke Autofill.
296   FocusFirstNameField();
297 
298   // Start filling the first name field with "M" and wait for the popup to be
299   // shown.
300   ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
301       browser(), ui::VKEY_M, false, true, false, false,
302       NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS,
303       Source<RenderViewHost>(render_view_host())));
304 
305   // Press the down arrow to select the suggestion and preview the autofilled
306   // form.
307   ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
308       browser(), ui::VKEY_DOWN, false, false, false, false,
309       NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
310       Source<RenderViewHost>(render_view_host())));
311 
312   // Press Enter to accept the autofill suggestions.
313   ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
314       browser(), ui::VKEY_RETURN, false, false, false, false,
315       NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
316       Source<RenderViewHost>(render_view_host())));
317 
318   // The form should be filled.
319   ExpectFilledTestForm();
320 
321   // The change event should have already fired for unfocused fields, both of
322   // <input> and of <select> type. However, it should not yet have fired for the
323   // focused field.
324   bool focused_fired = false;
325   bool unfocused_fired = false;
326   bool changed_select_fired = false;
327   bool unchanged_select_fired = false;
328   ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
329       render_view_host(), L"",
330       L"domAutomationController.send(focused_fired);", &focused_fired));
331   ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
332       render_view_host(), L"",
333       L"domAutomationController.send(unfocused_fired);", &unfocused_fired));
334   ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
335       render_view_host(), L"",
336       L"domAutomationController.send(changed_select_fired);",
337       &changed_select_fired));
338   ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
339       render_view_host(), L"",
340       L"domAutomationController.send(unchanged_select_fired);",
341       &unchanged_select_fired));
342   EXPECT_FALSE(focused_fired);
343   EXPECT_TRUE(unfocused_fired);
344   EXPECT_TRUE(changed_select_fired);
345   EXPECT_FALSE(unchanged_select_fired);
346 
347   // Unfocus the first name field. Its change event should fire.
348   ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
349       render_view_host(), L"",
350       L"document.getElementById('firstname').blur();"
351       L"domAutomationController.send(focused_fired);", &focused_fired));
352   EXPECT_TRUE(focused_fired);
353 }
354 
355 // Test that we can autofill forms distinguished only by their |id| attribute.
IN_PROC_BROWSER_TEST_F(AutofillTest,AutofillFormsDistinguishedById)356 IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillFormsDistinguishedById) {
357   CreateTestProfile();
358 
359   // Load the test page.
360   const std::string kURL =
361       std::string(kDataURIPrefix) + kTestFormString +
362       "<script>"
363       "var mainForm = document.forms[0];"
364       "mainForm.id = 'mainForm';"
365       "var newForm = document.createElement('form');"
366       "newForm.action = mainForm.action;"
367       "newForm.method = mainForm.method;"
368       "newForm.id = 'newForm';"
369       "mainForm.parentNode.insertBefore(newForm, mainForm);"
370       "</script>";
371   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
372   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), GURL(kURL)));
373 
374   // Invoke Autofill.
375   TryBasicFormFill();
376 }
377 
378 // Test that form filling works after reloading the current page.
379 // This test brought to you by http://crbug.com/69204
IN_PROC_BROWSER_TEST_F(AutofillTest,AutofillAfterReload)380 IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillAfterReload) {
381   CreateTestProfile();
382 
383   // Load the test page.
384   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
385   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
386       GURL(std::string(kDataURIPrefix) + kTestFormString)));
387 
388   // Reload the page.
389   TabContents* tab =
390       browser()->GetSelectedTabContentsWrapper()->tab_contents();
391   tab->controller().Reload(false);
392   ui_test_utils::WaitForLoadStop(tab);
393 
394   // Invoke Autofill.
395   TryBasicFormFill();
396 }
397 
398 // Test that autofill works after page translation.
IN_PROC_BROWSER_TEST_F(AutofillTest,AutofillAfterTranslate)399 IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillAfterTranslate) {
400   CreateTestProfile();
401 
402   GURL url(std::string(kDataURIPrefix) +
403                "<form action=\"http://www.example.com/\" method=\"POST\">"
404                "<label for=\"fn\">なまえ</label>"
405                " <input type=\"text\" id=\"fn\""
406                "        onFocus=\"domAutomationController.send(true)\""
407                " /><br />"
408                "<label for=\"ln\">みょうじ</label>"
409                " <input type=\"text\" id=\"ln\" /><br />"
410                "<label for=\"a1\">Address line 1:</label>"
411                " <input type=\"text\" id=\"a1\" /><br />"
412                "<label for=\"a2\">Address line 2:</label>"
413                " <input type=\"text\" id=\"a2\" /><br />"
414                "<label for=\"ci\">City:</label>"
415                " <input type=\"text\" id=\"ci\" /><br />"
416                "<label for=\"st\">State:</label>"
417                " <select id=\"st\">"
418                " <option value=\"\" selected=\"yes\">--</option>"
419                " <option value=\"CA\">California</option>"
420                " <option value=\"TX\">Texas</option>"
421                " </select><br />"
422                "<label for=\"z\">ZIP code:</label>"
423                " <input type=\"text\" id=\"z\" /><br />"
424                "<label for=\"co\">Country:</label>"
425                " <select id=\"co\">"
426                " <option value=\"\" selected=\"yes\">--</option>"
427                " <option value=\"CA\">Canada</option>"
428                " <option value=\"US\">United States</option>"
429                " </select><br />"
430                "<label for=\"ph\">Phone number:</label>"
431                " <input type=\"text\" id=\"ph\" /><br />"
432                "</form>");
433   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
434   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url));
435 
436   // Get translation bar.
437   render_view_host()->OnMessageReceived(ViewHostMsg_TranslateLanguageDetermined(
438       0, "ja", true));
439   TranslateInfoBarDelegate* infobar = browser()->GetSelectedTabContents()->
440       GetInfoBarDelegateAt(0)->AsTranslateInfoBarDelegate();
441 
442   ASSERT_TRUE(infobar != NULL);
443   EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
444 
445   // Simulate translation button press.
446   infobar->Translate();
447 
448   // Simulate the translate script being retrieved.
449   // Pass fake google.translate lib as the translate script.
450   SimulateURLFetch(true);
451 
452   // Simulate translation to kick onTranslateElementLoad.
453   // But right now, the call stucks here.
454   // Once click the text field, it starts again.
455   ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(
456       render_view_host(), L"",
457       L"cr.googleTranslate.onTranslateElementLoad();"));
458 
459   // Simulate the render notifying the translation has been done.
460   ui_test_utils::WaitForNotification(NotificationType::PAGE_TRANSLATED);
461 
462   TryBasicFormFill();
463 }
464