1 // Copyright (c) 2012 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 "base/strings/string_util.h" 6 #include "base/strings/utf_string_conversions.h" 7 #include "chrome/test/base/chrome_render_view_test.h" 8 #include "components/autofill/content/common/autofill_messages.h" 9 #include "components/autofill/content/renderer/autofill_agent.h" 10 #include "components/autofill/content/renderer/form_autofill_util.h" 11 #include "components/autofill/content/renderer/password_autofill_agent.h" 12 #include "components/autofill/content/renderer/test_password_autofill_agent.h" 13 #include "components/autofill/core/common/form_data.h" 14 #include "components/autofill/core/common/form_field_data.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "third_party/WebKit/public/platform/WebString.h" 17 #include "third_party/WebKit/public/platform/WebVector.h" 18 #include "third_party/WebKit/public/web/WebDocument.h" 19 #include "third_party/WebKit/public/web/WebElement.h" 20 #include "third_party/WebKit/public/web/WebFormElement.h" 21 #include "third_party/WebKit/public/web/WebFrame.h" 22 #include "third_party/WebKit/public/web/WebInputElement.h" 23 #include "third_party/WebKit/public/web/WebNode.h" 24 #include "third_party/WebKit/public/web/WebView.h" 25 #include "ui/events/keycodes/keyboard_codes.h" 26 27 using autofill::PasswordForm; 28 using blink::WebDocument; 29 using blink::WebElement; 30 using blink::WebFrame; 31 using blink::WebInputElement; 32 using blink::WebString; 33 using blink::WebView; 34 35 namespace { 36 37 // The name of the username/password element in the form. 38 const char kUsernameName[] = "username"; 39 const char kPasswordName[] = "password"; 40 41 const char kAliceUsername[] = "alice"; 42 const char kAlicePassword[] = "password"; 43 const char kBobUsername[] = "bob"; 44 const char kBobPassword[] = "secret"; 45 const char kCarolUsername[] = "Carol"; 46 const char kCarolPassword[] = "test"; 47 const char kCarolAlternateUsername[] = "RealCarolUsername"; 48 49 50 const char kFormHTML[] = 51 "<FORM name='LoginTestForm' action='http://www.bidule.com'>" 52 " <INPUT type='text' id='username'/>" 53 " <INPUT type='password' id='password'/>" 54 " <INPUT type='submit' value='Login'/>" 55 "</FORM>"; 56 57 const char kVisibleFormHTML[] = 58 "<head> <style> form {display: inline;} </style> </head>" 59 "<body>" 60 " <form>" 61 " <div>" 62 " <input type='password' id='password'/>" 63 " </div>" 64 " </form>" 65 "</body>"; 66 67 const char kEmptyFormHTML[] = 68 "<head> <style> form {display: inline;} </style> </head>" 69 "<body> <form> </form> </body>"; 70 71 const char kNonVisibleFormHTML[] = 72 "<head> <style> form {display: none;} </style> </head>" 73 "<body>" 74 " <form>" 75 " <div>" 76 " <input type='password' id='password'/>" 77 " </div>" 78 " </form>" 79 "</body>"; 80 81 const char kEmptyWebpage[] = 82 "<html>" 83 " <head>" 84 " </head>" 85 " <body>" 86 " </body>" 87 "</html>"; 88 89 const char kRedirectionWebpage[] = 90 "<html>" 91 " <head>" 92 " <meta http-equiv='Content-Type' content='text/html'>" 93 " <title>Redirection page</title>" 94 " <script></script>" 95 " </head>" 96 " <body>" 97 " <script type='text/javascript'>" 98 " function test(){}" 99 " </script>" 100 " </body>" 101 "</html>"; 102 103 const char kSimpleWebpage[] = 104 "<html>" 105 " <head>" 106 " <meta charset='utf-8' />" 107 " <title>Title</title>" 108 " </head>" 109 " <body>" 110 " <form name='LoginTestForm'>" 111 " <input type='text' id='username'/>" 112 " <input type='password' id='password'/>" 113 " <input type='submit' value='Login'/>" 114 " </form>" 115 " </body>" 116 "</html>"; 117 118 const char kWebpageWithDynamicContent[] = 119 "<html>" 120 " <head>" 121 " <meta charset='utf-8' />" 122 " <title>Title</title>" 123 " </head>" 124 " <body>" 125 " <script type='text/javascript'>" 126 " function addParagraph() {" 127 " var p = document.createElement('p');" 128 " document.body.appendChild(p);" 129 " }" 130 " window.onload = addParagraph;" 131 " </script>" 132 " </body>" 133 "</html>"; 134 135 } // namespace 136 137 namespace autofill { 138 139 class PasswordAutofillAgentTest : public ChromeRenderViewTest { 140 public: 141 PasswordAutofillAgentTest() { 142 } 143 144 // Simulates the fill password form message being sent to the renderer. 145 // We use that so we don't have to make RenderView::OnFillPasswordForm() 146 // protected. 147 void SimulateOnFillPasswordForm( 148 const PasswordFormFillData& fill_data) { 149 AutofillMsg_FillPasswordForm msg(0, fill_data); 150 password_autofill_->OnMessageReceived(msg); 151 } 152 153 virtual void SetUp() { 154 ChromeRenderViewTest::SetUp(); 155 156 // Add a preferred login and an additional login to the FillData. 157 username1_ = ASCIIToUTF16(kAliceUsername); 158 password1_ = ASCIIToUTF16(kAlicePassword); 159 username2_ = ASCIIToUTF16(kBobUsername); 160 password2_ = ASCIIToUTF16(kBobPassword); 161 username3_ = ASCIIToUTF16(kCarolUsername); 162 password3_ = ASCIIToUTF16(kCarolPassword); 163 alternate_username3_ = ASCIIToUTF16(kCarolAlternateUsername); 164 165 FormFieldData username_field; 166 username_field.name = ASCIIToUTF16(kUsernameName); 167 username_field.value = username1_; 168 fill_data_.basic_data.fields.push_back(username_field); 169 170 FormFieldData password_field; 171 password_field.name = ASCIIToUTF16(kPasswordName); 172 password_field.value = password1_; 173 password_field.form_control_type = "password"; 174 fill_data_.basic_data.fields.push_back(password_field); 175 176 PasswordAndRealm password2; 177 password2.password = password2_; 178 fill_data_.additional_logins[username2_] = password2; 179 PasswordAndRealm password3; 180 password3.password = password3_; 181 fill_data_.additional_logins[username3_] = password3; 182 183 UsernamesCollectionKey key; 184 key.username = username3_; 185 key.password = password3_; 186 key.realm = "google.com"; 187 fill_data_.other_possible_usernames[key].push_back(alternate_username3_); 188 189 // We need to set the origin so it matches the frame URL and the action so 190 // it matches the form action, otherwise we won't autocomplete. 191 std::string origin("data:text/html;charset=utf-8,"); 192 origin += kFormHTML; 193 fill_data_.basic_data.origin = GURL(origin); 194 fill_data_.basic_data.action = GURL("http://www.bidule.com"); 195 196 LoadHTML(kFormHTML); 197 198 // Now retrieves the input elements so the test can access them. 199 WebDocument document = GetMainFrame()->document(); 200 WebElement element = 201 document.getElementById(WebString::fromUTF8(kUsernameName)); 202 ASSERT_FALSE(element.isNull()); 203 username_element_ = element.to<blink::WebInputElement>(); 204 element = document.getElementById(WebString::fromUTF8(kPasswordName)); 205 ASSERT_FALSE(element.isNull()); 206 password_element_ = element.to<blink::WebInputElement>(); 207 } 208 209 virtual void TearDown() { 210 username_element_.reset(); 211 password_element_.reset(); 212 ChromeRenderViewTest::TearDown(); 213 } 214 215 void ClearUsernameAndPasswordFields() { 216 username_element_.setValue(""); 217 username_element_.setAutofilled(false); 218 password_element_.setValue(""); 219 password_element_.setAutofilled(false); 220 } 221 222 void SimulateUsernameChangeForElement(const std::string& username, 223 bool move_caret_to_end, 224 WebFrame* input_frame, 225 WebInputElement& username_input) { 226 username_input.setValue(WebString::fromUTF8(username)); 227 // The field must have focus or AutofillAgent will think the 228 // change should be ignored. 229 while (!username_input.focused()) 230 input_frame->document().frame()->view()->advanceFocus(false); 231 if (move_caret_to_end) 232 username_input.setSelectionRange(username.length(), username.length()); 233 autofill_agent_->textFieldDidChange(username_input); 234 // Processing is delayed because of a WebKit bug, see 235 // PasswordAutocompleteManager::TextDidChangeInTextField() for details. 236 base::MessageLoop::current()->RunUntilIdle(); 237 } 238 239 void SimulateUsernameChange(const std::string& username, 240 bool move_caret_to_end) { 241 SimulateUsernameChangeForElement(username, move_caret_to_end, 242 GetMainFrame(), username_element_); 243 } 244 245 246 void SimulateKeyDownEvent(const WebInputElement& element, 247 ui::KeyboardCode key_code) { 248 blink::WebKeyboardEvent key_event; 249 key_event.windowsKeyCode = key_code; 250 autofill_agent_->textFieldDidReceiveKeyDown(element, key_event); 251 } 252 253 void CheckTextFieldsStateForElements(const WebInputElement& username_element, 254 const std::string& username, 255 bool username_autofilled, 256 const WebInputElement& password_element, 257 const std::string& password, 258 bool password_autofilled) { 259 EXPECT_EQ(username, 260 static_cast<std::string>(username_element.value().utf8())); 261 EXPECT_EQ(username_autofilled, username_element.isAutofilled()); 262 EXPECT_EQ(password, 263 static_cast<std::string>(password_element.value().utf8())); 264 EXPECT_EQ(password_autofilled, password_element.isAutofilled()); 265 } 266 267 void CheckTextFieldsState(const std::string& username, 268 bool username_autofilled, 269 const std::string& password, 270 bool password_autofilled) { 271 CheckTextFieldsStateForElements(username_element_, username, 272 username_autofilled, password_element_, 273 password, password_autofilled); 274 } 275 276 void CheckUsernameSelection(int start, int end) { 277 EXPECT_EQ(start, username_element_.selectionStart()); 278 EXPECT_EQ(end, username_element_.selectionEnd()); 279 } 280 281 base::string16 username1_; 282 base::string16 username2_; 283 base::string16 username3_; 284 base::string16 password1_; 285 base::string16 password2_; 286 base::string16 password3_; 287 base::string16 alternate_username3_; 288 PasswordFormFillData fill_data_; 289 290 WebInputElement username_element_; 291 WebInputElement password_element_; 292 293 private: 294 DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgentTest); 295 }; 296 297 // Tests that the password login is autocompleted as expected when the browser 298 // sends back the password info. 299 TEST_F(PasswordAutofillAgentTest, InitialAutocomplete) { 300 /* 301 * Right now we are not sending the message to the browser because we are 302 * loading a data URL and the security origin canAccessPasswordManager() 303 * returns false. May be we should mock URL loading to cirmcuvent this? 304 TODO(jcivelli): find a way to make the security origin not deny access to the 305 password manager and then reenable this code. 306 307 // The form has been loaded, we should have sent the browser a message about 308 // the form. 309 const IPC::Message* msg = render_thread_.sink().GetFirstMessageMatching( 310 AutofillHostMsg_PasswordFormsParsed::ID); 311 ASSERT_TRUE(msg != NULL); 312 313 Tuple1<std::vector<PasswordForm> > forms; 314 AutofillHostMsg_PasswordFormsParsed::Read(msg, &forms); 315 ASSERT_EQ(1U, forms.a.size()); 316 PasswordForm password_form = forms.a[0]; 317 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form.scheme); 318 EXPECT_EQ(ASCIIToUTF16(kUsernameName), password_form.username_element); 319 EXPECT_EQ(ASCIIToUTF16(kPasswordName), password_form.password_element); 320 */ 321 322 // Simulate the browser sending back the login info, it triggers the 323 // autocomplete. 324 SimulateOnFillPasswordForm(fill_data_); 325 326 // The username and password should have been autocompleted. 327 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); 328 } 329 330 // Tests that we correctly fill forms having an empty 'action' attribute. 331 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForEmptyAction) { 332 const char kEmptyActionFormHTML[] = 333 "<FORM name='LoginTestForm'>" 334 " <INPUT type='text' id='username'/>" 335 " <INPUT type='password' id='password'/>" 336 " <INPUT type='submit' value='Login'/>" 337 "</FORM>"; 338 LoadHTML(kEmptyActionFormHTML); 339 340 // Retrieve the input elements so the test can access them. 341 WebDocument document = GetMainFrame()->document(); 342 WebElement element = 343 document.getElementById(WebString::fromUTF8(kUsernameName)); 344 ASSERT_FALSE(element.isNull()); 345 username_element_ = element.to<blink::WebInputElement>(); 346 element = document.getElementById(WebString::fromUTF8(kPasswordName)); 347 ASSERT_FALSE(element.isNull()); 348 password_element_ = element.to<blink::WebInputElement>(); 349 350 // Set the expected form origin and action URLs. 351 std::string origin("data:text/html;charset=utf-8,"); 352 origin += kEmptyActionFormHTML; 353 fill_data_.basic_data.origin = GURL(origin); 354 fill_data_.basic_data.action = GURL(origin); 355 356 // Simulate the browser sending back the login info, it triggers the 357 // autocomplete. 358 SimulateOnFillPasswordForm(fill_data_); 359 360 // The username and password should have been autocompleted. 361 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); 362 } 363 364 // Tests that if a password is marked as readonly, neither field is autofilled 365 // on page load. 366 TEST_F(PasswordAutofillAgentTest, NoInitialAutocompleteForReadOnlyPassword) { 367 password_element_.setAttribute(WebString::fromUTF8("readonly"), 368 WebString::fromUTF8("true")); 369 370 // Simulate the browser sending back the login info, it triggers the 371 // autocomplete. 372 SimulateOnFillPasswordForm(fill_data_); 373 374 CheckTextFieldsState(std::string(), false, std::string(), false); 375 } 376 377 // Can still fill a password field if the username is set to a value that 378 // matches. 379 TEST_F(PasswordAutofillAgentTest, 380 AutocompletePasswordForReadonlyUsernameMatched) { 381 username_element_.setValue(username3_); 382 username_element_.setAttribute(WebString::fromUTF8("readonly"), 383 WebString::fromUTF8("true")); 384 385 // Filled even though username is not the preferred match. 386 SimulateOnFillPasswordForm(fill_data_); 387 CheckTextFieldsState(UTF16ToUTF8(username3_), false, 388 UTF16ToUTF8(password3_), true); 389 } 390 391 // If a username field is empty and readonly, don't autofill. 392 TEST_F(PasswordAutofillAgentTest, 393 NoAutocompletePasswordForReadonlyUsernameUnmatched) { 394 username_element_.setValue(WebString::fromUTF8("")); 395 username_element_.setAttribute(WebString::fromUTF8("readonly"), 396 WebString::fromUTF8("true")); 397 398 SimulateOnFillPasswordForm(fill_data_); 399 CheckTextFieldsState(std::string(), false, std::string(), false); 400 } 401 402 // Tests that having a non-matching username precludes the autocomplete. 403 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForFilledFieldUnmatched) { 404 username_element_.setValue(WebString::fromUTF8("bogus")); 405 406 // Simulate the browser sending back the login info, it triggers the 407 // autocomplete. 408 SimulateOnFillPasswordForm(fill_data_); 409 410 // Neither field should be autocompleted. 411 CheckTextFieldsState("bogus", false, std::string(), false); 412 } 413 414 // Don't try to complete a prefilled value even if it's a partial match 415 // to a username. 416 TEST_F(PasswordAutofillAgentTest, NoPartialMatchForPrefilledUsername) { 417 username_element_.setValue(WebString::fromUTF8("ali")); 418 419 SimulateOnFillPasswordForm(fill_data_); 420 421 CheckTextFieldsState("ali", false, std::string(), false); 422 } 423 424 TEST_F(PasswordAutofillAgentTest, InputWithNoForms) { 425 const char kNoFormInputs[] = 426 "<input type='text' id='username'/>" 427 "<input type='password' id='password'/>"; 428 LoadHTML(kNoFormInputs); 429 430 SimulateOnFillPasswordForm(fill_data_); 431 432 // Input elements that aren't in a <form> won't autofill. 433 CheckTextFieldsState(std::string(), false, std::string(), false); 434 } 435 436 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForTextFieldPasswords) { 437 const char kTextFieldPasswordFormHTML[] = 438 "<FORM name='LoginTestForm' action='http://www.bidule.com'>" 439 " <INPUT type='text' id='username'/>" 440 " <INPUT type='text' id='password'/>" 441 " <INPUT type='submit' value='Login'/>" 442 "</FORM>"; 443 LoadHTML(kTextFieldPasswordFormHTML); 444 445 // Retrieve the input elements so the test can access them. 446 WebDocument document = GetMainFrame()->document(); 447 WebElement element = 448 document.getElementById(WebString::fromUTF8(kUsernameName)); 449 ASSERT_FALSE(element.isNull()); 450 username_element_ = element.to<blink::WebInputElement>(); 451 element = document.getElementById(WebString::fromUTF8(kPasswordName)); 452 ASSERT_FALSE(element.isNull()); 453 password_element_ = element.to<blink::WebInputElement>(); 454 455 // Set the expected form origin URL. 456 std::string origin("data:text/html;charset=utf-8,"); 457 origin += kTextFieldPasswordFormHTML; 458 fill_data_.basic_data.origin = GURL(origin); 459 460 SimulateOnFillPasswordForm(fill_data_); 461 462 // Fields should still be empty. 463 CheckTextFieldsState(std::string(), false, std::string(), false); 464 } 465 466 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) { 467 const char kPasswordFieldUsernameFormHTML[] = 468 "<FORM name='LoginTestForm' action='http://www.bidule.com'>" 469 " <INPUT type='password' id='username'/>" 470 " <INPUT type='password' id='password'/>" 471 " <INPUT type='submit' value='Login'/>" 472 "</FORM>"; 473 LoadHTML(kPasswordFieldUsernameFormHTML); 474 475 // Retrieve the input elements so the test can access them. 476 WebDocument document = GetMainFrame()->document(); 477 WebElement element = 478 document.getElementById(WebString::fromUTF8(kUsernameName)); 479 ASSERT_FALSE(element.isNull()); 480 username_element_ = element.to<blink::WebInputElement>(); 481 element = document.getElementById(WebString::fromUTF8(kPasswordName)); 482 ASSERT_FALSE(element.isNull()); 483 password_element_ = element.to<blink::WebInputElement>(); 484 485 // Set the expected form origin URL. 486 std::string origin("data:text/html;charset=utf-8,"); 487 origin += kPasswordFieldUsernameFormHTML; 488 fill_data_.basic_data.origin = GURL(origin); 489 490 SimulateOnFillPasswordForm(fill_data_); 491 492 // Fields should still be empty. 493 CheckTextFieldsState(std::string(), false, std::string(), false); 494 } 495 496 // Tests that having a matching username does not preclude the autocomplete. 497 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) { 498 username_element_.setValue(WebString::fromUTF8(kAliceUsername)); 499 500 // Simulate the browser sending back the login info, it triggers the 501 // autocomplete. 502 SimulateOnFillPasswordForm(fill_data_); 503 504 // The username and password should have been autocompleted. 505 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); 506 } 507 508 // Tests that editing the password clears the autocompleted password field. 509 TEST_F(PasswordAutofillAgentTest, PasswordClearOnEdit) { 510 // Simulate the browser sending back the login info, it triggers the 511 // autocomplete. 512 SimulateOnFillPasswordForm(fill_data_); 513 514 // Simulate the user changing the username to some unknown username. 515 SimulateUsernameChange("alicia", true); 516 517 // The password should have been cleared. 518 CheckTextFieldsState("alicia", false, std::string(), false); 519 } 520 521 // Tests that we only autocomplete on focus lost and with a full username match 522 // when |wait_for_username| is true. 523 TEST_F(PasswordAutofillAgentTest, WaitUsername) { 524 // Simulate the browser sending back the login info. 525 fill_data_.wait_for_username = true; 526 SimulateOnFillPasswordForm(fill_data_); 527 528 // No auto-fill should have taken place. 529 CheckTextFieldsState(std::string(), false, std::string(), false); 530 531 // No autocomplete should happen when text is entered in the username. 532 SimulateUsernameChange("a", true); 533 CheckTextFieldsState("a", false, std::string(), false); 534 SimulateUsernameChange("al", true); 535 CheckTextFieldsState("al", false, std::string(), false); 536 SimulateUsernameChange(kAliceUsername, true); 537 CheckTextFieldsState(kAliceUsername, false, std::string(), false); 538 539 // Autocomplete should happen only when the username textfield is blurred with 540 // a full match. 541 username_element_.setValue("a"); 542 autofill_agent_->textFieldDidEndEditing(username_element_); 543 CheckTextFieldsState("a", false, std::string(), false); 544 username_element_.setValue("al"); 545 autofill_agent_->textFieldDidEndEditing(username_element_); 546 CheckTextFieldsState("al", false, std::string(), false); 547 username_element_.setValue("alices"); 548 autofill_agent_->textFieldDidEndEditing(username_element_); 549 CheckTextFieldsState("alices", false, std::string(), false); 550 username_element_.setValue(ASCIIToUTF16(kAliceUsername)); 551 autofill_agent_->textFieldDidEndEditing(username_element_); 552 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); 553 } 554 555 // Tests that inline autocompletion works properly. 556 TEST_F(PasswordAutofillAgentTest, InlineAutocomplete) { 557 // Simulate the browser sending back the login info. 558 SimulateOnFillPasswordForm(fill_data_); 559 560 // Clear the text fields to start fresh. 561 ClearUsernameAndPasswordFields(); 562 563 // Simulate the user typing in the first letter of 'alice', a stored username. 564 SimulateUsernameChange("a", true); 565 // Both the username and password text fields should reflect selection of the 566 // stored login. 567 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); 568 // And the selection should have been set to 'lice', the last 4 letters. 569 CheckUsernameSelection(1, 5); 570 571 // Now the user types the next letter of the same username, 'l'. 572 SimulateUsernameChange("al", true); 573 // Now the fields should have the same value, but the selection should have a 574 // different start value. 575 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); 576 CheckUsernameSelection(2, 5); 577 578 // Test that deleting does not trigger autocomplete. 579 SimulateKeyDownEvent(username_element_, ui::VKEY_BACK); 580 SimulateUsernameChange("alic", true); 581 CheckTextFieldsState("alic", false, std::string(), false); 582 CheckUsernameSelection(4, 4); // No selection. 583 // Reset the last pressed key to something other than backspace. 584 SimulateKeyDownEvent(username_element_, ui::VKEY_A); 585 586 // Now lets say the user goes astray from the stored username and types the 587 // letter 'f', spelling 'alf'. We don't know alf (that's just sad), so in 588 // practice the username should no longer be 'alice' and the selected range 589 // should be empty. 590 SimulateUsernameChange("alf", true); 591 CheckTextFieldsState("alf", false, std::string(), false); 592 CheckUsernameSelection(3, 3); // No selection. 593 594 // Ok, so now the user removes all the text and enters the letter 'b'. 595 SimulateUsernameChange("b", true); 596 // The username and password fields should match the 'bob' entry. 597 CheckTextFieldsState(kBobUsername, true, kBobPassword, true); 598 CheckUsernameSelection(1, 3); 599 600 // Then, the user again removes all the text and types an uppercase 'C'. 601 SimulateUsernameChange("C", true); 602 // The username and password fields should match the 'Carol' entry. 603 CheckTextFieldsState(kCarolUsername, true, kCarolPassword, true); 604 CheckUsernameSelection(1, 5); 605 // The user removes all the text and types a lowercase 'c'. We only 606 // want case-sensitive autocompletion, so the username and the selected range 607 // should be empty. 608 SimulateUsernameChange("c", true); 609 CheckTextFieldsState("c", false, std::string(), false); 610 CheckUsernameSelection(1, 1); 611 612 // Check that we complete other_possible_usernames as well. 613 SimulateUsernameChange("R", true); 614 CheckTextFieldsState(kCarolAlternateUsername, true, kCarolPassword, true); 615 CheckUsernameSelection(1, 17); 616 } 617 618 // Tests that selecting an item in the suggestion drop-down no-ops. 619 TEST_F(PasswordAutofillAgentTest, SuggestionSelect) { 620 // Simulate the browser sending back the login info. 621 SimulateOnFillPasswordForm(fill_data_); 622 623 // Clear the text fields to start fresh. 624 ClearUsernameAndPasswordFields(); 625 626 // To simulate accepting an item in the suggestion drop-down we just mimic 627 // what the WebView does: it sets the element value then calls 628 // didSelectAutofillSuggestion on the renderer. 629 autofill_agent_->didSelectAutofillSuggestion(username_element_, 630 ASCIIToUTF16(kAliceUsername), 631 blink::WebString(), 632 0); 633 // Autocomplete should not have kicked in. 634 CheckTextFieldsState(std::string(), false, std::string(), false); 635 } 636 637 TEST_F(PasswordAutofillAgentTest, IsWebNodeVisibleTest) { 638 blink::WebVector<blink::WebFormElement> forms1, forms2, forms3; 639 blink::WebFrame* frame; 640 641 LoadHTML(kVisibleFormHTML); 642 frame = GetMainFrame(); 643 frame->document().forms(forms1); 644 ASSERT_EQ(1u, forms1.size()); 645 EXPECT_TRUE(IsWebNodeVisible(forms1[0])); 646 647 LoadHTML(kEmptyFormHTML); 648 frame = GetMainFrame(); 649 frame->document().forms(forms2); 650 ASSERT_EQ(1u, forms2.size()); 651 EXPECT_FALSE(IsWebNodeVisible(forms2[0])); 652 653 LoadHTML(kNonVisibleFormHTML); 654 frame = GetMainFrame(); 655 frame->document().forms(forms3); 656 ASSERT_EQ(1u, forms3.size()); 657 EXPECT_FALSE(IsWebNodeVisible(forms3[0])); 658 } 659 660 TEST_F(PasswordAutofillAgentTest, SendPasswordFormsTest) { 661 render_thread_->sink().ClearMessages(); 662 LoadHTML(kVisibleFormHTML); 663 const IPC::Message* message = render_thread_->sink() 664 .GetFirstMessageMatching(AutofillHostMsg_PasswordFormsRendered::ID); 665 EXPECT_TRUE(message); 666 Tuple1<std::vector<autofill::PasswordForm> > param; 667 AutofillHostMsg_PasswordFormsRendered::Read(message, ¶m); 668 EXPECT_TRUE(param.a.size()); 669 670 render_thread_->sink().ClearMessages(); 671 LoadHTML(kEmptyFormHTML); 672 message = render_thread_->sink().GetFirstMessageMatching( 673 AutofillHostMsg_PasswordFormsRendered::ID); 674 EXPECT_TRUE(message); 675 AutofillHostMsg_PasswordFormsRendered::Read(message, ¶m); 676 EXPECT_FALSE(param.a.size()); 677 678 render_thread_->sink().ClearMessages(); 679 LoadHTML(kNonVisibleFormHTML); 680 message = render_thread_->sink().GetFirstMessageMatching( 681 AutofillHostMsg_PasswordFormsRendered::ID); 682 EXPECT_TRUE(message); 683 AutofillHostMsg_PasswordFormsRendered::Read(message, ¶m); 684 EXPECT_FALSE(param.a.size()); 685 } 686 687 TEST_F(PasswordAutofillAgentTest, SendPasswordFormsTest_Redirection) { 688 render_thread_->sink().ClearMessages(); 689 LoadHTML(kEmptyWebpage); 690 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 691 AutofillHostMsg_PasswordFormsRendered::ID)); 692 693 render_thread_->sink().ClearMessages(); 694 LoadHTML(kRedirectionWebpage); 695 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 696 AutofillHostMsg_PasswordFormsRendered::ID)); 697 698 render_thread_->sink().ClearMessages(); 699 LoadHTML(kSimpleWebpage); 700 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching( 701 AutofillHostMsg_PasswordFormsRendered::ID)); 702 703 render_thread_->sink().ClearMessages(); 704 LoadHTML(kWebpageWithDynamicContent); 705 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching( 706 AutofillHostMsg_PasswordFormsRendered::ID)); 707 } 708 709 // Tests that a password form in an iframe will not be filled in until a user 710 // interaction with the form. 711 TEST_F(PasswordAutofillAgentTest, IframeNoFillTest) { 712 const char kIframeName[] = "iframe"; 713 const char kWebpageWithIframeStart[] = 714 "<html>" 715 " <head>" 716 " <meta charset='utf-8' />" 717 " <title>Title</title>" 718 " </head>" 719 " <body>" 720 " <iframe id='iframe' src=\""; 721 const char kWebpageWithIframeEnd[] = 722 "\"></iframe>" 723 " </body>" 724 "</html>"; 725 726 std::string origin("data:text/html;charset=utf-8,"); 727 origin += kSimpleWebpage; 728 729 std::string page_html(kWebpageWithIframeStart); 730 page_html += origin; 731 page_html += kWebpageWithIframeEnd; 732 733 LoadHTML(page_html.c_str()); 734 735 // Set the expected form origin and action URLs. 736 fill_data_.basic_data.origin = GURL(origin); 737 fill_data_.basic_data.action = GURL(origin); 738 739 SimulateOnFillPasswordForm(fill_data_); 740 741 // Retrieve the input elements from the iframe since that is where we want to 742 // test the autofill. 743 WebFrame* iframe = GetMainFrame()->findChildByName(kIframeName); 744 ASSERT_TRUE(iframe); 745 WebDocument document = iframe->document(); 746 747 WebElement username_element = document.getElementById(kUsernameName); 748 WebElement password_element = document.getElementById(kPasswordName); 749 ASSERT_FALSE(username_element.isNull()); 750 ASSERT_FALSE(password_element.isNull()); 751 752 WebInputElement username_input = username_element.to<WebInputElement>(); 753 WebInputElement password_input = password_element.to<WebInputElement>(); 754 ASSERT_FALSE(username_element.isNull()); 755 756 CheckTextFieldsStateForElements(username_input, "", false, 757 password_input, "", false); 758 759 // Simulate the user typing in the username in the iframe, which should cause 760 // an autofill. 761 SimulateUsernameChangeForElement(kAliceUsername, true, 762 iframe, username_input); 763 764 CheckTextFieldsStateForElements(username_input, kAliceUsername, true, 765 password_input, kAlicePassword, true); 766 } 767 768 } // namespace autofill 769