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.
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 "components/autofill/core/common/password_autofill_util.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/WebKit/public/platform/WebString.h"
18 #include "third_party/WebKit/public/platform/WebVector.h"
19 #include "third_party/WebKit/public/web/WebDocument.h"
20 #include "third_party/WebKit/public/web/WebElement.h"
21 #include "third_party/WebKit/public/web/WebFormElement.h"
22 #include "third_party/WebKit/public/web/WebFrame.h"
23 #include "third_party/WebKit/public/web/WebInputElement.h"
24 #include "third_party/WebKit/public/web/WebNode.h"
25 #include "third_party/WebKit/public/web/WebView.h"
26 #include "ui/events/keycodes/keyboard_codes.h"
28 using autofill::PasswordForm;
29 using base::ASCIIToUTF16;
30 using base::UTF16ToUTF8;
31 using blink::WebDocument;
32 using blink::WebElement;
33 using blink::WebFrame;
34 using blink::WebInputElement;
35 using blink::WebString;
40 // The name of the username/password element in the form.
41 const char kUsernameName[] = "username";
42 const char kPasswordName[] = "password";
44 const char kAliceUsername[] = "alice";
45 const char kAlicePassword[] = "password";
46 const char kBobUsername[] = "bob";
47 const char kBobPassword[] = "secret";
48 const char kCarolUsername[] = "Carol";
49 const char kCarolPassword[] = "test";
50 const char kCarolAlternateUsername[] = "RealCarolUsername";
53 const char kFormHTML[] =
54 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
55 " <INPUT type='text' id='username'/>"
56 " <INPUT type='password' id='password'/>"
57 " <INPUT type='submit' value='Login'/>"
60 const char kVisibleFormHTML[] =
61 "<head> <style> form {display: inline;} </style> </head>"
65 " <input type='password' id='password'/>"
70 const char kEmptyFormHTML[] =
71 "<head> <style> form {display: inline;} </style> </head>"
72 "<body> <form> </form> </body>";
74 const char kNonVisibleFormHTML[] =
75 "<head> <style> form {display: none;} </style> </head>"
79 " <input type='password' id='password'/>"
84 const char kEmptyWebpage[] =
92 const char kRedirectionWebpage[] =
95 " <meta http-equiv='Content-Type' content='text/html'>"
96 " <title>Redirection page</title>"
100 " <script type='text/javascript'>"
106 const char kSimpleWebpage[] =
109 " <meta charset='utf-8' />"
110 " <title>Title</title>"
113 " <form name='LoginTestForm'>"
114 " <input type='text' id='username'/>"
115 " <input type='password' id='password'/>"
116 " <input type='submit' value='Login'/>"
121 const char kWebpageWithDynamicContent[] =
124 " <meta charset='utf-8' />"
125 " <title>Title</title>"
128 " <script type='text/javascript'>"
129 " function addParagraph() {"
130 " var p = document.createElement('p');"
131 " document.body.appendChild(p);"
133 " window.onload = addParagraph;"
138 const char kJavaScriptClick[] =
139 "var event = new MouseEvent('click', {"
142 " 'cancelable': true"
144 "var form = document.getElementById('myform1');"
145 "form.dispatchEvent(event);"
146 "console.log('clicked!');";
148 const char kOnChangeDetectionScript[] =
150 " usernameOnchangeCalled = false;"
151 " passwordOnchangeCalled = false;"
152 " document.getElementById('username').onchange = function() {"
153 " usernameOnchangeCalled = true;"
155 " document.getElementById('password').onchange = function() {"
156 " passwordOnchangeCalled = true;"
164 class PasswordAutofillAgentTest : public ChromeRenderViewTest {
166 PasswordAutofillAgentTest() {
169 // Simulates the fill password form message being sent to the renderer.
170 // We use that so we don't have to make RenderView::OnFillPasswordForm()
172 void SimulateOnFillPasswordForm(
173 const PasswordFormFillData& fill_data) {
174 AutofillMsg_FillPasswordForm msg(0, fill_data);
175 password_autofill_->OnMessageReceived(msg);
178 virtual void SetUp() {
179 ChromeRenderViewTest::SetUp();
181 // Add a preferred login and an additional login to the FillData.
182 username1_ = ASCIIToUTF16(kAliceUsername);
183 password1_ = ASCIIToUTF16(kAlicePassword);
184 username2_ = ASCIIToUTF16(kBobUsername);
185 password2_ = ASCIIToUTF16(kBobPassword);
186 username3_ = ASCIIToUTF16(kCarolUsername);
187 password3_ = ASCIIToUTF16(kCarolPassword);
188 alternate_username3_ = ASCIIToUTF16(kCarolAlternateUsername);
190 FormFieldData username_field;
191 username_field.name = ASCIIToUTF16(kUsernameName);
192 username_field.value = username1_;
193 fill_data_.basic_data.fields.push_back(username_field);
195 FormFieldData password_field;
196 password_field.name = ASCIIToUTF16(kPasswordName);
197 password_field.value = password1_;
198 password_field.form_control_type = "password";
199 fill_data_.basic_data.fields.push_back(password_field);
201 PasswordAndRealm password2;
202 password2.password = password2_;
203 fill_data_.additional_logins[username2_] = password2;
204 PasswordAndRealm password3;
205 password3.password = password3_;
206 fill_data_.additional_logins[username3_] = password3;
208 UsernamesCollectionKey key;
209 key.username = username3_;
210 key.password = password3_;
211 key.realm = "google.com";
212 fill_data_.other_possible_usernames[key].push_back(alternate_username3_);
214 // We need to set the origin so it matches the frame URL and the action so
215 // it matches the form action, otherwise we won't autocomplete.
216 UpdateOriginForHTML(kFormHTML);
217 fill_data_.basic_data.action = GURL("http://www.bidule.com");
221 // Now retrieve the input elements so the test can access them.
222 UpdateUsernameAndPasswordElements();
225 virtual void TearDown() {
226 username_element_.reset();
227 password_element_.reset();
228 ChromeRenderViewTest::TearDown();
231 void UpdateOriginForHTML(const std::string& html) {
232 std::string origin = "data:text/html;charset=utf-8," + html;
233 fill_data_.basic_data.origin = GURL(origin);
236 void UpdateUsernameAndPasswordElements() {
237 WebDocument document = GetMainFrame()->document();
239 document.getElementById(WebString::fromUTF8(kUsernameName));
240 ASSERT_FALSE(element.isNull());
241 username_element_ = element.to<blink::WebInputElement>();
242 element = document.getElementById(WebString::fromUTF8(kPasswordName));
243 ASSERT_FALSE(element.isNull());
244 password_element_ = element.to<blink::WebInputElement>();
247 void ClearUsernameAndPasswordFields() {
248 username_element_.setValue("");
249 username_element_.setAutofilled(false);
250 password_element_.setValue("");
251 password_element_.setAutofilled(false);
254 void SimulateUsernameChangeForElement(const std::string& username,
255 bool move_caret_to_end,
256 WebFrame* input_frame,
257 WebInputElement& username_input) {
258 username_input.setValue(WebString::fromUTF8(username));
259 // The field must have focus or AutofillAgent will think the
260 // change should be ignored.
261 while (!username_input.focused())
262 input_frame->document().frame()->view()->advanceFocus(false);
263 if (move_caret_to_end)
264 username_input.setSelectionRange(username.length(), username.length());
265 autofill_agent_->textFieldDidChange(username_input);
266 // Processing is delayed because of a Blink bug:
267 // https://bugs.webkit.org/show_bug.cgi?id=16976
268 // See PasswordAutofillAgent::TextDidChangeInTextField() for details.
270 // Autocomplete will trigger a style recalculation when we put up the next
271 // frame, but we don't want to wait that long. Instead, trigger a style
272 // recalcuation manually after TextFieldDidChangeImpl runs.
273 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
274 &PasswordAutofillAgentTest::LayoutMainFrame, base::Unretained(this)));
276 base::MessageLoop::current()->RunUntilIdle();
279 void LayoutMainFrame() {
280 GetMainFrame()->view()->layout();
283 void SimulateUsernameChange(const std::string& username,
284 bool move_caret_to_end) {
285 SimulateUsernameChangeForElement(username, move_caret_to_end,
286 GetMainFrame(), username_element_);
289 // Tests that no suggestion popup is generated when the username_element_ is
291 void ExpectNoSuggestionsPopup() {
292 // The first test below ensures that the suggestions have been handled by
293 // the password_autofill_agent, even though autocomplete='off' is set. The
294 // second check ensures that, although handled, no "show suggestions" IPC to
295 // the browser was generated.
297 // This is interesting in the specific case of an autocomplete='off' form
298 // that also has a remembered username and password
299 // (http://crbug.com/326679). To fix the DCHECK that this case used to hit,
300 // |true| is returned from ShowSuggestions for all forms with valid
301 // usersnames that are autocomplete='off', prentending that a selection box
302 // has been shown to the user. Of course, it hasn't, so a message is never
303 // sent to the browser on acceptance, and the DCHECK isn't hit (and nothing
306 // These tests only make sense in the context of not ignoring
307 // autocomplete='off', so only test them if the disable autocomplete='off'
308 // flag is not enabled.
309 // TODO(jww): Remove this function and callers once autocomplete='off' is
310 // permanently ignored.
311 if (!ShouldIgnoreAutocompleteOffForPasswordFields()) {
312 EXPECT_TRUE(autofill_agent_->password_autofill_agent_->ShowSuggestions(
315 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
316 AutofillHostMsg_ShowPasswordSuggestions::ID));
320 void SimulateKeyDownEvent(const WebInputElement& element,
321 ui::KeyboardCode key_code) {
322 blink::WebKeyboardEvent key_event;
323 key_event.windowsKeyCode = key_code;
324 autofill_agent_->textFieldDidReceiveKeyDown(element, key_event);
327 void CheckTextFieldsStateForElements(const WebInputElement& username_element,
328 const std::string& username,
329 bool username_autofilled,
330 const WebInputElement& password_element,
331 const std::string& password,
332 bool password_autofilled,
333 bool checkSuggestedValue = true) {
335 static_cast<std::string>(username_element.value().utf8()));
336 EXPECT_EQ(username_autofilled, username_element.isAutofilled());
338 static_cast<std::string>(
339 checkSuggestedValue ? password_element.suggestedValue().utf8()
340 : password_element.value().utf8()));
341 EXPECT_EQ(password_autofilled, password_element.isAutofilled());
344 // Checks the DOM-accessible value of the username element and the
345 // *suggested* value of the password element.
346 void CheckTextFieldsState(const std::string& username,
347 bool username_autofilled,
348 const std::string& password,
349 bool password_autofilled) {
350 CheckTextFieldsStateForElements(username_element_, username,
351 username_autofilled, password_element_,
352 password, password_autofilled);
355 // Checks the DOM-accessible value of the username element and the
356 // DOM-accessible value of the password element.
357 void CheckTextFieldsDOMState(const std::string& username,
358 bool username_autofilled,
359 const std::string& password,
360 bool password_autofilled) {
361 CheckTextFieldsStateForElements(username_element_,
370 void CheckUsernameSelection(int start, int end) {
371 EXPECT_EQ(start, username_element_.selectionStart());
372 EXPECT_EQ(end, username_element_.selectionEnd());
375 base::string16 username1_;
376 base::string16 username2_;
377 base::string16 username3_;
378 base::string16 password1_;
379 base::string16 password2_;
380 base::string16 password3_;
381 base::string16 alternate_username3_;
382 PasswordFormFillData fill_data_;
384 WebInputElement username_element_;
385 WebInputElement password_element_;
388 DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgentTest);
391 // Tests that the password login is autocompleted as expected when the browser
392 // sends back the password info.
393 TEST_F(PasswordAutofillAgentTest, InitialAutocomplete) {
395 * Right now we are not sending the message to the browser because we are
396 * loading a data URL and the security origin canAccessPasswordManager()
397 * returns false. May be we should mock URL loading to cirmcuvent this?
398 TODO(jcivelli): find a way to make the security origin not deny access to the
399 password manager and then reenable this code.
401 // The form has been loaded, we should have sent the browser a message about
403 const IPC::Message* msg = render_thread_.sink().GetFirstMessageMatching(
404 AutofillHostMsg_PasswordFormsParsed::ID);
405 ASSERT_TRUE(msg != NULL);
407 Tuple1<std::vector<PasswordForm> > forms;
408 AutofillHostMsg_PasswordFormsParsed::Read(msg, &forms);
409 ASSERT_EQ(1U, forms.a.size());
410 PasswordForm password_form = forms.a[0];
411 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form.scheme);
412 EXPECT_EQ(ASCIIToUTF16(kUsernameName), password_form.username_element);
413 EXPECT_EQ(ASCIIToUTF16(kPasswordName), password_form.password_element);
416 // Simulate the browser sending back the login info, it triggers the
418 SimulateOnFillPasswordForm(fill_data_);
420 // The username and password should have been autocompleted.
421 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
424 // Tests that we correctly fill forms having an empty 'action' attribute.
425 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForEmptyAction) {
426 const char kEmptyActionFormHTML[] =
427 "<FORM name='LoginTestForm'>"
428 " <INPUT type='text' id='username'/>"
429 " <INPUT type='password' id='password'/>"
430 " <INPUT type='submit' value='Login'/>"
432 LoadHTML(kEmptyActionFormHTML);
434 // Retrieve the input elements so the test can access them.
435 WebDocument document = GetMainFrame()->document();
437 document.getElementById(WebString::fromUTF8(kUsernameName));
438 ASSERT_FALSE(element.isNull());
439 username_element_ = element.to<blink::WebInputElement>();
440 element = document.getElementById(WebString::fromUTF8(kPasswordName));
441 ASSERT_FALSE(element.isNull());
442 password_element_ = element.to<blink::WebInputElement>();
444 // Set the expected form origin and action URLs.
445 UpdateOriginForHTML(kEmptyActionFormHTML);
446 fill_data_.basic_data.action = fill_data_.basic_data.origin;
448 // Simulate the browser sending back the login info, it triggers the
450 SimulateOnFillPasswordForm(fill_data_);
452 // The username and password should have been autocompleted.
453 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
456 // Tests that if a password is marked as readonly, neither field is autofilled
458 TEST_F(PasswordAutofillAgentTest, NoInitialAutocompleteForReadOnlyPassword) {
459 password_element_.setAttribute(WebString::fromUTF8("readonly"),
460 WebString::fromUTF8("true"));
462 // Simulate the browser sending back the login info, it triggers the
464 SimulateOnFillPasswordForm(fill_data_);
466 CheckTextFieldsState(std::string(), false, std::string(), false);
469 // Can still fill a password field if the username is set to a value that
471 TEST_F(PasswordAutofillAgentTest,
472 AutocompletePasswordForReadonlyUsernameMatched) {
473 username_element_.setValue(username3_);
474 username_element_.setAttribute(WebString::fromUTF8("readonly"),
475 WebString::fromUTF8("true"));
477 // Filled even though username is not the preferred match.
478 SimulateOnFillPasswordForm(fill_data_);
479 CheckTextFieldsState(UTF16ToUTF8(username3_), false,
480 UTF16ToUTF8(password3_), true);
483 // If a username field is empty and readonly, don't autofill.
484 TEST_F(PasswordAutofillAgentTest,
485 NoAutocompletePasswordForReadonlyUsernameUnmatched) {
486 username_element_.setValue(WebString::fromUTF8(""));
487 username_element_.setAttribute(WebString::fromUTF8("readonly"),
488 WebString::fromUTF8("true"));
490 SimulateOnFillPasswordForm(fill_data_);
491 CheckTextFieldsState(std::string(), false, std::string(), false);
494 // Tests that having a non-matching username precludes the autocomplete.
495 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForFilledFieldUnmatched) {
496 username_element_.setValue(WebString::fromUTF8("bogus"));
498 // Simulate the browser sending back the login info, it triggers the
500 SimulateOnFillPasswordForm(fill_data_);
502 // Neither field should be autocompleted.
503 CheckTextFieldsState("bogus", false, std::string(), false);
506 // Don't try to complete a prefilled value even if it's a partial match
508 TEST_F(PasswordAutofillAgentTest, NoPartialMatchForPrefilledUsername) {
509 username_element_.setValue(WebString::fromUTF8("ali"));
511 SimulateOnFillPasswordForm(fill_data_);
513 CheckTextFieldsState("ali", false, std::string(), false);
516 TEST_F(PasswordAutofillAgentTest, InputWithNoForms) {
517 const char kNoFormInputs[] =
518 "<input type='text' id='username'/>"
519 "<input type='password' id='password'/>";
520 LoadHTML(kNoFormInputs);
522 SimulateOnFillPasswordForm(fill_data_);
524 // Input elements that aren't in a <form> won't autofill.
525 CheckTextFieldsState(std::string(), false, std::string(), false);
528 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForTextFieldPasswords) {
529 const char kTextFieldPasswordFormHTML[] =
530 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
531 " <INPUT type='text' id='username'/>"
532 " <INPUT type='text' id='password'/>"
533 " <INPUT type='submit' value='Login'/>"
535 LoadHTML(kTextFieldPasswordFormHTML);
537 // Retrieve the input elements so the test can access them.
538 WebDocument document = GetMainFrame()->document();
540 document.getElementById(WebString::fromUTF8(kUsernameName));
541 ASSERT_FALSE(element.isNull());
542 username_element_ = element.to<blink::WebInputElement>();
543 element = document.getElementById(WebString::fromUTF8(kPasswordName));
544 ASSERT_FALSE(element.isNull());
545 password_element_ = element.to<blink::WebInputElement>();
547 // Set the expected form origin URL.
548 UpdateOriginForHTML(kTextFieldPasswordFormHTML);
550 SimulateOnFillPasswordForm(fill_data_);
552 // Fields should still be empty.
553 CheckTextFieldsState(std::string(), false, std::string(), false);
556 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) {
557 const char kPasswordFieldUsernameFormHTML[] =
558 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
559 " <INPUT type='password' id='username'/>"
560 " <INPUT type='password' id='password'/>"
561 " <INPUT type='submit' value='Login'/>"
563 LoadHTML(kPasswordFieldUsernameFormHTML);
565 // Retrieve the input elements so the test can access them.
566 WebDocument document = GetMainFrame()->document();
568 document.getElementById(WebString::fromUTF8(kUsernameName));
569 ASSERT_FALSE(element.isNull());
570 username_element_ = element.to<blink::WebInputElement>();
571 element = document.getElementById(WebString::fromUTF8(kPasswordName));
572 ASSERT_FALSE(element.isNull());
573 password_element_ = element.to<blink::WebInputElement>();
575 // Set the expected form origin URL.
576 UpdateOriginForHTML(kPasswordFieldUsernameFormHTML);
578 SimulateOnFillPasswordForm(fill_data_);
580 // Fields should still be empty.
581 CheckTextFieldsState(std::string(), false, std::string(), false);
584 // Tests that having a matching username does not preclude the autocomplete.
585 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) {
586 username_element_.setValue(WebString::fromUTF8(kAliceUsername));
588 // Simulate the browser sending back the login info, it triggers the
590 SimulateOnFillPasswordForm(fill_data_);
592 // The username and password should have been autocompleted.
593 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
596 // Tests that editing the password clears the autocompleted password field.
597 TEST_F(PasswordAutofillAgentTest, PasswordClearOnEdit) {
598 // Simulate the browser sending back the login info, it triggers the
600 SimulateOnFillPasswordForm(fill_data_);
602 // Simulate the user changing the username to some unknown username.
603 SimulateUsernameChange("alicia", true);
605 // The password should have been cleared.
606 CheckTextFieldsState("alicia", false, std::string(), false);
609 // Tests that we only autocomplete on focus lost and with a full username match
610 // when |wait_for_username| is true.
611 TEST_F(PasswordAutofillAgentTest, WaitUsername) {
612 // Simulate the browser sending back the login info.
613 fill_data_.wait_for_username = true;
614 SimulateOnFillPasswordForm(fill_data_);
616 // No auto-fill should have taken place.
617 CheckTextFieldsState(std::string(), false, std::string(), false);
619 // No autocomplete should happen when text is entered in the username.
620 SimulateUsernameChange("a", true);
621 CheckTextFieldsState("a", false, std::string(), false);
622 SimulateUsernameChange("al", true);
623 CheckTextFieldsState("al", false, std::string(), false);
624 SimulateUsernameChange(kAliceUsername, true);
625 CheckTextFieldsState(kAliceUsername, false, std::string(), false);
627 // Autocomplete should happen only when the username textfield is blurred with
629 username_element_.setValue("a");
630 autofill_agent_->textFieldDidEndEditing(username_element_);
631 CheckTextFieldsState("a", false, std::string(), false);
632 username_element_.setValue("al");
633 autofill_agent_->textFieldDidEndEditing(username_element_);
634 CheckTextFieldsState("al", false, std::string(), false);
635 username_element_.setValue("alices");
636 autofill_agent_->textFieldDidEndEditing(username_element_);
637 CheckTextFieldsState("alices", false, std::string(), false);
638 username_element_.setValue(ASCIIToUTF16(kAliceUsername));
639 autofill_agent_->textFieldDidEndEditing(username_element_);
640 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
643 // Tests that inline autocompletion works properly.
644 TEST_F(PasswordAutofillAgentTest, InlineAutocomplete) {
645 // Simulate the browser sending back the login info.
646 SimulateOnFillPasswordForm(fill_data_);
648 // Clear the text fields to start fresh.
649 ClearUsernameAndPasswordFields();
651 // Simulate the user typing in the first letter of 'alice', a stored username.
652 SimulateUsernameChange("a", true);
653 // Both the username and password text fields should reflect selection of the
655 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
656 // And the selection should have been set to 'lice', the last 4 letters.
657 CheckUsernameSelection(1, 5);
659 // Now the user types the next letter of the same username, 'l'.
660 SimulateUsernameChange("al", true);
661 // Now the fields should have the same value, but the selection should have a
662 // different start value.
663 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
664 CheckUsernameSelection(2, 5);
666 // Test that deleting does not trigger autocomplete.
667 SimulateKeyDownEvent(username_element_, ui::VKEY_BACK);
668 SimulateUsernameChange("alic", true);
669 CheckTextFieldsState("alic", false, std::string(), false);
670 CheckUsernameSelection(4, 4); // No selection.
671 // Reset the last pressed key to something other than backspace.
672 SimulateKeyDownEvent(username_element_, ui::VKEY_A);
674 // Now lets say the user goes astray from the stored username and types the
675 // letter 'f', spelling 'alf'. We don't know alf (that's just sad), so in
676 // practice the username should no longer be 'alice' and the selected range
678 SimulateUsernameChange("alf", true);
679 CheckTextFieldsState("alf", false, std::string(), false);
680 CheckUsernameSelection(3, 3); // No selection.
682 // Ok, so now the user removes all the text and enters the letter 'b'.
683 SimulateUsernameChange("b", true);
684 // The username and password fields should match the 'bob' entry.
685 CheckTextFieldsState(kBobUsername, true, kBobPassword, true);
686 CheckUsernameSelection(1, 3);
688 // Then, the user again removes all the text and types an uppercase 'C'.
689 SimulateUsernameChange("C", true);
690 // The username and password fields should match the 'Carol' entry.
691 CheckTextFieldsState(kCarolUsername, true, kCarolPassword, true);
692 CheckUsernameSelection(1, 5);
693 // The user removes all the text and types a lowercase 'c'. We only
694 // want case-sensitive autocompletion, so the username and the selected range
696 SimulateUsernameChange("c", true);
697 CheckTextFieldsState("c", false, std::string(), false);
698 CheckUsernameSelection(1, 1);
700 // Check that we complete other_possible_usernames as well.
701 SimulateUsernameChange("R", true);
702 CheckTextFieldsState(kCarolAlternateUsername, true, kCarolPassword, true);
703 CheckUsernameSelection(1, 17);
706 TEST_F(PasswordAutofillAgentTest, IsWebNodeVisibleTest) {
707 blink::WebVector<blink::WebFormElement> forms1, forms2, forms3;
708 blink::WebFrame* frame;
710 LoadHTML(kVisibleFormHTML);
711 frame = GetMainFrame();
712 frame->document().forms(forms1);
713 ASSERT_EQ(1u, forms1.size());
714 EXPECT_TRUE(IsWebNodeVisible(forms1[0]));
716 LoadHTML(kEmptyFormHTML);
717 frame = GetMainFrame();
718 frame->document().forms(forms2);
719 ASSERT_EQ(1u, forms2.size());
720 EXPECT_FALSE(IsWebNodeVisible(forms2[0]));
722 LoadHTML(kNonVisibleFormHTML);
723 frame = GetMainFrame();
724 frame->document().forms(forms3);
725 ASSERT_EQ(1u, forms3.size());
726 EXPECT_FALSE(IsWebNodeVisible(forms3[0]));
729 TEST_F(PasswordAutofillAgentTest, SendPasswordFormsTest) {
730 render_thread_->sink().ClearMessages();
731 LoadHTML(kVisibleFormHTML);
732 const IPC::Message* message = render_thread_->sink()
733 .GetFirstMessageMatching(AutofillHostMsg_PasswordFormsRendered::ID);
734 EXPECT_TRUE(message);
735 Tuple1<std::vector<autofill::PasswordForm> > param;
736 AutofillHostMsg_PasswordFormsRendered::Read(message, ¶m);
737 EXPECT_TRUE(param.a.size());
739 render_thread_->sink().ClearMessages();
740 LoadHTML(kEmptyFormHTML);
741 message = render_thread_->sink().GetFirstMessageMatching(
742 AutofillHostMsg_PasswordFormsRendered::ID);
743 EXPECT_TRUE(message);
744 AutofillHostMsg_PasswordFormsRendered::Read(message, ¶m);
745 EXPECT_FALSE(param.a.size());
747 render_thread_->sink().ClearMessages();
748 LoadHTML(kNonVisibleFormHTML);
749 message = render_thread_->sink().GetFirstMessageMatching(
750 AutofillHostMsg_PasswordFormsRendered::ID);
751 EXPECT_TRUE(message);
752 AutofillHostMsg_PasswordFormsRendered::Read(message, ¶m);
753 EXPECT_FALSE(param.a.size());
756 TEST_F(PasswordAutofillAgentTest, SendPasswordFormsTest_Redirection) {
757 render_thread_->sink().ClearMessages();
758 LoadHTML(kEmptyWebpage);
759 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
760 AutofillHostMsg_PasswordFormsRendered::ID));
762 render_thread_->sink().ClearMessages();
763 LoadHTML(kRedirectionWebpage);
764 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
765 AutofillHostMsg_PasswordFormsRendered::ID));
767 render_thread_->sink().ClearMessages();
768 LoadHTML(kSimpleWebpage);
769 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
770 AutofillHostMsg_PasswordFormsRendered::ID));
772 render_thread_->sink().ClearMessages();
773 LoadHTML(kWebpageWithDynamicContent);
774 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
775 AutofillHostMsg_PasswordFormsRendered::ID));
778 // Tests that a password form in an iframe will not be filled in until a user
779 // interaction with the form.
780 TEST_F(PasswordAutofillAgentTest, IframeNoFillTest) {
781 const char kIframeName[] = "iframe";
782 const char kWebpageWithIframeStart[] =
785 " <meta charset='utf-8' />"
786 " <title>Title</title>"
789 " <iframe id='iframe' src=\"";
790 const char kWebpageWithIframeEnd[] =
795 std::string origin("data:text/html;charset=utf-8,");
796 origin += kSimpleWebpage;
798 std::string page_html(kWebpageWithIframeStart);
800 page_html += kWebpageWithIframeEnd;
802 LoadHTML(page_html.c_str());
804 // Set the expected form origin and action URLs.
805 fill_data_.basic_data.origin = GURL(origin);
806 fill_data_.basic_data.action = GURL(origin);
808 SimulateOnFillPasswordForm(fill_data_);
810 // Retrieve the input elements from the iframe since that is where we want to
811 // test the autofill.
812 WebFrame* iframe = GetMainFrame()->findChildByName(kIframeName);
814 WebDocument document = iframe->document();
816 WebElement username_element = document.getElementById(kUsernameName);
817 WebElement password_element = document.getElementById(kPasswordName);
818 ASSERT_FALSE(username_element.isNull());
819 ASSERT_FALSE(password_element.isNull());
821 WebInputElement username_input = username_element.to<WebInputElement>();
822 WebInputElement password_input = password_element.to<WebInputElement>();
823 ASSERT_FALSE(username_element.isNull());
825 CheckTextFieldsStateForElements(username_input, "", false,
826 password_input, "", false);
828 // Simulate the user typing in the username in the iframe, which should cause
830 SimulateUsernameChangeForElement(kAliceUsername, true,
831 iframe, username_input);
833 CheckTextFieldsStateForElements(username_input, kAliceUsername, true,
834 password_input, kAlicePassword, true);
837 // Tests that a password will only be filled as a suggested and will not be
838 // accessible by the DOM until a user gesture has occurred.
839 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) {
840 // Trigger the initial autocomplete.
841 SimulateOnFillPasswordForm(fill_data_);
843 // The username and password should have been autocompleted.
844 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
846 // However, it should only have completed with the suggested value, as tested
847 // above, and it should not have completed into the DOM accessible value for
848 // the password field.
849 CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true);
851 // Simulate a user click so that the password field's real value is filled.
852 SimulateElementClick(kUsernameName);
853 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
856 // Verfies that a DOM-activated UI event will not cause an autofill.
857 TEST_F(PasswordAutofillAgentTest, NoDOMActivationTest) {
858 // Trigger the initial autocomplete.
859 SimulateOnFillPasswordForm(fill_data_);
861 ExecuteJavaScript(kJavaScriptClick);
862 CheckTextFieldsDOMState(kAliceUsername, true, "", true);
865 // Regression test for http://crbug.com/326679
866 TEST_F(PasswordAutofillAgentTest, SelectUsernameWithUsernameAutofillOff) {
867 // Simulate the browser sending back the login info.
868 SimulateOnFillPasswordForm(fill_data_);
870 // Set the username element to autocomplete='off'
871 username_element_.setAttribute(WebString::fromUTF8("autocomplete"),
872 WebString::fromUTF8("off"));
874 // Simulate the user changing the username to some known username.
875 SimulateUsernameChange(kAliceUsername, true);
877 ExpectNoSuggestionsPopup();
880 // Regression test for http://crbug.com/326679
881 TEST_F(PasswordAutofillAgentTest,
882 SelectUnknownUsernameWithUsernameAutofillOff) {
883 // Simulate the browser sending back the login info.
884 SimulateOnFillPasswordForm(fill_data_);
886 // Set the username element to autocomplete='off'
887 username_element_.setAttribute(WebString::fromUTF8("autocomplete"),
888 WebString::fromUTF8("off"));
890 // Simulate the user changing the username to some unknown username.
891 SimulateUsernameChange("foo", true);
893 ExpectNoSuggestionsPopup();
896 // Regression test for http://crbug.com/326679
897 TEST_F(PasswordAutofillAgentTest, SelectUsernameWithPasswordAutofillOff) {
898 // Simulate the browser sending back the login info.
899 SimulateOnFillPasswordForm(fill_data_);
901 // Set the main password element to autocomplete='off'
902 password_element_.setAttribute(WebString::fromUTF8("autocomplete"),
903 WebString::fromUTF8("off"));
905 // Simulate the user changing the username to some known username.
906 SimulateUsernameChange(kAliceUsername, true);
908 ExpectNoSuggestionsPopup();
911 // Regression test for http://crbug.com/326679
912 TEST_F(PasswordAutofillAgentTest,
913 SelectUnknownUsernameWithPasswordAutofillOff) {
914 // Simulate the browser sending back the login info.
915 SimulateOnFillPasswordForm(fill_data_);
917 // Set the main password element to autocomplete='off'
918 password_element_.setAttribute(WebString::fromUTF8("autocomplete"),
919 WebString::fromUTF8("off"));
921 // Simulate the user changing the username to some unknown username.
922 SimulateUsernameChange("foo", true);
924 ExpectNoSuggestionsPopup();
927 // Verifies that password autofill triggers onChange events in JavaScript for
928 // forms that are filled on page load.
929 TEST_F(PasswordAutofillAgentTest,
930 PasswordAutofillTriggersOnChangeEventsOnLoad) {
931 std::string html = std::string(kFormHTML) + kOnChangeDetectionScript;
932 LoadHTML(html.c_str());
933 UpdateOriginForHTML(html);
934 UpdateUsernameAndPasswordElements();
936 // Simulate the browser sending back the login info, it triggers the
938 SimulateOnFillPasswordForm(fill_data_);
940 // The username and password should have been autocompleted...
941 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
942 // ... but since there hasn't been a user gesture yet, the autocompleted
943 // password should only be visible to the user.
944 CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true);
946 // A JavaScript onChange event should have been triggered for the username,
947 // but not yet for the password.
948 int username_onchange_called = -1;
949 int password_onchange_called = -1;
951 ExecuteJavaScriptAndReturnIntValue(
952 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"),
953 &username_onchange_called));
954 EXPECT_EQ(1, username_onchange_called);
956 ExecuteJavaScriptAndReturnIntValue(
957 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"),
958 &password_onchange_called));
959 // TODO(isherman): Re-enable this check once http://crbug.com/333144 is fixed.
960 // EXPECT_EQ(0, password_onchange_called);
962 // Simulate a user click so that the password field's real value is filled.
963 SimulateElementClick(kUsernameName);
964 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
966 // Now, a JavaScript onChange event should have been triggered for the
969 ExecuteJavaScriptAndReturnIntValue(
970 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"),
971 &password_onchange_called));
972 EXPECT_EQ(1, password_onchange_called);
975 // Verifies that password autofill triggers onChange events in JavaScript for
976 // forms that are filled after page load.
977 TEST_F(PasswordAutofillAgentTest,
978 PasswordAutofillTriggersOnChangeEventsWaitForUsername) {
979 std::string html = std::string(kFormHTML) + kOnChangeDetectionScript;
980 LoadHTML(html.c_str());
981 UpdateOriginForHTML(html);
982 UpdateUsernameAndPasswordElements();
984 // Simulate the browser sending back the login info, it triggers the
986 fill_data_.wait_for_username = true;
987 SimulateOnFillPasswordForm(fill_data_);
989 // The username and password should not yet have been autocompleted.
990 CheckTextFieldsState(std::string(), false, std::string(), false);
992 // Simulate a click just to force a user gesture, since the username value is
994 SimulateElementClick(kUsernameName);
996 // Simulate the user entering her username.
997 username_element_.setValue(ASCIIToUTF16(kAliceUsername), true);
998 autofill_agent_->textFieldDidEndEditing(username_element_);
1000 // The username and password should now have been autocompleted.
1001 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
1003 // JavaScript onChange events should have been triggered both for the username
1004 // and for the password.
1005 int username_onchange_called = -1;
1006 int password_onchange_called = -1;
1008 ExecuteJavaScriptAndReturnIntValue(
1009 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"),
1010 &username_onchange_called));
1011 EXPECT_EQ(1, username_onchange_called);
1013 ExecuteJavaScriptAndReturnIntValue(
1014 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"),
1015 &password_onchange_called));
1016 EXPECT_EQ(1, password_onchange_called);
1019 } // namespace autofill