Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / renderer / autofill / password_autofill_agent_browsertest.cc
blobf5eed742853dcf79613ca2e49a01e40f566f2c0c
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 "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"
27 using autofill::PasswordForm;
28 using base::ASCIIToUTF16;
29 using base::UTF16ToUTF8;
30 using blink::WebDocument;
31 using blink::WebElement;
32 using blink::WebFrame;
33 using blink::WebInputElement;
34 using blink::WebString;
35 using blink::WebView;
37 namespace {
39 // The name of the username/password element in the form.
40 const char kUsernameName[] = "username";
41 const char kPasswordName[] = "password";
43 const char kAliceUsername[] = "alice";
44 const char kAlicePassword[] = "password";
45 const char kBobUsername[] = "bob";
46 const char kBobPassword[] = "secret";
47 const char kCarolUsername[] = "Carol";
48 const char kCarolPassword[] = "test";
49 const char kCarolAlternateUsername[] = "RealCarolUsername";
52 const char kFormHTML[] =
53 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
54 " <INPUT type='text' id='username'/>"
55 " <INPUT type='password' id='password'/>"
56 " <INPUT type='submit' value='Login'/>"
57 "</FORM>";
59 const char kVisibleFormHTML[] =
60 "<head> <style> form {display: inline;} </style> </head>"
61 "<body>"
62 " <form>"
63 " <div>"
64 " <input type='password' id='password'/>"
65 " </div>"
66 " </form>"
67 "</body>";
69 const char kEmptyFormHTML[] =
70 "<head> <style> form {display: inline;} </style> </head>"
71 "<body> <form> </form> </body>";
73 const char kNonVisibleFormHTML[] =
74 "<head> <style> form {display: none;} </style> </head>"
75 "<body>"
76 " <form>"
77 " <div>"
78 " <input type='password' id='password'/>"
79 " </div>"
80 " </form>"
81 "</body>";
83 const char kEmptyWebpage[] =
84 "<html>"
85 " <head>"
86 " </head>"
87 " <body>"
88 " </body>"
89 "</html>";
91 const char kRedirectionWebpage[] =
92 "<html>"
93 " <head>"
94 " <meta http-equiv='Content-Type' content='text/html'>"
95 " <title>Redirection page</title>"
96 " <script></script>"
97 " </head>"
98 " <body>"
99 " <script type='text/javascript'>"
100 " function test(){}"
101 " </script>"
102 " </body>"
103 "</html>";
105 const char kSimpleWebpage[] =
106 "<html>"
107 " <head>"
108 " <meta charset='utf-8' />"
109 " <title>Title</title>"
110 " </head>"
111 " <body>"
112 " <form name='LoginTestForm'>"
113 " <input type='text' id='username'/>"
114 " <input type='password' id='password'/>"
115 " <input type='submit' value='Login'/>"
116 " </form>"
117 " </body>"
118 "</html>";
120 const char kWebpageWithDynamicContent[] =
121 "<html>"
122 " <head>"
123 " <meta charset='utf-8' />"
124 " <title>Title</title>"
125 " </head>"
126 " <body>"
127 " <script type='text/javascript'>"
128 " function addParagraph() {"
129 " var p = document.createElement('p');"
130 " document.body.appendChild(p);"
131 " }"
132 " window.onload = addParagraph;"
133 " </script>"
134 " </body>"
135 "</html>";
137 const char kJavaScriptClick[] =
138 "var event = new MouseEvent('click', {"
139 " 'view': window,"
140 " 'bubbles': true,"
141 " 'cancelable': true"
142 "});"
143 "var form = document.getElementById('myform1');"
144 "form.dispatchEvent(event);"
145 "console.log('clicked!');";
147 const char kOnChangeDetectionScript[] =
148 "<script>"
149 " usernameOnchangeCalled = false;"
150 " passwordOnchangeCalled = false;"
151 " document.getElementById('username').onchange = function() {"
152 " usernameOnchangeCalled = true;"
153 " };"
154 " document.getElementById('password').onchange = function() {"
155 " passwordOnchangeCalled = true;"
156 " };"
157 "</script>";
159 } // namespace
161 namespace autofill {
163 class PasswordAutofillAgentTest : public ChromeRenderViewTest {
164 public:
165 PasswordAutofillAgentTest() {
168 // Simulates the fill password form message being sent to the renderer.
169 // We use that so we don't have to make RenderView::OnFillPasswordForm()
170 // protected.
171 void SimulateOnFillPasswordForm(
172 const PasswordFormFillData& fill_data) {
173 AutofillMsg_FillPasswordForm msg(0, fill_data);
174 password_autofill_->OnMessageReceived(msg);
177 virtual void SetUp() {
178 ChromeRenderViewTest::SetUp();
180 // Add a preferred login and an additional login to the FillData.
181 username1_ = ASCIIToUTF16(kAliceUsername);
182 password1_ = ASCIIToUTF16(kAlicePassword);
183 username2_ = ASCIIToUTF16(kBobUsername);
184 password2_ = ASCIIToUTF16(kBobPassword);
185 username3_ = ASCIIToUTF16(kCarolUsername);
186 password3_ = ASCIIToUTF16(kCarolPassword);
187 alternate_username3_ = ASCIIToUTF16(kCarolAlternateUsername);
189 FormFieldData username_field;
190 username_field.name = ASCIIToUTF16(kUsernameName);
191 username_field.value = username1_;
192 fill_data_.basic_data.fields.push_back(username_field);
194 FormFieldData password_field;
195 password_field.name = ASCIIToUTF16(kPasswordName);
196 password_field.value = password1_;
197 password_field.form_control_type = "password";
198 fill_data_.basic_data.fields.push_back(password_field);
200 PasswordAndRealm password2;
201 password2.password = password2_;
202 fill_data_.additional_logins[username2_] = password2;
203 PasswordAndRealm password3;
204 password3.password = password3_;
205 fill_data_.additional_logins[username3_] = password3;
207 UsernamesCollectionKey key;
208 key.username = username3_;
209 key.password = password3_;
210 key.realm = "google.com";
211 fill_data_.other_possible_usernames[key].push_back(alternate_username3_);
213 // We need to set the origin so it matches the frame URL and the action so
214 // it matches the form action, otherwise we won't autocomplete.
215 UpdateOriginForHTML(kFormHTML);
216 fill_data_.basic_data.action = GURL("http://www.bidule.com");
218 LoadHTML(kFormHTML);
220 // Now retrieve the input elements so the test can access them.
221 UpdateUsernameAndPasswordElements();
224 virtual void TearDown() {
225 username_element_.reset();
226 password_element_.reset();
227 ChromeRenderViewTest::TearDown();
230 void UpdateOriginForHTML(const std::string& html) {
231 std::string origin = "data:text/html;charset=utf-8," + html;
232 fill_data_.basic_data.origin = GURL(origin);
235 void UpdateUsernameAndPasswordElements() {
236 WebDocument document = GetMainFrame()->document();
237 WebElement element =
238 document.getElementById(WebString::fromUTF8(kUsernameName));
239 ASSERT_FALSE(element.isNull());
240 username_element_ = element.to<blink::WebInputElement>();
241 element = document.getElementById(WebString::fromUTF8(kPasswordName));
242 ASSERT_FALSE(element.isNull());
243 password_element_ = element.to<blink::WebInputElement>();
246 void ClearUsernameAndPasswordFields() {
247 username_element_.setValue("");
248 username_element_.setAutofilled(false);
249 password_element_.setValue("");
250 password_element_.setAutofilled(false);
253 void SimulateUsernameChangeForElement(const std::string& username,
254 bool move_caret_to_end,
255 WebFrame* input_frame,
256 WebInputElement& username_input) {
257 username_input.setValue(WebString::fromUTF8(username));
258 // The field must have focus or AutofillAgent will think the
259 // change should be ignored.
260 while (!username_input.focused())
261 input_frame->document().frame()->view()->advanceFocus(false);
262 if (move_caret_to_end)
263 username_input.setSelectionRange(username.length(), username.length());
264 autofill_agent_->textFieldDidChange(username_input);
265 // Processing is delayed because of a WebKit bug, see
266 // PasswordAutocompleteManager::TextDidChangeInTextField() for details.
267 base::MessageLoop::current()->RunUntilIdle();
270 void SimulateUsernameChange(const std::string& username,
271 bool move_caret_to_end) {
272 SimulateUsernameChangeForElement(username, move_caret_to_end,
273 GetMainFrame(), username_element_);
276 // Tests that no suggestion popup is generated when the username_element_ is
277 // edited.
278 void ExpectNoSuggestionsPopup() {
279 // The first test below ensures that the suggestions have been handled by
280 // the password_autofill_agent, even though autocomplete='off' is set. The
281 // second check ensures that, although handled, no "show suggestions" IPC to
282 // the browser was generated.
284 // This is interesting in the specific case of an autocomplete='off' form
285 // that also has a remembered username and password
286 // (http://crbug.com/326679). To fix the DCHECK that this case used to hit,
287 // |true| is returned from ShowSuggestions for all forms with valid
288 // usersnames that are autocomplete='off', prentending that a selection box
289 // has been shown to the user. Of course, it hasn't, so a message is never
290 // sent to the browser on acceptance, and the DCHECK isn't hit (and nothing
291 // is filled).
292 EXPECT_TRUE(autofill_agent_->password_autofill_agent_->ShowSuggestions(
293 username_element_));
295 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
296 AutofillHostMsg_ShowPasswordSuggestions::ID));
299 void SimulateKeyDownEvent(const WebInputElement& element,
300 ui::KeyboardCode key_code) {
301 blink::WebKeyboardEvent key_event;
302 key_event.windowsKeyCode = key_code;
303 autofill_agent_->textFieldDidReceiveKeyDown(element, key_event);
306 void CheckTextFieldsStateForElements(const WebInputElement& username_element,
307 const std::string& username,
308 bool username_autofilled,
309 const WebInputElement& password_element,
310 const std::string& password,
311 bool password_autofilled,
312 bool checkSuggestedValue = true) {
313 EXPECT_EQ(username,
314 static_cast<std::string>(username_element.value().utf8()));
315 EXPECT_EQ(username_autofilled, username_element.isAutofilled());
316 EXPECT_EQ(password,
317 static_cast<std::string>(
318 checkSuggestedValue ? password_element.suggestedValue().utf8()
319 : password_element.value().utf8()));
320 EXPECT_EQ(password_autofilled, password_element.isAutofilled());
323 // Checks the DOM-accessible value of the username element and the
324 // *suggested* value of the password element.
325 void CheckTextFieldsState(const std::string& username,
326 bool username_autofilled,
327 const std::string& password,
328 bool password_autofilled) {
329 CheckTextFieldsStateForElements(username_element_, username,
330 username_autofilled, password_element_,
331 password, password_autofilled);
334 // Checks the DOM-accessible value of the username element and the
335 // DOM-accessible value of the password element.
336 void CheckTextFieldsDOMState(const std::string& username,
337 bool username_autofilled,
338 const std::string& password,
339 bool password_autofilled) {
340 CheckTextFieldsStateForElements(username_element_,
341 username,
342 username_autofilled,
343 password_element_,
344 password,
345 password_autofilled,
346 false);
349 void CheckUsernameSelection(int start, int end) {
350 EXPECT_EQ(start, username_element_.selectionStart());
351 EXPECT_EQ(end, username_element_.selectionEnd());
354 base::string16 username1_;
355 base::string16 username2_;
356 base::string16 username3_;
357 base::string16 password1_;
358 base::string16 password2_;
359 base::string16 password3_;
360 base::string16 alternate_username3_;
361 PasswordFormFillData fill_data_;
363 WebInputElement username_element_;
364 WebInputElement password_element_;
366 private:
367 DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgentTest);
370 // Tests that the password login is autocompleted as expected when the browser
371 // sends back the password info.
372 TEST_F(PasswordAutofillAgentTest, InitialAutocomplete) {
374 * Right now we are not sending the message to the browser because we are
375 * loading a data URL and the security origin canAccessPasswordManager()
376 * returns false. May be we should mock URL loading to cirmcuvent this?
377 TODO(jcivelli): find a way to make the security origin not deny access to the
378 password manager and then reenable this code.
380 // The form has been loaded, we should have sent the browser a message about
381 // the form.
382 const IPC::Message* msg = render_thread_.sink().GetFirstMessageMatching(
383 AutofillHostMsg_PasswordFormsParsed::ID);
384 ASSERT_TRUE(msg != NULL);
386 Tuple1<std::vector<PasswordForm> > forms;
387 AutofillHostMsg_PasswordFormsParsed::Read(msg, &forms);
388 ASSERT_EQ(1U, forms.a.size());
389 PasswordForm password_form = forms.a[0];
390 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form.scheme);
391 EXPECT_EQ(ASCIIToUTF16(kUsernameName), password_form.username_element);
392 EXPECT_EQ(ASCIIToUTF16(kPasswordName), password_form.password_element);
395 // Simulate the browser sending back the login info, it triggers the
396 // autocomplete.
397 SimulateOnFillPasswordForm(fill_data_);
399 // The username and password should have been autocompleted.
400 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
403 // Tests that we correctly fill forms having an empty 'action' attribute.
404 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForEmptyAction) {
405 const char kEmptyActionFormHTML[] =
406 "<FORM name='LoginTestForm'>"
407 " <INPUT type='text' id='username'/>"
408 " <INPUT type='password' id='password'/>"
409 " <INPUT type='submit' value='Login'/>"
410 "</FORM>";
411 LoadHTML(kEmptyActionFormHTML);
413 // Retrieve the input elements so the test can access them.
414 WebDocument document = GetMainFrame()->document();
415 WebElement element =
416 document.getElementById(WebString::fromUTF8(kUsernameName));
417 ASSERT_FALSE(element.isNull());
418 username_element_ = element.to<blink::WebInputElement>();
419 element = document.getElementById(WebString::fromUTF8(kPasswordName));
420 ASSERT_FALSE(element.isNull());
421 password_element_ = element.to<blink::WebInputElement>();
423 // Set the expected form origin and action URLs.
424 UpdateOriginForHTML(kEmptyActionFormHTML);
425 fill_data_.basic_data.action = fill_data_.basic_data.origin;
427 // Simulate the browser sending back the login info, it triggers the
428 // autocomplete.
429 SimulateOnFillPasswordForm(fill_data_);
431 // The username and password should have been autocompleted.
432 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
435 // Tests that if a password is marked as readonly, neither field is autofilled
436 // on page load.
437 TEST_F(PasswordAutofillAgentTest, NoInitialAutocompleteForReadOnlyPassword) {
438 password_element_.setAttribute(WebString::fromUTF8("readonly"),
439 WebString::fromUTF8("true"));
441 // Simulate the browser sending back the login info, it triggers the
442 // autocomplete.
443 SimulateOnFillPasswordForm(fill_data_);
445 CheckTextFieldsState(std::string(), false, std::string(), false);
448 // Can still fill a password field if the username is set to a value that
449 // matches.
450 TEST_F(PasswordAutofillAgentTest,
451 AutocompletePasswordForReadonlyUsernameMatched) {
452 username_element_.setValue(username3_);
453 username_element_.setAttribute(WebString::fromUTF8("readonly"),
454 WebString::fromUTF8("true"));
456 // Filled even though username is not the preferred match.
457 SimulateOnFillPasswordForm(fill_data_);
458 CheckTextFieldsState(UTF16ToUTF8(username3_), false,
459 UTF16ToUTF8(password3_), true);
462 // If a username field is empty and readonly, don't autofill.
463 TEST_F(PasswordAutofillAgentTest,
464 NoAutocompletePasswordForReadonlyUsernameUnmatched) {
465 username_element_.setValue(WebString::fromUTF8(""));
466 username_element_.setAttribute(WebString::fromUTF8("readonly"),
467 WebString::fromUTF8("true"));
469 SimulateOnFillPasswordForm(fill_data_);
470 CheckTextFieldsState(std::string(), false, std::string(), false);
473 // Tests that having a non-matching username precludes the autocomplete.
474 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForFilledFieldUnmatched) {
475 username_element_.setValue(WebString::fromUTF8("bogus"));
477 // Simulate the browser sending back the login info, it triggers the
478 // autocomplete.
479 SimulateOnFillPasswordForm(fill_data_);
481 // Neither field should be autocompleted.
482 CheckTextFieldsState("bogus", false, std::string(), false);
485 // Don't try to complete a prefilled value even if it's a partial match
486 // to a username.
487 TEST_F(PasswordAutofillAgentTest, NoPartialMatchForPrefilledUsername) {
488 username_element_.setValue(WebString::fromUTF8("ali"));
490 SimulateOnFillPasswordForm(fill_data_);
492 CheckTextFieldsState("ali", false, std::string(), false);
495 TEST_F(PasswordAutofillAgentTest, InputWithNoForms) {
496 const char kNoFormInputs[] =
497 "<input type='text' id='username'/>"
498 "<input type='password' id='password'/>";
499 LoadHTML(kNoFormInputs);
501 SimulateOnFillPasswordForm(fill_data_);
503 // Input elements that aren't in a <form> won't autofill.
504 CheckTextFieldsState(std::string(), false, std::string(), false);
507 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForTextFieldPasswords) {
508 const char kTextFieldPasswordFormHTML[] =
509 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
510 " <INPUT type='text' id='username'/>"
511 " <INPUT type='text' id='password'/>"
512 " <INPUT type='submit' value='Login'/>"
513 "</FORM>";
514 LoadHTML(kTextFieldPasswordFormHTML);
516 // Retrieve the input elements so the test can access them.
517 WebDocument document = GetMainFrame()->document();
518 WebElement element =
519 document.getElementById(WebString::fromUTF8(kUsernameName));
520 ASSERT_FALSE(element.isNull());
521 username_element_ = element.to<blink::WebInputElement>();
522 element = document.getElementById(WebString::fromUTF8(kPasswordName));
523 ASSERT_FALSE(element.isNull());
524 password_element_ = element.to<blink::WebInputElement>();
526 // Set the expected form origin URL.
527 UpdateOriginForHTML(kTextFieldPasswordFormHTML);
529 SimulateOnFillPasswordForm(fill_data_);
531 // Fields should still be empty.
532 CheckTextFieldsState(std::string(), false, std::string(), false);
535 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) {
536 const char kPasswordFieldUsernameFormHTML[] =
537 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
538 " <INPUT type='password' id='username'/>"
539 " <INPUT type='password' id='password'/>"
540 " <INPUT type='submit' value='Login'/>"
541 "</FORM>";
542 LoadHTML(kPasswordFieldUsernameFormHTML);
544 // Retrieve the input elements so the test can access them.
545 WebDocument document = GetMainFrame()->document();
546 WebElement element =
547 document.getElementById(WebString::fromUTF8(kUsernameName));
548 ASSERT_FALSE(element.isNull());
549 username_element_ = element.to<blink::WebInputElement>();
550 element = document.getElementById(WebString::fromUTF8(kPasswordName));
551 ASSERT_FALSE(element.isNull());
552 password_element_ = element.to<blink::WebInputElement>();
554 // Set the expected form origin URL.
555 UpdateOriginForHTML(kPasswordFieldUsernameFormHTML);
557 SimulateOnFillPasswordForm(fill_data_);
559 // Fields should still be empty.
560 CheckTextFieldsState(std::string(), false, std::string(), false);
563 // Tests that having a matching username does not preclude the autocomplete.
564 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) {
565 username_element_.setValue(WebString::fromUTF8(kAliceUsername));
567 // Simulate the browser sending back the login info, it triggers the
568 // autocomplete.
569 SimulateOnFillPasswordForm(fill_data_);
571 // The username and password should have been autocompleted.
572 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
575 // Tests that editing the password clears the autocompleted password field.
576 TEST_F(PasswordAutofillAgentTest, PasswordClearOnEdit) {
577 // Simulate the browser sending back the login info, it triggers the
578 // autocomplete.
579 SimulateOnFillPasswordForm(fill_data_);
581 // Simulate the user changing the username to some unknown username.
582 SimulateUsernameChange("alicia", true);
584 // The password should have been cleared.
585 CheckTextFieldsState("alicia", false, std::string(), false);
588 // Tests that we only autocomplete on focus lost and with a full username match
589 // when |wait_for_username| is true.
590 TEST_F(PasswordAutofillAgentTest, WaitUsername) {
591 // Simulate the browser sending back the login info.
592 fill_data_.wait_for_username = true;
593 SimulateOnFillPasswordForm(fill_data_);
595 // No auto-fill should have taken place.
596 CheckTextFieldsState(std::string(), false, std::string(), false);
598 // No autocomplete should happen when text is entered in the username.
599 SimulateUsernameChange("a", true);
600 CheckTextFieldsState("a", false, std::string(), false);
601 SimulateUsernameChange("al", true);
602 CheckTextFieldsState("al", false, std::string(), false);
603 SimulateUsernameChange(kAliceUsername, true);
604 CheckTextFieldsState(kAliceUsername, false, std::string(), false);
606 // Autocomplete should happen only when the username textfield is blurred with
607 // a full match.
608 username_element_.setValue("a");
609 autofill_agent_->textFieldDidEndEditing(username_element_);
610 CheckTextFieldsState("a", false, std::string(), false);
611 username_element_.setValue("al");
612 autofill_agent_->textFieldDidEndEditing(username_element_);
613 CheckTextFieldsState("al", false, std::string(), false);
614 username_element_.setValue("alices");
615 autofill_agent_->textFieldDidEndEditing(username_element_);
616 CheckTextFieldsState("alices", false, std::string(), false);
617 username_element_.setValue(ASCIIToUTF16(kAliceUsername));
618 autofill_agent_->textFieldDidEndEditing(username_element_);
619 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
622 // Tests that inline autocompletion works properly.
623 TEST_F(PasswordAutofillAgentTest, InlineAutocomplete) {
624 // Simulate the browser sending back the login info.
625 SimulateOnFillPasswordForm(fill_data_);
627 // Clear the text fields to start fresh.
628 ClearUsernameAndPasswordFields();
630 // Simulate the user typing in the first letter of 'alice', a stored username.
631 SimulateUsernameChange("a", true);
632 // Both the username and password text fields should reflect selection of the
633 // stored login.
634 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
635 // And the selection should have been set to 'lice', the last 4 letters.
636 CheckUsernameSelection(1, 5);
638 // Now the user types the next letter of the same username, 'l'.
639 SimulateUsernameChange("al", true);
640 // Now the fields should have the same value, but the selection should have a
641 // different start value.
642 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
643 CheckUsernameSelection(2, 5);
645 // Test that deleting does not trigger autocomplete.
646 SimulateKeyDownEvent(username_element_, ui::VKEY_BACK);
647 SimulateUsernameChange("alic", true);
648 CheckTextFieldsState("alic", false, std::string(), false);
649 CheckUsernameSelection(4, 4); // No selection.
650 // Reset the last pressed key to something other than backspace.
651 SimulateKeyDownEvent(username_element_, ui::VKEY_A);
653 // Now lets say the user goes astray from the stored username and types the
654 // letter 'f', spelling 'alf'. We don't know alf (that's just sad), so in
655 // practice the username should no longer be 'alice' and the selected range
656 // should be empty.
657 SimulateUsernameChange("alf", true);
658 CheckTextFieldsState("alf", false, std::string(), false);
659 CheckUsernameSelection(3, 3); // No selection.
661 // Ok, so now the user removes all the text and enters the letter 'b'.
662 SimulateUsernameChange("b", true);
663 // The username and password fields should match the 'bob' entry.
664 CheckTextFieldsState(kBobUsername, true, kBobPassword, true);
665 CheckUsernameSelection(1, 3);
667 // Then, the user again removes all the text and types an uppercase 'C'.
668 SimulateUsernameChange("C", true);
669 // The username and password fields should match the 'Carol' entry.
670 CheckTextFieldsState(kCarolUsername, true, kCarolPassword, true);
671 CheckUsernameSelection(1, 5);
672 // The user removes all the text and types a lowercase 'c'. We only
673 // want case-sensitive autocompletion, so the username and the selected range
674 // should be empty.
675 SimulateUsernameChange("c", true);
676 CheckTextFieldsState("c", false, std::string(), false);
677 CheckUsernameSelection(1, 1);
679 // Check that we complete other_possible_usernames as well.
680 SimulateUsernameChange("R", true);
681 CheckTextFieldsState(kCarolAlternateUsername, true, kCarolPassword, true);
682 CheckUsernameSelection(1, 17);
685 TEST_F(PasswordAutofillAgentTest, IsWebNodeVisibleTest) {
686 blink::WebVector<blink::WebFormElement> forms1, forms2, forms3;
687 blink::WebFrame* frame;
689 LoadHTML(kVisibleFormHTML);
690 frame = GetMainFrame();
691 frame->document().forms(forms1);
692 ASSERT_EQ(1u, forms1.size());
693 EXPECT_TRUE(IsWebNodeVisible(forms1[0]));
695 LoadHTML(kEmptyFormHTML);
696 frame = GetMainFrame();
697 frame->document().forms(forms2);
698 ASSERT_EQ(1u, forms2.size());
699 EXPECT_FALSE(IsWebNodeVisible(forms2[0]));
701 LoadHTML(kNonVisibleFormHTML);
702 frame = GetMainFrame();
703 frame->document().forms(forms3);
704 ASSERT_EQ(1u, forms3.size());
705 EXPECT_FALSE(IsWebNodeVisible(forms3[0]));
708 TEST_F(PasswordAutofillAgentTest, SendPasswordFormsTest) {
709 render_thread_->sink().ClearMessages();
710 LoadHTML(kVisibleFormHTML);
711 const IPC::Message* message = render_thread_->sink()
712 .GetFirstMessageMatching(AutofillHostMsg_PasswordFormsRendered::ID);
713 EXPECT_TRUE(message);
714 Tuple1<std::vector<autofill::PasswordForm> > param;
715 AutofillHostMsg_PasswordFormsRendered::Read(message, &param);
716 EXPECT_TRUE(param.a.size());
718 render_thread_->sink().ClearMessages();
719 LoadHTML(kEmptyFormHTML);
720 message = render_thread_->sink().GetFirstMessageMatching(
721 AutofillHostMsg_PasswordFormsRendered::ID);
722 EXPECT_TRUE(message);
723 AutofillHostMsg_PasswordFormsRendered::Read(message, &param);
724 EXPECT_FALSE(param.a.size());
726 render_thread_->sink().ClearMessages();
727 LoadHTML(kNonVisibleFormHTML);
728 message = render_thread_->sink().GetFirstMessageMatching(
729 AutofillHostMsg_PasswordFormsRendered::ID);
730 EXPECT_TRUE(message);
731 AutofillHostMsg_PasswordFormsRendered::Read(message, &param);
732 EXPECT_FALSE(param.a.size());
735 TEST_F(PasswordAutofillAgentTest, SendPasswordFormsTest_Redirection) {
736 render_thread_->sink().ClearMessages();
737 LoadHTML(kEmptyWebpage);
738 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
739 AutofillHostMsg_PasswordFormsRendered::ID));
741 render_thread_->sink().ClearMessages();
742 LoadHTML(kRedirectionWebpage);
743 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
744 AutofillHostMsg_PasswordFormsRendered::ID));
746 render_thread_->sink().ClearMessages();
747 LoadHTML(kSimpleWebpage);
748 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
749 AutofillHostMsg_PasswordFormsRendered::ID));
751 render_thread_->sink().ClearMessages();
752 LoadHTML(kWebpageWithDynamicContent);
753 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
754 AutofillHostMsg_PasswordFormsRendered::ID));
757 // Tests that a password form in an iframe will not be filled in until a user
758 // interaction with the form.
759 TEST_F(PasswordAutofillAgentTest, IframeNoFillTest) {
760 const char kIframeName[] = "iframe";
761 const char kWebpageWithIframeStart[] =
762 "<html>"
763 " <head>"
764 " <meta charset='utf-8' />"
765 " <title>Title</title>"
766 " </head>"
767 " <body>"
768 " <iframe id='iframe' src=\"";
769 const char kWebpageWithIframeEnd[] =
770 "\"></iframe>"
771 " </body>"
772 "</html>";
774 std::string origin("data:text/html;charset=utf-8,");
775 origin += kSimpleWebpage;
777 std::string page_html(kWebpageWithIframeStart);
778 page_html += origin;
779 page_html += kWebpageWithIframeEnd;
781 LoadHTML(page_html.c_str());
783 // Set the expected form origin and action URLs.
784 fill_data_.basic_data.origin = GURL(origin);
785 fill_data_.basic_data.action = GURL(origin);
787 SimulateOnFillPasswordForm(fill_data_);
789 // Retrieve the input elements from the iframe since that is where we want to
790 // test the autofill.
791 WebFrame* iframe = GetMainFrame()->findChildByName(kIframeName);
792 ASSERT_TRUE(iframe);
793 WebDocument document = iframe->document();
795 WebElement username_element = document.getElementById(kUsernameName);
796 WebElement password_element = document.getElementById(kPasswordName);
797 ASSERT_FALSE(username_element.isNull());
798 ASSERT_FALSE(password_element.isNull());
800 WebInputElement username_input = username_element.to<WebInputElement>();
801 WebInputElement password_input = password_element.to<WebInputElement>();
802 ASSERT_FALSE(username_element.isNull());
804 CheckTextFieldsStateForElements(username_input, "", false,
805 password_input, "", false);
807 // Simulate the user typing in the username in the iframe, which should cause
808 // an autofill.
809 SimulateUsernameChangeForElement(kAliceUsername, true,
810 iframe, username_input);
812 CheckTextFieldsStateForElements(username_input, kAliceUsername, true,
813 password_input, kAlicePassword, true);
816 // Tests that a password will only be filled as a suggested and will not be
817 // accessible by the DOM until a user gesture has occurred.
818 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) {
819 // Trigger the initial autocomplete.
820 SimulateOnFillPasswordForm(fill_data_);
822 // The username and password should have been autocompleted.
823 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
825 // However, it should only have completed with the suggested value, as tested
826 // above, and it should not have completed into the DOM accessible value for
827 // the password field.
828 CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true);
830 // Simulate a user click so that the password field's real value is filled.
831 SimulateElementClick(kUsernameName);
832 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
835 // Verfies that a DOM-activated UI event will not cause an autofill.
836 TEST_F(PasswordAutofillAgentTest, NoDOMActivationTest) {
837 // Trigger the initial autocomplete.
838 SimulateOnFillPasswordForm(fill_data_);
840 ExecuteJavaScript(kJavaScriptClick);
841 CheckTextFieldsDOMState(kAliceUsername, true, "", true);
844 // Regression test for http://crbug.com/326679
845 TEST_F(PasswordAutofillAgentTest, SelectUsernameWithUsernameAutofillOff) {
846 // Simulate the browser sending back the login info.
847 SimulateOnFillPasswordForm(fill_data_);
849 // Set the username element to autocomplete='off'
850 username_element_.setAttribute(WebString::fromUTF8("autocomplete"),
851 WebString::fromUTF8("off"));
853 // Simulate the user changing the username to some known username.
854 SimulateUsernameChange(kAliceUsername, true);
856 ExpectNoSuggestionsPopup();
859 // Regression test for http://crbug.com/326679
860 TEST_F(PasswordAutofillAgentTest,
861 SelectUnknownUsernameWithUsernameAutofillOff) {
862 // Simulate the browser sending back the login info.
863 SimulateOnFillPasswordForm(fill_data_);
865 // Set the username element to autocomplete='off'
866 username_element_.setAttribute(WebString::fromUTF8("autocomplete"),
867 WebString::fromUTF8("off"));
869 // Simulate the user changing the username to some unknown username.
870 SimulateUsernameChange("foo", true);
872 ExpectNoSuggestionsPopup();
875 // Regression test for http://crbug.com/326679
876 TEST_F(PasswordAutofillAgentTest, SelectUsernameWithPasswordAutofillOff) {
877 // Simulate the browser sending back the login info.
878 SimulateOnFillPasswordForm(fill_data_);
880 // Set the main password element to autocomplete='off'
881 password_element_.setAttribute(WebString::fromUTF8("autocomplete"),
882 WebString::fromUTF8("off"));
884 // Simulate the user changing the username to some known username.
885 SimulateUsernameChange(kAliceUsername, true);
887 ExpectNoSuggestionsPopup();
890 // Regression test for http://crbug.com/326679
891 TEST_F(PasswordAutofillAgentTest,
892 SelectUnknownUsernameWithPasswordAutofillOff) {
893 // Simulate the browser sending back the login info.
894 SimulateOnFillPasswordForm(fill_data_);
896 // Set the main password element to autocomplete='off'
897 password_element_.setAttribute(WebString::fromUTF8("autocomplete"),
898 WebString::fromUTF8("off"));
900 // Simulate the user changing the username to some unknown username.
901 SimulateUsernameChange("foo", true);
903 ExpectNoSuggestionsPopup();
906 // Verifies that password autofill triggers onChange events in JavaScript for
907 // forms that are filled on page load.
908 TEST_F(PasswordAutofillAgentTest,
909 PasswordAutofillTriggersOnChangeEventsOnLoad) {
910 std::string html = std::string(kFormHTML) + kOnChangeDetectionScript;
911 LoadHTML(html.c_str());
912 UpdateOriginForHTML(html);
913 UpdateUsernameAndPasswordElements();
915 // Simulate the browser sending back the login info, it triggers the
916 // autocomplete.
917 SimulateOnFillPasswordForm(fill_data_);
919 // The username and password should have been autocompleted...
920 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
921 // ... but since there hasn't been a user gesture yet, the autocompleted
922 // password should only be visible to the user.
923 CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true);
925 // A JavaScript onChange event should have been triggered for the username,
926 // but not yet for the password.
927 int username_onchange_called = -1;
928 int password_onchange_called = -1;
929 ASSERT_TRUE(
930 ExecuteJavaScriptAndReturnIntValue(
931 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"),
932 &username_onchange_called));
933 EXPECT_EQ(1, username_onchange_called);
934 ASSERT_TRUE(
935 ExecuteJavaScriptAndReturnIntValue(
936 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"),
937 &password_onchange_called));
938 // TODO(isherman): Re-enable this check once http://crbug.com/333144 is fixed.
939 // EXPECT_EQ(0, password_onchange_called);
941 // Simulate a user click so that the password field's real value is filled.
942 SimulateElementClick(kUsernameName);
943 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
945 // Now, a JavaScript onChange event should have been triggered for the
946 // password as well.
947 ASSERT_TRUE(
948 ExecuteJavaScriptAndReturnIntValue(
949 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"),
950 &password_onchange_called));
951 EXPECT_EQ(1, password_onchange_called);
954 // Verifies that password autofill triggers onChange events in JavaScript for
955 // forms that are filled after page load.
956 TEST_F(PasswordAutofillAgentTest,
957 PasswordAutofillTriggersOnChangeEventsWaitForUsername) {
958 std::string html = std::string(kFormHTML) + kOnChangeDetectionScript;
959 LoadHTML(html.c_str());
960 UpdateOriginForHTML(html);
961 UpdateUsernameAndPasswordElements();
963 // Simulate the browser sending back the login info, it triggers the
964 // autocomplete.
965 fill_data_.wait_for_username = true;
966 SimulateOnFillPasswordForm(fill_data_);
968 // The username and password should not yet have been autocompleted.
969 CheckTextFieldsState(std::string(), false, std::string(), false);
971 // Simulate a click just to force a user gesture, since the username value is
972 // set directly.
973 SimulateElementClick(kUsernameName);
975 // Simulate the user entering her username.
976 username_element_.setValue(ASCIIToUTF16(kAliceUsername), true);
977 autofill_agent_->textFieldDidEndEditing(username_element_);
979 // The username and password should now have been autocompleted.
980 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
982 // JavaScript onChange events should have been triggered both for the username
983 // and for the password.
984 int username_onchange_called = -1;
985 int password_onchange_called = -1;
986 ASSERT_TRUE(
987 ExecuteJavaScriptAndReturnIntValue(
988 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"),
989 &username_onchange_called));
990 EXPECT_EQ(1, username_onchange_called);
991 ASSERT_TRUE(
992 ExecuteJavaScriptAndReturnIntValue(
993 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"),
994 &password_onchange_called));
995 EXPECT_EQ(1, password_onchange_called);
998 } // namespace autofill