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