// Copyright (c) 2012 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 #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/autofill/personal_data_manager_factory.h" #include "chrome/browser/autofill/personal_data_manager_observer.h" #include "chrome/browser/infobars/infobar_tab_helper.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/chrome_notification_types.h" #include "chrome/common/render_messages.h" #include "chrome/renderer/translate_helper.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/test/mock_render_process_host.h" #include "content/test/test_renderer_host.h" #include "content/test/test_url_fetcher_factory.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/keycodes/keyboard_codes.h" using content::RenderViewHost; using content::RenderViewHostTester; using content::WebContents; static const char* kDataURIPrefix = "data:text/html;charset=utf-8,"; static const char* kTestFormString = "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "
"; class WindowedPersonalDataManagerObserver : public PersonalDataManagerObserver { public: WindowedPersonalDataManagerObserver() : personal_data_changed_(false), has_run_message_loop_(false) { } void Wait() { if (!personal_data_changed_) { has_run_message_loop_ = true; ui_test_utils::RunMessageLoop(); } } void OnPersonalDataChanged() OVERRIDE { if (has_run_message_loop_) { MessageLoopForUI::current()->Quit(); has_run_message_loop_ = false; } personal_data_changed_ = true; } private: bool personal_data_changed_; bool has_run_message_loop_; }; class AutofillTest : public InProcessBrowserTest { protected: AutofillTest() { EnableDOMAutomation(); } 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"); PersonalDataManager* personal_data_manager = PersonalDataManagerFactory::GetForProfile(browser()->profile()); ASSERT_TRUE(personal_data_manager); WindowedPersonalDataManagerObserver observer; personal_data_manager->SetObserver(&observer); personal_data_manager->AddProfile(profile); // AddProfile is asynchronous. Wait for it to finish before continuing the // tests. observer.Wait(); personal_data_manager->RemoveObserver(&observer); } void ExpectFieldValue(const std::wstring& field_name, const std::string& expected_value) { std::string value; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( browser()->GetSelectedWebContents()->GetRenderViewHost(), L"", L"window.domAutomationController.send(" L"document.getElementById('" + field_name + L"').value);", &value)); EXPECT_EQ(expected_value, value); } RenderViewHost* render_view_host() { return browser()->GetSelectedWebContents()->GetRenderViewHost(); } 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->set_url(fetcher->GetOriginalURL()); fetcher->set_status(status); fetcher->set_response_code(success ? 200 : 500); fetcher->SetResponseString(script); fetcher->delegate()->OnURLFetchComplete(fetcher); } void FocusFirstNameField() { LOG(WARNING) << "Clicking on the tab."; ui_test_utils::SimulateMouseClick(browser()->GetSelectedWebContents()); LOG(WARNING) << "Focusing the first name field."; bool result = false; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( render_view_host(), L"", L"if (document.readyState === 'complete')" L" document.getElementById('firstname').focus();" L"else" L" domAutomationController.send(false);", &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 SendKeyAndWait(ui::KeyboardCode key, int notification_type) { ui_test_utils::WindowedNotificationObserver observer( notification_type, content::Source(render_view_host())); ui_test_utils::SimulateKeyPress( browser()->GetSelectedWebContents(), key, false, false, false, false); observer.Wait(); } void TryBasicFormFill() { FocusFirstNameField(); // Start filling the first name field with "M" and wait for the popup to be // shown. LOG(WARNING) << "Typing 'M' to bring up the Autofill popup."; SendKeyAndWait( ui::VKEY_M, chrome::NOTIFICATION_AUTOFILL_DID_SHOW_SUGGESTIONS); // Press the down arrow to select the suggestion and preview the autofilled // form. LOG(WARNING) << "Simulating down arrow press to initiate Autofill preview."; SendKeyAndWait( ui::VKEY_DOWN, chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA); // 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. LOG(WARNING) << "Simulating Return press to fill the form."; SendKeyAndWait( ui::VKEY_RETURN, chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA); // 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_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. SendKeyAndWait( ui::VKEY_DOWN, chrome::NOTIFICATION_AUTOFILL_DID_SHOW_SUGGESTIONS); // Press the down arrow to select the suggestion and preview the autofilled // form. SendKeyAndWait( ui::VKEY_DOWN, chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA); // Press Enter to accept the autofill suggestions. SendKeyAndWait( ui::VKEY_RETURN, chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA); // 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 = ""; // 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. SendKeyAndWait( ui::VKEY_M, chrome::NOTIFICATION_AUTOFILL_DID_SHOW_SUGGESTIONS); // Press the down arrow to select the suggestion and preview the autofilled // form. SendKeyAndWait( ui::VKEY_DOWN, chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA); // Press Enter to accept the autofill suggestions. SendKeyAndWait( ui::VKEY_RETURN, chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA); // The form should be filled. ExpectFilledTestForm(); // The change event should have already fired for unfocused fields, both of // and of
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" ""))); // Invoke Autofill. TryBasicFormFill(); ExpectFieldValue(L"state_freeform", ""); } #if defined(OS_WIN) // Has been observed to fail on windows. crbug.com/100062 #define MAYBE_AutofillFormWithNonAutofillableField \ DISABLED_AutofillFormWithNonAutofillableField #else #define MAYBE_AutofillFormWithNonAutofillableField \ AutofillFormWithNonAutofillableField #endif // Test that we properly autofill forms with non-autofillable fields. IN_PROC_BROWSER_TEST_F(AutofillTest, MAYBE_AutofillFormWithNonAutofillableField) { 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) + "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "
"))); // Invoke Autofill. TryBasicFormFill(); } // Test that we can Autofill dynamically generated forms. IN_PROC_BROWSER_TEST_F(AutofillTest, DynamicFormFill) { 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) + "
" ""))); // Dynamically construct the form. ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(render_view_host(), L"", L"BuildForm();")); // Invoke Autofill. TryBasicFormFill(); } // Test that form filling works after reloading the current page. // This test brought to you by http://crbug.com/69204 #if defined(OS_MACOSX) // Sometimes times out on Mac: http://crbug.com/81451 // Currently enabled for logging. #define MAYBE_AutofillAfterReload AutofillAfterReload #else #define MAYBE_AutofillAfterReload AutofillAfterReload #endif IN_PROC_BROWSER_TEST_F(AutofillTest, MAYBE_AutofillAfterReload) { LOG(WARNING) << "Creating test profile."; CreateTestProfile(); // Load the test page. LOG(WARNING) << "Bringing browser window to front."; ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); LOG(WARNING) << "Navigating to URL."; ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), GURL(std::string(kDataURIPrefix) + kTestFormString))); // Reload the page. LOG(WARNING) << "Reloading the page."; WebContents* tab = browser()->GetSelectedTabContentsWrapper()->web_contents(); tab->GetController().Reload(false); ui_test_utils::WaitForLoadStop(tab); // Invoke Autofill. LOG(WARNING) << "Trying to fill the form."; TryBasicFormFill(); } #if defined(OS_MACOSX) || defined(OS_CHROMEOS) // Test that autofill works after page translation. // http://crbug.com/81451 IN_PROC_BROWSER_TEST_F(AutofillTest, DISABLED_AutofillAfterTranslate) { #else IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillAfterTranslate) { #endif CreateTestProfile(); GURL url(std::string(kDataURIPrefix) + "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "" "
" "
"); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); // Get translation bar. RenderViewHostTester::TestOnMessageReceived( render_view_host(), ChromeViewHostMsg_TranslateLanguageDetermined(0, "ja", true)); TranslateInfoBarDelegate* infobar = browser()->GetSelectedTabContentsWrapper()->infobar_tab_helper()-> 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); ui_test_utils::WindowedNotificationObserver translation_observer( chrome::NOTIFICATION_PAGE_TRANSLATED, content::NotificationService::AllSources()); // 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. translation_observer.Wait(); TryBasicFormFill(); }