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