Home | History | Annotate | Download | only in autofill
      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:
     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 (at) 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.
    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.
    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.
    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.
    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
    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.
    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