OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/strings/string_util.h" | 5 #include "base/strings/string_util.h" |
6 #include "base/strings/utf_string_conversions.h" | 6 #include "base/strings/utf_string_conversions.h" |
7 #include "chrome/test/base/chrome_render_view_test.h" | 7 #include "chrome/test/base/chrome_render_view_test.h" |
8 #include "components/autofill/content/common/autofill_messages.h" | 8 #include "components/autofill/content/common/autofill_messages.h" |
9 #include "components/autofill/content/renderer/autofill_agent.h" | 9 #include "components/autofill/content/renderer/autofill_agent.h" |
10 #include "components/autofill/content/renderer/form_autofill_util.h" | 10 #include "components/autofill/content/renderer/form_autofill_util.h" |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
247 void ClearUsernameAndPasswordFields() { | 247 void ClearUsernameAndPasswordFields() { |
248 username_element_.setValue(""); | 248 username_element_.setValue(""); |
249 username_element_.setAutofilled(false); | 249 username_element_.setAutofilled(false); |
250 password_element_.setValue(""); | 250 password_element_.setValue(""); |
251 password_element_.setAutofilled(false); | 251 password_element_.setAutofilled(false); |
252 } | 252 } |
253 | 253 |
254 void SimulateUsernameChangeForElement(const std::string& username, | 254 void SimulateUsernameChangeForElement(const std::string& username, |
255 bool move_caret_to_end, | 255 bool move_caret_to_end, |
256 WebFrame* input_frame, | 256 WebFrame* input_frame, |
257 WebInputElement& username_input) { | 257 WebInputElement& username_input, |
258 username_input.setValue(WebString::fromUTF8(username)); | 258 bool is_user_input) { |
259 username_input.setValue(WebString::fromUTF8(username), is_user_input); | |
259 // The field must have focus or AutofillAgent will think the | 260 // The field must have focus or AutofillAgent will think the |
260 // change should be ignored. | 261 // change should be ignored. |
261 while (!username_input.focused()) | 262 while (!username_input.focused()) |
262 input_frame->document().frame()->view()->advanceFocus(false); | 263 input_frame->document().frame()->view()->advanceFocus(false); |
263 if (move_caret_to_end) | 264 if (move_caret_to_end) |
264 username_input.setSelectionRange(username.length(), username.length()); | 265 username_input.setSelectionRange(username.length(), username.length()); |
266 if (is_user_input) | |
267 password_autofill_->set_user_gesture_occurred(true); | |
265 autofill_agent_->textFieldDidChange(username_input); | 268 autofill_agent_->textFieldDidChange(username_input); |
266 // Processing is delayed because of a Blink bug: | 269 // Processing is delayed because of a Blink bug: |
267 // https://bugs.webkit.org/show_bug.cgi?id=16976 | 270 // https://bugs.webkit.org/show_bug.cgi?id=16976 |
268 // See PasswordAutofillAgent::TextDidChangeInTextField() for details. | 271 // See PasswordAutofillAgent::TextDidChangeInTextField() for details. |
269 | 272 |
270 // Autocomplete will trigger a style recalculation when we put up the next | 273 // 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 | 274 // frame, but we don't want to wait that long. Instead, trigger a style |
272 // recalcuation manually after TextFieldDidChangeImpl runs. | 275 // recalcuation manually after TextFieldDidChangeImpl runs. |
273 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 276 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
274 &PasswordAutofillAgentTest::LayoutMainFrame, base::Unretained(this))); | 277 &PasswordAutofillAgentTest::LayoutMainFrame, base::Unretained(this))); |
275 | 278 |
276 base::MessageLoop::current()->RunUntilIdle(); | 279 base::MessageLoop::current()->RunUntilIdle(); |
277 } | 280 } |
278 | 281 |
282 void SimulateSuggestionChoice(const std::string& username, | |
283 WebInputElement& username_input) { | |
284 blink::WebString blink_username = blink::WebString::fromUTF8(username); | |
285 | |
286 // This call is necessary to setup the autofill agent appropriate for the | |
287 // user selection; simulates the menu actually popping up. | |
288 autofill_agent_->InputElementClicked(username_input, false, true); | |
289 | |
290 autofill_agent_->OnAcceptPasswordAutofillSuggestion(blink_username); | |
291 } | |
292 | |
279 void LayoutMainFrame() { | 293 void LayoutMainFrame() { |
280 GetMainFrame()->view()->layout(); | 294 GetMainFrame()->view()->layout(); |
281 } | 295 } |
282 | 296 |
283 void SimulateUsernameChange(const std::string& username, | 297 void SimulateUsernameChange(const std::string& username, |
284 bool move_caret_to_end) { | 298 bool move_caret_to_end, |
285 SimulateUsernameChangeForElement(username, move_caret_to_end, | 299 bool is_user_input = false) { |
286 GetMainFrame(), username_element_); | 300 SimulateUsernameChangeForElement(username, |
301 move_caret_to_end, | |
302 GetMainFrame(), | |
303 username_element_, | |
304 is_user_input); | |
287 } | 305 } |
288 | 306 |
289 // Tests that no suggestion popup is generated when the username_element_ is | 307 // Tests that no suggestion popup is generated when the username_element_ is |
290 // edited. | 308 // edited. |
291 void ExpectNoSuggestionsPopup() { | 309 void ExpectNoSuggestionsPopup() { |
292 // The first test below ensures that the suggestions have been handled by | 310 // The first test below ensures that the suggestions have been handled by |
293 // the password_autofill_agent, even though autocomplete='off' is set. The | 311 // the password_autofill_agent, even though autocomplete='off' is set. The |
294 // second check ensures that, although handled, no "show suggestions" IPC to | 312 // second check ensures that, although handled, no "show suggestions" IPC to |
295 // the browser was generated. | 313 // the browser was generated. |
296 // | 314 // |
297 // This is interesting in the specific case of an autocomplete='off' form | 315 // This is interesting in the specific case of an autocomplete='off' form |
298 // that also has a remembered username and password | 316 // that also has a remembered username and password |
299 // (http://crbug.com/326679). To fix the DCHECK that this case used to hit, | 317 // (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 | 318 // |true| is returned from ShowSuggestions for all forms with valid |
301 // usersnames that are autocomplete='off', prentending that a selection box | 319 // 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 | 320 // 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 | 321 // sent to the browser on acceptance, and the DCHECK isn't hit (and nothing |
304 // is filled). | 322 // is filled). |
305 // | 323 // |
306 // These tests only make sense in the context of not ignoring | 324 // These tests only make sense in the context of not ignoring |
307 // autocomplete='off', so only test them if the disable autocomplete='off' | 325 // autocomplete='off', so only test them if the disable autocomplete='off' |
308 // flag is not enabled. | 326 // flag is not enabled. |
309 // TODO(jww): Remove this function and callers once autocomplete='off' is | 327 // TODO(jww): Remove this function and callers once autocomplete='off' is |
310 // permanently ignored. | 328 // permanently ignored. |
311 if (!ShouldIgnoreAutocompleteOffForPasswordFields()) { | 329 if (!ShouldIgnoreAutocompleteOffForPasswordFields()) { |
312 EXPECT_TRUE(autofill_agent_->password_autofill_agent_->ShowSuggestions( | 330 EXPECT_TRUE(autofill_agent_->password_autofill_agent_->ShowSuggestions( |
313 username_element_)); | 331 username_element_, false)); |
314 | 332 |
315 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( | 333 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( |
316 AutofillHostMsg_ShowPasswordSuggestions::ID)); | 334 AutofillHostMsg_ShowPasswordSuggestions::ID)); |
317 } | 335 } |
318 } | 336 } |
319 | 337 |
320 void SimulateKeyDownEvent(const WebInputElement& element, | 338 void SimulateKeyDownEvent(const WebInputElement& element, |
321 ui::KeyboardCode key_code) { | 339 ui::KeyboardCode key_code) { |
322 blink::WebKeyboardEvent key_event; | 340 blink::WebKeyboardEvent key_event; |
323 key_event.windowsKeyCode = key_code; | 341 key_event.windowsKeyCode = key_code; |
324 autofill_agent_->textFieldDidReceiveKeyDown(element, key_event); | 342 autofill_agent_->textFieldDidReceiveKeyDown(element, key_event); |
325 } | 343 } |
326 | 344 |
327 void CheckTextFieldsStateForElements(const WebInputElement& username_element, | 345 void CheckTextFieldsStateForElements(const WebInputElement& username_element, |
328 const std::string& username, | 346 const std::string& username, |
329 bool username_autofilled, | 347 bool username_autofilled, |
330 const WebInputElement& password_element, | 348 const WebInputElement& password_element, |
331 const std::string& password, | 349 const std::string& password, |
332 bool password_autofilled, | 350 bool password_autofilled, |
333 bool checkSuggestedValue = true) { | 351 bool checkSuggestedValue) { |
334 EXPECT_EQ(username, | 352 EXPECT_EQ(username, |
335 static_cast<std::string>(username_element.value().utf8())); | 353 static_cast<std::string>(username_element.value().utf8())); |
336 EXPECT_EQ(username_autofilled, username_element.isAutofilled()); | 354 EXPECT_EQ(username_autofilled, username_element.isAutofilled()); |
337 EXPECT_EQ(password, | 355 EXPECT_EQ(password, |
338 static_cast<std::string>( | 356 static_cast<std::string>( |
339 checkSuggestedValue ? password_element.suggestedValue().utf8() | 357 checkSuggestedValue ? password_element.suggestedValue().utf8() |
340 : password_element.value().utf8())); | 358 : password_element.value().utf8())); |
341 EXPECT_EQ(password_autofilled, password_element.isAutofilled()); | 359 EXPECT_EQ(password_autofilled, password_element.isAutofilled()); |
342 } | 360 } |
343 | 361 |
344 // Checks the DOM-accessible value of the username element and the | 362 // Checks the DOM-accessible value of the username element and the |
345 // *suggested* value of the password element. | 363 // *suggested* value of the password element. |
346 void CheckTextFieldsState(const std::string& username, | 364 void CheckTextFieldsState(const std::string& username, |
347 bool username_autofilled, | 365 bool username_autofilled, |
348 const std::string& password, | 366 const std::string& password, |
349 bool password_autofilled) { | 367 bool password_autofilled) { |
350 CheckTextFieldsStateForElements(username_element_, username, | 368 CheckTextFieldsStateForElements(username_element_, |
351 username_autofilled, password_element_, | 369 username, |
352 password, password_autofilled); | 370 username_autofilled, |
371 password_element_, | |
372 password, | |
373 password_autofilled, | |
374 true); | |
353 } | 375 } |
354 | 376 |
355 // Checks the DOM-accessible value of the username element and the | 377 // Checks the DOM-accessible value of the username element and the |
356 // DOM-accessible value of the password element. | 378 // DOM-accessible value of the password element. |
357 void CheckTextFieldsDOMState(const std::string& username, | 379 void CheckTextFieldsDOMState(const std::string& username, |
358 bool username_autofilled, | 380 bool username_autofilled, |
359 const std::string& password, | 381 const std::string& password, |
360 bool password_autofilled) { | 382 bool password_autofilled) { |
361 CheckTextFieldsStateForElements(username_element_, | 383 CheckTextFieldsStateForElements(username_element_, |
362 username, | 384 username, |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
638 username_element_.setValue(ASCIIToUTF16(kAliceUsername)); | 660 username_element_.setValue(ASCIIToUTF16(kAliceUsername)); |
639 autofill_agent_->textFieldDidEndEditing(username_element_); | 661 autofill_agent_->textFieldDidEndEditing(username_element_); |
640 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | 662 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); |
641 } | 663 } |
642 | 664 |
643 // Tests that inline autocompletion works properly. | 665 // Tests that inline autocompletion works properly. |
644 TEST_F(PasswordAutofillAgentTest, InlineAutocomplete) { | 666 TEST_F(PasswordAutofillAgentTest, InlineAutocomplete) { |
645 // Simulate the browser sending back the login info. | 667 // Simulate the browser sending back the login info. |
646 SimulateOnFillPasswordForm(fill_data_); | 668 SimulateOnFillPasswordForm(fill_data_); |
647 | 669 |
648 // Clear the text fields to start fresh. | |
649 ClearUsernameAndPasswordFields(); | 670 ClearUsernameAndPasswordFields(); |
650 | 671 |
651 // Simulate the user typing in the first letter of 'alice', a stored username. | 672 // Simulate the user typing in the first letter of 'alice', a stored |
673 // username. | |
652 SimulateUsernameChange("a", true); | 674 SimulateUsernameChange("a", true); |
653 // Both the username and password text fields should reflect selection of the | 675 // Both the username and password text fields should reflect selection of the |
654 // stored login. | 676 // stored login. |
655 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | 677 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); |
656 // And the selection should have been set to 'lice', the last 4 letters. | 678 // And the selection should have been set to 'lice', the last 4 letters. |
657 CheckUsernameSelection(1, 5); | 679 CheckUsernameSelection(1, 5); |
658 | 680 |
659 // Now the user types the next letter of the same username, 'l'. | 681 // Now the user types the next letter of the same username, 'l'. |
660 SimulateUsernameChange("al", true); | 682 SimulateUsernameChange("al", true); |
661 // Now the fields should have the same value, but the selection should have a | 683 // Now the fields should have the same value, but the selection should have a |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
815 | 837 |
816 WebElement username_element = document.getElementById(kUsernameName); | 838 WebElement username_element = document.getElementById(kUsernameName); |
817 WebElement password_element = document.getElementById(kPasswordName); | 839 WebElement password_element = document.getElementById(kPasswordName); |
818 ASSERT_FALSE(username_element.isNull()); | 840 ASSERT_FALSE(username_element.isNull()); |
819 ASSERT_FALSE(password_element.isNull()); | 841 ASSERT_FALSE(password_element.isNull()); |
820 | 842 |
821 WebInputElement username_input = username_element.to<WebInputElement>(); | 843 WebInputElement username_input = username_element.to<WebInputElement>(); |
822 WebInputElement password_input = password_element.to<WebInputElement>(); | 844 WebInputElement password_input = password_element.to<WebInputElement>(); |
823 ASSERT_FALSE(username_element.isNull()); | 845 ASSERT_FALSE(username_element.isNull()); |
824 | 846 |
825 CheckTextFieldsStateForElements(username_input, "", false, | 847 CheckTextFieldsStateForElements( |
826 password_input, "", false); | 848 username_input, "", false, password_input, "", false, false); |
827 | 849 |
828 // Simulate the user typing in the username in the iframe, which should cause | 850 // Simulate the user typing in the username in the iframe and then selecting |
829 // an autofill. | 851 // the autofill choice from the dropdown, thus causing an autofill. |
Garrett Casto
2014/02/24 23:45:09
Just calling textFieldDidEndEditing() (or possibly
jww
2014/03/05 02:11:49
Calling textFieldDidEndEditing() is insufficient b
| |
830 SimulateUsernameChangeForElement(kAliceUsername, true, | 852 SimulateUsernameChangeForElement( |
831 iframe, username_input); | 853 kAliceUsername, true, iframe, username_input, false); |
854 SimulateElementClick(kUsernameName); | |
855 SimulateSuggestionChoice(kAliceUsername, username_input); | |
832 | 856 |
833 CheckTextFieldsStateForElements(username_input, kAliceUsername, true, | 857 CheckTextFieldsStateForElements(username_input, |
834 password_input, kAlicePassword, true); | 858 kAliceUsername, |
859 true, | |
860 password_input, | |
861 kAlicePassword, | |
862 true, | |
863 false); | |
835 } | 864 } |
836 | 865 |
837 // Tests that a password will only be filled as a suggested and will not be | 866 // 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. | 867 // accessible by the DOM until a user gesture has occurred. |
839 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) { | 868 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) { |
840 // Trigger the initial autocomplete. | 869 // Trigger the initial autocomplete. |
841 SimulateOnFillPasswordForm(fill_data_); | 870 SimulateOnFillPasswordForm(fill_data_); |
842 | 871 |
843 // The username and password should have been autocompleted. | 872 // The username and password should have been autocompleted. |
844 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | 873 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
986 fill_data_.wait_for_username = true; | 1015 fill_data_.wait_for_username = true; |
987 SimulateOnFillPasswordForm(fill_data_); | 1016 SimulateOnFillPasswordForm(fill_data_); |
988 | 1017 |
989 // The username and password should not yet have been autocompleted. | 1018 // The username and password should not yet have been autocompleted. |
990 CheckTextFieldsState(std::string(), false, std::string(), false); | 1019 CheckTextFieldsState(std::string(), false, std::string(), false); |
991 | 1020 |
992 // Simulate a click just to force a user gesture, since the username value is | 1021 // Simulate a click just to force a user gesture, since the username value is |
993 // set directly. | 1022 // set directly. |
994 SimulateElementClick(kUsernameName); | 1023 SimulateElementClick(kUsernameName); |
995 | 1024 |
996 // Simulate the user entering her username. | 1025 // Simulate the user entering her username and selecting the matching autofill |
997 username_element_.setValue(ASCIIToUTF16(kAliceUsername), true); | 1026 // from the dropdown. |
998 autofill_agent_->textFieldDidEndEditing(username_element_); | 1027 SimulateUsernameChange(kAliceUsername, true, true); |
1028 SimulateSuggestionChoice(kAliceUsername, username_element_); | |
999 | 1029 |
1000 // The username and password should now have been autocompleted. | 1030 // The username and password should now have been autocompleted. |
1001 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); | 1031 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); |
1002 | 1032 |
1003 // JavaScript onChange events should have been triggered both for the username | 1033 // JavaScript onChange events should have been triggered both for the username |
1004 // and for the password. | 1034 // and for the password. |
1005 int username_onchange_called = -1; | 1035 int username_onchange_called = -1; |
1006 int password_onchange_called = -1; | 1036 int password_onchange_called = -1; |
1007 ASSERT_TRUE( | 1037 ASSERT_TRUE( |
1008 ExecuteJavaScriptAndReturnIntValue( | 1038 ExecuteJavaScriptAndReturnIntValue( |
1009 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"), | 1039 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"), |
1010 &username_onchange_called)); | 1040 &username_onchange_called)); |
1011 EXPECT_EQ(1, username_onchange_called); | 1041 EXPECT_EQ(1, username_onchange_called); |
1012 ASSERT_TRUE( | 1042 ASSERT_TRUE( |
1013 ExecuteJavaScriptAndReturnIntValue( | 1043 ExecuteJavaScriptAndReturnIntValue( |
1014 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"), | 1044 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"), |
1015 &password_onchange_called)); | 1045 &password_onchange_called)); |
1016 EXPECT_EQ(1, password_onchange_called); | 1046 EXPECT_EQ(1, password_onchange_called); |
1017 } | 1047 } |
1018 | 1048 |
1049 // Tests that autocomplete works when the user clicks on an element and chooses | |
1050 // a suggestion from the autofill suggestion list. { | |
Garrett Casto
2014/02/24 23:45:09
1) I think that this test is trying to verify that
jww
2014/03/05 02:11:49
I've update the comment to be more specific, but d
| |
1051 TEST_F(PasswordAutofillAgentTest, ClickAndSelect) { | |
1052 // Simulate the browser sending back the login info. | |
1053 SimulateOnFillPasswordForm(fill_data_); | |
1054 | |
1055 // Clear the text fields to start fresh. | |
1056 ClearUsernameAndPasswordFields(); | |
1057 | |
1058 SimulateElementClick(kUsernameName); | |
Garrett Casto
2014/02/24 23:45:09
Is this necessary to focus the element? As it's cu
jww
2014/03/05 02:11:49
Yeah, it's a bit odd because the SimulateElementCl
| |
1059 SimulateSuggestionChoice(kAliceUsername, username_element_); | |
1060 | |
1061 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); | |
1062 } | |
1063 | |
1019 } // namespace autofill | 1064 } // namespace autofill |
OLD | NEW |