[Android] Added UMA for search by image context menu.
[chromium-blink-merge.git] / chrome / renderer / autofill / password_autofill_agent_browsertest.cc
blob975b4f4c71ae99948a5ae526b7f3efcc813de640
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/renderer/autofill_agent.h"
9 #include "components/autofill/content/renderer/password_autofill_agent.h"
10 #include "components/autofill/core/common/autofill_messages.h"
11 #include "components/autofill/core/common/form_data.h"
12 #include "components/autofill/core/common/form_field_data.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/WebKit/public/platform/WebString.h"
15 #include "third_party/WebKit/public/platform/WebVector.h"
16 #include "third_party/WebKit/public/web/WebDocument.h"
17 #include "third_party/WebKit/public/web/WebElement.h"
18 #include "third_party/WebKit/public/web/WebFormElement.h"
19 #include "third_party/WebKit/public/web/WebInputElement.h"
20 #include "third_party/WebKit/public/web/WebNode.h"
21 #include "third_party/WebKit/public/web/WebView.h"
22 #include "ui/base/keycodes/keyboard_codes.h"
24 using content::PasswordForm;
25 using WebKit::WebDocument;
26 using WebKit::WebElement;
27 using WebKit::WebFrame;
28 using WebKit::WebInputElement;
29 using WebKit::WebString;
30 using WebKit::WebView;
32 namespace {
34 // The name of the username/password element in the form.
35 const char* const kUsernameName = "username";
36 const char* const kPasswordName = "password";
38 const char* const kAliceUsername = "alice";
39 const char* const kAlicePassword = "password";
40 const char* const kBobUsername = "bob";
41 const char* const kBobPassword = "secret";
42 const char* const kCarolUsername = "Carol";
43 const char* const kCarolPassword = "test";
44 const char* const kCarolAlternateUsername = "RealCarolUsername";
47 const char* const kFormHTML =
48 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
49 " <INPUT type='text' id='username'/>"
50 " <INPUT type='password' id='password'/>"
51 " <INPUT type='submit' value='Login'/>"
52 "</FORM>";
54 } // namespace
56 namespace autofill {
58 class PasswordAutofillAgentTest : public ChromeRenderViewTest {
59 public:
60 PasswordAutofillAgentTest() {
63 // Simulates the fill password form message being sent to the renderer.
64 // We use that so we don't have to make RenderView::OnFillPasswordForm()
65 // protected.
66 void SimulateOnFillPasswordForm(
67 const PasswordFormFillData& fill_data) {
68 AutofillMsg_FillPasswordForm msg(0, fill_data);
69 password_autofill_->OnMessageReceived(msg);
72 virtual void SetUp() {
73 ChromeRenderViewTest::SetUp();
75 // Add a preferred login and an additional login to the FillData.
76 username1_ = ASCIIToUTF16(kAliceUsername);
77 password1_ = ASCIIToUTF16(kAlicePassword);
78 username2_ = ASCIIToUTF16(kBobUsername);
79 password2_ = ASCIIToUTF16(kBobPassword);
80 username3_ = ASCIIToUTF16(kCarolUsername);
81 password3_ = ASCIIToUTF16(kCarolPassword);
82 alternate_username3_ = ASCIIToUTF16(kCarolAlternateUsername);
84 FormFieldData username_field;
85 username_field.name = ASCIIToUTF16(kUsernameName);
86 username_field.value = username1_;
87 fill_data_.basic_data.fields.push_back(username_field);
89 FormFieldData password_field;
90 password_field.name = ASCIIToUTF16(kPasswordName);
91 password_field.value = password1_;
92 password_field.form_control_type = "password";
93 fill_data_.basic_data.fields.push_back(password_field);
95 PasswordAndRealm password2;
96 password2.password = password2_;
97 fill_data_.additional_logins[username2_] = password2;
98 PasswordAndRealm password3;
99 password3.password = password3_;
100 fill_data_.additional_logins[username3_] = password3;
102 UsernamesCollectionKey key;
103 key.username = username3_;
104 key.password = password3_;
105 key.realm = "google.com";
106 fill_data_.other_possible_usernames[key].push_back(alternate_username3_);
108 // We need to set the origin so it matches the frame URL and the action so
109 // it matches the form action, otherwise we won't autocomplete.
110 std::string origin("data:text/html;charset=utf-8,");
111 origin += kFormHTML;
112 fill_data_.basic_data.origin = GURL(origin);
113 fill_data_.basic_data.action = GURL("http://www.bidule.com");
115 LoadHTML(kFormHTML);
117 // Now retrieves the input elements so the test can access them.
118 WebDocument document = GetMainFrame()->document();
119 WebElement element =
120 document.getElementById(WebString::fromUTF8(kUsernameName));
121 ASSERT_FALSE(element.isNull());
122 username_element_ = element.to<WebKit::WebInputElement>();
123 element = document.getElementById(WebString::fromUTF8(kPasswordName));
124 ASSERT_FALSE(element.isNull());
125 password_element_ = element.to<WebKit::WebInputElement>();
128 virtual void TearDown() {
129 username_element_.reset();
130 password_element_.reset();
131 ChromeRenderViewTest::TearDown();
134 void ClearUsernameAndPasswordFields() {
135 username_element_.setValue("");
136 username_element_.setAutofilled(false);
137 password_element_.setValue("");
138 password_element_.setAutofilled(false);
141 void SimulateUsernameChange(const std::string& username,
142 bool move_caret_to_end) {
143 username_element_.setValue(WebString::fromUTF8(username));
144 // The field must have focus or AutofillAgent will think the
145 // change should be ignored.
146 while (!username_element_.focused())
147 GetMainFrame()->document().frame()->view()->advanceFocus(false);
148 if (move_caret_to_end)
149 username_element_.setSelectionRange(username.length(), username.length());
150 autofill_agent_->textFieldDidChange(username_element_);
151 // Processing is delayed because of a WebKit bug, see
152 // PasswordAutocompleteManager::TextDidChangeInTextField() for details.
153 base::MessageLoop::current()->RunUntilIdle();
156 void SimulateKeyDownEvent(const WebInputElement& element,
157 ui::KeyboardCode key_code) {
158 WebKit::WebKeyboardEvent key_event;
159 key_event.windowsKeyCode = key_code;
160 autofill_agent_->textFieldDidReceiveKeyDown(element, key_event);
163 void CheckTextFieldsState(const std::string& username,
164 bool username_autofilled,
165 const std::string& password,
166 bool password_autofilled) {
167 EXPECT_EQ(username,
168 static_cast<std::string>(username_element_.value().utf8()));
169 EXPECT_EQ(username_autofilled, username_element_.isAutofilled());
170 EXPECT_EQ(password,
171 static_cast<std::string>(password_element_.value().utf8()));
172 EXPECT_EQ(password_autofilled, password_element_.isAutofilled());
175 void CheckUsernameSelection(int start, int end) {
176 EXPECT_EQ(start, username_element_.selectionStart());
177 EXPECT_EQ(end, username_element_.selectionEnd());
180 string16 username1_;
181 string16 username2_;
182 string16 username3_;
183 string16 password1_;
184 string16 password2_;
185 string16 password3_;
186 string16 alternate_username3_;
187 PasswordFormFillData fill_data_;
189 WebInputElement username_element_;
190 WebInputElement password_element_;
192 private:
193 DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgentTest);
196 // Tests that the password login is autocompleted as expected when the browser
197 // sends back the password info.
198 TEST_F(PasswordAutofillAgentTest, InitialAutocomplete) {
200 * Right now we are not sending the message to the browser because we are
201 * loading a data URL and the security origin canAccessPasswordManager()
202 * returns false. May be we should mock URL loading to cirmcuvent this?
203 TODO(jcivelli): find a way to make the security origin not deny access to the
204 password manager and then reenable this code.
206 // The form has been loaded, we should have sent the browser a message about
207 // the form.
208 const IPC::Message* msg = render_thread_.sink().GetFirstMessageMatching(
209 AutofillHostMsg_PasswordFormsParsed::ID);
210 ASSERT_TRUE(msg != NULL);
212 Tuple1<std::vector<PasswordForm> > forms;
213 AutofillHostMsg_PasswordFormsParsed::Read(msg, &forms);
214 ASSERT_EQ(1U, forms.a.size());
215 PasswordForm password_form = forms.a[0];
216 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form.scheme);
217 EXPECT_EQ(ASCIIToUTF16(kUsernameName), password_form.username_element);
218 EXPECT_EQ(ASCIIToUTF16(kPasswordName), password_form.password_element);
221 // Simulate the browser sending back the login info, it triggers the
222 // autocomplete.
223 SimulateOnFillPasswordForm(fill_data_);
225 // The username and password should have been autocompleted.
226 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
229 // Tests that we correctly fill forms having an empty 'action' attribute.
230 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForEmptyAction) {
231 const char kEmptyActionFormHTML[] =
232 "<FORM name='LoginTestForm'>"
233 " <INPUT type='text' id='username'/>"
234 " <INPUT type='password' id='password'/>"
235 " <INPUT type='submit' value='Login'/>"
236 "</FORM>";
237 LoadHTML(kEmptyActionFormHTML);
239 // Retrieve the input elements so the test can access them.
240 WebDocument document = GetMainFrame()->document();
241 WebElement element =
242 document.getElementById(WebString::fromUTF8(kUsernameName));
243 ASSERT_FALSE(element.isNull());
244 username_element_ = element.to<WebKit::WebInputElement>();
245 element = document.getElementById(WebString::fromUTF8(kPasswordName));
246 ASSERT_FALSE(element.isNull());
247 password_element_ = element.to<WebKit::WebInputElement>();
249 // Set the expected form origin and action URLs.
250 std::string origin("data:text/html;charset=utf-8,");
251 origin += kEmptyActionFormHTML;
252 fill_data_.basic_data.origin = GURL(origin);
253 fill_data_.basic_data.action = GURL(origin);
255 // Simulate the browser sending back the login info, it triggers the
256 // autocomplete.
257 SimulateOnFillPasswordForm(fill_data_);
259 // The username and password should have been autocompleted.
260 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
263 // Tests that if a password or input element is marked as readonly, neither
264 // field is autofilled on page load.
265 TEST_F(PasswordAutofillAgentTest, NoInitialAutocompleteForReadOnly) {
266 password_element_.setAttribute(WebString::fromUTF8("readonly"),
267 WebString::fromUTF8("true"));
269 // Simulate the browser sending back the login info, it triggers the
270 // autocomplete.
271 SimulateOnFillPasswordForm(fill_data_);
273 CheckTextFieldsState(std::string(), false, std::string(), false);
276 // Tests that having a non-matching username precludes the autocomplete.
277 TEST_F(PasswordAutofillAgentTest, NoInitialAutocompleteForFilledField) {
278 username_element_.setValue(WebString::fromUTF8("bogus"));
280 // Simulate the browser sending back the login info, it triggers the
281 // autocomplete.
282 SimulateOnFillPasswordForm(fill_data_);
284 // Neither field should be autocompleted.
285 CheckTextFieldsState("bogus", false, std::string(), false);
288 // Tests that we do not autofill username/passwords if marked as
289 // autocomplete="off".
290 TEST_F(PasswordAutofillAgentTest, NoInitialAutocompleteForAutocompleteOff) {
291 username_element_.setAttribute(WebString::fromUTF8("autocomplete"),
292 WebString::fromUTF8("off"));
294 // Simulate the browser sending back the login info, it triggers the
295 // autocomplete.
296 SimulateOnFillPasswordForm(fill_data_);
298 CheckTextFieldsState(std::string(), false, std::string(), false);
301 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForTextFieldPasswords) {
302 const char kTextFieldPasswordFormHTML[] =
303 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
304 " <INPUT type='text' id='username'/>"
305 " <INPUT type='text' id='password'/>"
306 " <INPUT type='submit' value='Login'/>"
307 "</FORM>";
308 LoadHTML(kTextFieldPasswordFormHTML);
310 // Retrieve the input elements so the test can access them.
311 WebDocument document = GetMainFrame()->document();
312 WebElement element =
313 document.getElementById(WebString::fromUTF8(kUsernameName));
314 ASSERT_FALSE(element.isNull());
315 username_element_ = element.to<WebKit::WebInputElement>();
316 element = document.getElementById(WebString::fromUTF8(kPasswordName));
317 ASSERT_FALSE(element.isNull());
318 password_element_ = element.to<WebKit::WebInputElement>();
320 // Set the expected form origin URL.
321 std::string origin("data:text/html;charset=utf-8,");
322 origin += kTextFieldPasswordFormHTML;
323 fill_data_.basic_data.origin = GURL(origin);
325 SimulateOnFillPasswordForm(fill_data_);
327 // Fields should still be empty.
328 CheckTextFieldsState(std::string(), false, std::string(), false);
331 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) {
332 const char kPasswordFieldUsernameFormHTML[] =
333 "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
334 " <INPUT type='password' id='username'/>"
335 " <INPUT type='password' id='password'/>"
336 " <INPUT type='submit' value='Login'/>"
337 "</FORM>";
338 LoadHTML(kPasswordFieldUsernameFormHTML);
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<WebKit::WebInputElement>();
346 element = document.getElementById(WebString::fromUTF8(kPasswordName));
347 ASSERT_FALSE(element.isNull());
348 password_element_ = element.to<WebKit::WebInputElement>();
350 // Set the expected form origin URL.
351 std::string origin("data:text/html;charset=utf-8,");
352 origin += kPasswordFieldUsernameFormHTML;
353 fill_data_.basic_data.origin = GURL(origin);
355 SimulateOnFillPasswordForm(fill_data_);
357 // Fields should still be empty.
358 CheckTextFieldsState(std::string(), false, std::string(), false);
361 // Tests that having a matching username does not preclude the autocomplete.
362 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) {
363 username_element_.setValue(WebString::fromUTF8(kAliceUsername));
365 // Simulate the browser sending back the login info, it triggers the
366 // autocomplete.
367 SimulateOnFillPasswordForm(fill_data_);
369 // The username and password should have been autocompleted.
370 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
373 // Tests that editing the password clears the autocompleted password field.
374 TEST_F(PasswordAutofillAgentTest, PasswordClearOnEdit) {
375 // Simulate the browser sending back the login info, it triggers the
376 // autocomplete.
377 SimulateOnFillPasswordForm(fill_data_);
379 // Simulate the user changing the username to some unknown username.
380 SimulateUsernameChange("alicia", true);
382 // The password should have been cleared.
383 CheckTextFieldsState("alicia", false, std::string(), false);
386 // Tests that we only autocomplete on focus lost and with a full username match
387 // when |wait_for_username| is true.
388 TEST_F(PasswordAutofillAgentTest, WaitUsername) {
389 // Simulate the browser sending back the login info.
390 fill_data_.wait_for_username = true;
391 SimulateOnFillPasswordForm(fill_data_);
393 // No auto-fill should have taken place.
394 CheckTextFieldsState(std::string(), false, std::string(), false);
396 // No autocomplete should happen when text is entered in the username.
397 SimulateUsernameChange("a", true);
398 CheckTextFieldsState("a", false, std::string(), false);
399 SimulateUsernameChange("al", true);
400 CheckTextFieldsState("al", false, std::string(), false);
401 SimulateUsernameChange(kAliceUsername, true);
402 CheckTextFieldsState(kAliceUsername, false, std::string(), false);
404 // Autocomplete should happen only when the username textfield is blurred with
405 // a full match.
406 username_element_.setValue("a");
407 autofill_agent_->textFieldDidEndEditing(username_element_);
408 CheckTextFieldsState("a", false, std::string(), false);
409 username_element_.setValue("al");
410 autofill_agent_->textFieldDidEndEditing(username_element_);
411 CheckTextFieldsState("al", false, std::string(), false);
412 username_element_.setValue("alices");
413 autofill_agent_->textFieldDidEndEditing(username_element_);
414 CheckTextFieldsState("alices", false, std::string(), false);
415 username_element_.setValue(ASCIIToUTF16(kAliceUsername));
416 autofill_agent_->textFieldDidEndEditing(username_element_);
417 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
420 // Tests that inline autocompletion works properly.
421 TEST_F(PasswordAutofillAgentTest, InlineAutocomplete) {
422 // Simulate the browser sending back the login info.
423 SimulateOnFillPasswordForm(fill_data_);
425 // Clear the text fields to start fresh.
426 ClearUsernameAndPasswordFields();
428 // Simulate the user typing in the first letter of 'alice', a stored username.
429 SimulateUsernameChange("a", true);
430 // Both the username and password text fields should reflect selection of the
431 // stored login.
432 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
433 // And the selection should have been set to 'lice', the last 4 letters.
434 CheckUsernameSelection(1, 5);
436 // Now the user types the next letter of the same username, 'l'.
437 SimulateUsernameChange("al", true);
438 // Now the fields should have the same value, but the selection should have a
439 // different start value.
440 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
441 CheckUsernameSelection(2, 5);
443 // Test that deleting does not trigger autocomplete.
444 SimulateKeyDownEvent(username_element_, ui::VKEY_BACK);
445 SimulateUsernameChange("alic", true);
446 CheckTextFieldsState("alic", false, std::string(), false);
447 CheckUsernameSelection(4, 4); // No selection.
448 // Reset the last pressed key to something other than backspace.
449 SimulateKeyDownEvent(username_element_, ui::VKEY_A);
451 // Now lets say the user goes astray from the stored username and types the
452 // letter 'f', spelling 'alf'. We don't know alf (that's just sad), so in
453 // practice the username should no longer be 'alice' and the selected range
454 // should be empty.
455 SimulateUsernameChange("alf", true);
456 CheckTextFieldsState("alf", false, std::string(), false);
457 CheckUsernameSelection(3, 3); // No selection.
459 // Ok, so now the user removes all the text and enters the letter 'b'.
460 SimulateUsernameChange("b", true);
461 // The username and password fields should match the 'bob' entry.
462 CheckTextFieldsState(kBobUsername, true, kBobPassword, true);
463 CheckUsernameSelection(1, 3);
465 // Then, the user again removes all the text and types an uppercase 'C'.
466 SimulateUsernameChange("C", true);
467 // The username and password fields should match the 'Carol' entry.
468 CheckTextFieldsState(kCarolUsername, true, kCarolPassword, true);
469 CheckUsernameSelection(1, 5);
470 // The user removes all the text and types a lowercase 'c'. We only
471 // want case-sensitive autocompletion, so the username and the selected range
472 // should be empty.
473 SimulateUsernameChange("c", true);
474 CheckTextFieldsState("c", false, std::string(), false);
475 CheckUsernameSelection(1, 1);
477 // Check that we complete other_possible_usernames as well.
478 SimulateUsernameChange("R", true);
479 CheckTextFieldsState(kCarolAlternateUsername, true, kCarolPassword, true);
480 CheckUsernameSelection(1, 17);
483 // Tests that selecting an item in the suggestion drop-down no-ops.
484 TEST_F(PasswordAutofillAgentTest, SuggestionSelect) {
485 // Simulate the browser sending back the login info.
486 SimulateOnFillPasswordForm(fill_data_);
488 // Clear the text fields to start fresh.
489 ClearUsernameAndPasswordFields();
491 // To simulate accepting an item in the suggestion drop-down we just mimic
492 // what the WebView does: it sets the element value then calls
493 // didSelectAutofillSuggestion on the renderer.
494 autofill_agent_->didSelectAutofillSuggestion(username_element_,
495 ASCIIToUTF16(kAliceUsername),
496 WebKit::WebString(),
498 // Autocomplete should not have kicked in.
499 CheckTextFieldsState(std::string(), false, std::string(), false);
502 } // namespace autofill