| 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. |
| 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. { |
| 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); |
| 1059 SimulateSuggestionChoice(kAliceUsername, username_element_); |
| 1060 |
| 1061 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); |
| 1062 } |
| 1063 |
| 1019 } // namespace autofill | 1064 } // namespace autofill |
| OLD | NEW |