| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/string16.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/autofill/autofill_common_test.h" |
| #include "chrome/browser/autofill/autofill_profile.h" |
| #include "chrome/browser/autofill/personal_data_manager.h" |
| #include "chrome/browser/net/predictor_api.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/translate/translate_infobar_delegate.h" |
| #include "chrome/browser/translate/translate_manager.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/common/net/test_url_fetcher_factory.h" |
| #include "chrome/common/render_messages.h" |
| #include "chrome/renderer/translate_helper.h" |
| #include "chrome/test/in_process_browser_test.h" |
| #include "chrome/test/ui_test_utils.h" |
| #include "content/browser/renderer_host/mock_render_process_host.h" |
| #include "content/browser/renderer_host/render_view_host.h" |
| #include "content/browser/tab_contents/tab_contents.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/keycodes/keyboard_codes.h" |
| |
| static const char* kDataURIPrefix = "data:text/html;charset=utf-8,"; |
| static const char* kTestFormString = |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"firstname\">First name:</label>" |
| " <input type=\"text\" id=\"firstname\"" |
| " onFocus=\"domAutomationController.send(true)\" /><br />" |
| "<label for=\"lastname\">Last name:</label>" |
| " <input type=\"text\" id=\"lastname\" /><br />" |
| "<label for=\"address1\">Address line 1:</label>" |
| " <input type=\"text\" id=\"address1\" /><br />" |
| "<label for=\"address2\">Address line 2:</label>" |
| " <input type=\"text\" id=\"address2\" /><br />" |
| "<label for=\"city\">City:</label>" |
| " <input type=\"text\" id=\"city\" /><br />" |
| "<label for=\"state\">State:</label>" |
| " <select id=\"state\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br />" |
| "<label for=\"zip\">ZIP code:</label>" |
| " <input type=\"text\" id=\"zip\" /><br />" |
| "<label for=\"country\">Country:</label>" |
| " <select id=\"country\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br />" |
| "<label for=\"phone\">Phone number:</label>" |
| " <input type=\"text\" id=\"phone\" /><br />" |
| "</form>"; |
| |
| class AutofillTest : public InProcessBrowserTest { |
| protected: |
| AutofillTest() { |
| set_show_window(true); |
| EnableDOMAutomation(); |
| } |
| |
| virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { |
| URLFetcher::set_factory(&url_fetcher_factory_); |
| } |
| |
| void CreateTestProfile() { |
| autofill_test::DisableSystemServices(browser()->profile()); |
| |
| AutofillProfile profile; |
| autofill_test::SetProfileInfo( |
| &profile, "Milton", "C.", "Waddams", |
| "red.swingline@initech.com", "Initech", "4120 Freidrich Lane", |
| "Basement", "Austin", "Texas", "78744", "United States", "5125551234", |
| "5125550000"); |
| |
| PersonalDataManager* personal_data_manager = |
| browser()->profile()->GetPersonalDataManager(); |
| ASSERT_TRUE(personal_data_manager); |
| |
| std::vector<AutofillProfile> profiles(1, profile); |
| personal_data_manager->SetProfiles(&profiles); |
| } |
| |
| void ExpectFieldValue(const std::wstring& field_name, |
| const std::string& expected_value) { |
| std::string value; |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( |
| browser()->GetSelectedTabContents()->render_view_host(), L"", |
| L"window.domAutomationController.send(" |
| L"document.getElementById('" + field_name + L"').value);", &value)); |
| EXPECT_EQ(expected_value, value); |
| } |
| |
| RenderViewHost* render_view_host() { |
| return browser()->GetSelectedTabContents()->render_view_host(); |
| } |
| |
| void SimulateURLFetch(bool success) { |
| TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); |
| ASSERT_TRUE(fetcher); |
| net::URLRequestStatus status; |
| status.set_status(success ? net::URLRequestStatus::SUCCESS : |
| net::URLRequestStatus::FAILED); |
| |
| std::string script = " var google = {};" |
| "google.translate = (function() {" |
| " return {" |
| " TranslateService: function() {" |
| " return {" |
| " isAvailable : function() {" |
| " return true;" |
| " }," |
| " restore : function() {" |
| " return;" |
| " }," |
| " getDetectedLanguage : function() {" |
| " return \"ja\";" |
| " }," |
| " translatePage : function(originalLang, targetLang," |
| " onTranslateProgress) {" |
| " document.getElementsByTagName(\"body\")[0].innerHTML = '" + |
| std::string(kTestFormString) + |
| " ';" |
| " onTranslateProgress(100, true, false);" |
| " }" |
| " };" |
| " }" |
| " };" |
| "})();"; |
| |
| fetcher->delegate()->OnURLFetchComplete(fetcher, fetcher->original_url(), |
| status, success ? 200 : 500, |
| ResponseCookies(), |
| script); |
| } |
| |
| void FocusFirstNameField() { |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::ClickOnView(browser(), |
| VIEW_ID_TAB_CONTAINER)); |
| ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), |
| VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); |
| |
| bool result = false; |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( |
| render_view_host(), L"", |
| L"document.getElementById('firstname').focus();", &result)); |
| ASSERT_TRUE(result); |
| } |
| |
| void ExpectFilledTestForm() { |
| ExpectFieldValue(L"firstname", "Milton"); |
| ExpectFieldValue(L"lastname", "Waddams"); |
| ExpectFieldValue(L"address1", "4120 Freidrich Lane"); |
| ExpectFieldValue(L"address2", "Basement"); |
| ExpectFieldValue(L"city", "Austin"); |
| ExpectFieldValue(L"state", "TX"); |
| ExpectFieldValue(L"zip", "78744"); |
| ExpectFieldValue(L"country", "US"); |
| ExpectFieldValue(L"phone", "5125551234"); |
| } |
| |
| void TryBasicFormFill() { |
| FocusFirstNameField(); |
| |
| // Start filling the first name field with "M" and wait for the popup to be |
| // shown. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_M, false, true, false, false, |
| NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_DOWN, false, false, false, false, |
| NotificationType::AUTOFILL_DID_FILL_FORM_DATA, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // The previewed values should not be accessible to JavaScript. |
| ExpectFieldValue(L"firstname", "M"); |
| ExpectFieldValue(L"lastname", ""); |
| ExpectFieldValue(L"address1", ""); |
| ExpectFieldValue(L"address2", ""); |
| ExpectFieldValue(L"city", ""); |
| ExpectFieldValue(L"state", ""); |
| ExpectFieldValue(L"zip", ""); |
| ExpectFieldValue(L"country", ""); |
| ExpectFieldValue(L"phone", ""); |
| // TODO(isherman): It would be nice to test that the previewed values are |
| // displayed: http://crbug.com/57220 |
| |
| // Press Enter to accept the autofill suggestions. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_RETURN, false, false, false, false, |
| NotificationType::AUTOFILL_DID_FILL_FORM_DATA, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| private: |
| TestURLFetcherFactory url_fetcher_factory_; |
| }; |
| |
| // Test that basic form fill is working. |
| IN_PROC_BROWSER_TEST_F(AutofillTest, BasicFormFill) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), |
| GURL(std::string(kDataURIPrefix) + kTestFormString))); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| // Test that form filling can be initiated by pressing the down arrow. |
| IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillViaDownArrow) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), |
| GURL(std::string(kDataURIPrefix) + kTestFormString))); |
| |
| // Focus a fillable field. |
| FocusFirstNameField(); |
| |
| // Press the down arrow to initiate Autofill and wait for the popup to be |
| // shown. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_DOWN, false, false, false, false, |
| NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_DOWN, false, false, false, false, |
| NotificationType::AUTOFILL_DID_FILL_FORM_DATA, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // Press Enter to accept the autofill suggestions. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_RETURN, false, false, false, false, |
| NotificationType::AUTOFILL_DID_FILL_FORM_DATA, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| // Test that a JavaScript onchange event is fired after auto-filling a form. |
| IN_PROC_BROWSER_TEST_F(AutofillTest, OnChangeAfterAutofill) { |
| CreateTestProfile(); |
| |
| const char* kOnChangeScript = |
| "<script>" |
| "focused_fired = false;" |
| "unfocused_fired = false;" |
| "changed_select_fired = false;" |
| "unchanged_select_fired = false;" |
| "document.getElementById('firstname').onchange = function() {" |
| " focused_fired = true;" |
| "};" |
| "document.getElementById('lastname').onchange = function() {" |
| " unfocused_fired = true;" |
| "};" |
| "document.getElementById('state').onchange = function() {" |
| " changed_select_fired = true;" |
| "};" |
| "document.getElementById('country').onchange = function() {" |
| " unchanged_select_fired = true;" |
| "};" |
| "document.getElementById('country').value = 'US';" |
| "</script>"; |
| |
| // Load the test page. |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), |
| GURL(std::string(kDataURIPrefix) + kTestFormString + kOnChangeScript))); |
| |
| // Invoke Autofill. |
| FocusFirstNameField(); |
| |
| // Start filling the first name field with "M" and wait for the popup to be |
| // shown. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_M, false, true, false, false, |
| NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_DOWN, false, false, false, false, |
| NotificationType::AUTOFILL_DID_FILL_FORM_DATA, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // Press Enter to accept the autofill suggestions. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( |
| browser(), ui::VKEY_RETURN, false, false, false, false, |
| NotificationType::AUTOFILL_DID_FILL_FORM_DATA, |
| Source<RenderViewHost>(render_view_host()))); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| |
| // The change event should have already fired for unfocused fields, both of |
| // <input> and of <select> type. However, it should not yet have fired for the |
| // focused field. |
| bool focused_fired = false; |
| bool unfocused_fired = false; |
| bool changed_select_fired = false; |
| bool unchanged_select_fired = false; |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( |
| render_view_host(), L"", |
| L"domAutomationController.send(focused_fired);", &focused_fired)); |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( |
| render_view_host(), L"", |
| L"domAutomationController.send(unfocused_fired);", &unfocused_fired)); |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( |
| render_view_host(), L"", |
| L"domAutomationController.send(changed_select_fired);", |
| &changed_select_fired)); |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( |
| render_view_host(), L"", |
| L"domAutomationController.send(unchanged_select_fired);", |
| &unchanged_select_fired)); |
| EXPECT_FALSE(focused_fired); |
| EXPECT_TRUE(unfocused_fired); |
| EXPECT_TRUE(changed_select_fired); |
| EXPECT_FALSE(unchanged_select_fired); |
| |
| // Unfocus the first name field. Its change event should fire. |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( |
| render_view_host(), L"", |
| L"document.getElementById('firstname').blur();" |
| L"domAutomationController.send(focused_fired);", &focused_fired)); |
| EXPECT_TRUE(focused_fired); |
| } |
| |
| // Test that we can autofill forms distinguished only by their |id| attribute. |
| IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillFormsDistinguishedById) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| const std::string kURL = |
| std::string(kDataURIPrefix) + kTestFormString + |
| "<script>" |
| "var mainForm = document.forms[0];" |
| "mainForm.id = 'mainForm';" |
| "var newForm = document.createElement('form');" |
| "newForm.action = mainForm.action;" |
| "newForm.method = mainForm.method;" |
| "newForm.id = 'newForm';" |
| "mainForm.parentNode.insertBefore(newForm, mainForm);" |
| "</script>"; |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), GURL(kURL))); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| // Test that form filling works after reloading the current page. |
| // This test brought to you by http://crbug.com/69204 |
| IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillAfterReload) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), |
| GURL(std::string(kDataURIPrefix) + kTestFormString))); |
| |
| // Reload the page. |
| TabContents* tab = |
| browser()->GetSelectedTabContentsWrapper()->tab_contents(); |
| tab->controller().Reload(false); |
| ui_test_utils::WaitForLoadStop(tab); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| // Test that autofill works after page translation. |
| IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillAfterTranslate) { |
| CreateTestProfile(); |
| |
| GURL url(std::string(kDataURIPrefix) + |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"fn\">なまえ</label>" |
| " <input type=\"text\" id=\"fn\"" |
| " onFocus=\"domAutomationController.send(true)\"" |
| " /><br />" |
| "<label for=\"ln\">みょうじ</label>" |
| " <input type=\"text\" id=\"ln\" /><br />" |
| "<label for=\"a1\">Address line 1:</label>" |
| " <input type=\"text\" id=\"a1\" /><br />" |
| "<label for=\"a2\">Address line 2:</label>" |
| " <input type=\"text\" id=\"a2\" /><br />" |
| "<label for=\"ci\">City:</label>" |
| " <input type=\"text\" id=\"ci\" /><br />" |
| "<label for=\"st\">State:</label>" |
| " <select id=\"st\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br />" |
| "<label for=\"z\">ZIP code:</label>" |
| " <input type=\"text\" id=\"z\" /><br />" |
| "<label for=\"co\">Country:</label>" |
| " <select id=\"co\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br />" |
| "<label for=\"ph\">Phone number:</label>" |
| " <input type=\"text\" id=\"ph\" /><br />" |
| "</form>"); |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| // Get translation bar. |
| render_view_host()->OnMessageReceived(ViewHostMsg_TranslateLanguageDetermined( |
| 0, "ja", true)); |
| TranslateInfoBarDelegate* infobar = browser()->GetSelectedTabContents()-> |
| GetInfoBarDelegateAt(0)->AsTranslateInfoBarDelegate(); |
| |
| ASSERT_TRUE(infobar != NULL); |
| EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type()); |
| |
| // Simulate translation button press. |
| infobar->Translate(); |
| |
| // Simulate the translate script being retrieved. |
| // Pass fake google.translate lib as the translate script. |
| SimulateURLFetch(true); |
| |
| // Simulate translation to kick onTranslateElementLoad. |
| // But right now, the call stucks here. |
| // Once click the text field, it starts again. |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( |
| render_view_host(), L"", |
| L"cr.googleTranslate.onTranslateElementLoad();")); |
| |
| // Simulate the render notifying the translation has been done. |
| ui_test_utils::WaitForNotification(NotificationType::PAGE_TRANSLATED); |
| |
| TryBasicFormFill(); |
| } |