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
33static const char* kDataURIPrefix = "data:text/html;charset=utf-8,";
34static 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
65class AutofillTest : public InProcessBrowserTest {
66 protected:
67  AutofillTest() {
68    set_show_window(true);
69    EnableDOMAutomation();
70  }
71
72  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
73    URLFetcher::set_factory(&url_fetcher_factory_);
74  }
75
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
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
104  RenderViewHost* render_view_host() {
105    return browser()->GetSelectedTabContents()->render_view_host();
106  }
107
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
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
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
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.
217IN_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.
230IN_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.
266IN_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.
356IN_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
380IN_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.
399IN_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