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 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 const char kJavaScriptClick[] = | 137 const char kJavaScriptClick[] = |
138 "var event = new MouseEvent('click', {" | 138 "var event = new MouseEvent('click', {" |
139 " 'view': window," | 139 " 'view': window," |
140 " 'bubbles': true," | 140 " 'bubbles': true," |
141 " 'cancelable': true" | 141 " 'cancelable': true" |
142 "});" | 142 "});" |
143 "var form = document.getElementById('myform1');" | 143 "var form = document.getElementById('myform1');" |
144 "form.dispatchEvent(event);" | 144 "form.dispatchEvent(event);" |
145 "console.log('clicked!');"; | 145 "console.log('clicked!');"; |
146 | 146 |
| 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>"; |
| 158 |
147 } // namespace | 159 } // namespace |
148 | 160 |
149 namespace autofill { | 161 namespace autofill { |
150 | 162 |
151 class PasswordAutofillAgentTest : public ChromeRenderViewTest { | 163 class PasswordAutofillAgentTest : public ChromeRenderViewTest { |
152 public: | 164 public: |
153 PasswordAutofillAgentTest() { | 165 PasswordAutofillAgentTest() { |
154 } | 166 } |
155 | 167 |
156 // Simulates the fill password form message being sent to the renderer. | 168 // Simulates the fill password form message being sent to the renderer. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 fill_data_.additional_logins[username3_] = password3; | 205 fill_data_.additional_logins[username3_] = password3; |
194 | 206 |
195 UsernamesCollectionKey key; | 207 UsernamesCollectionKey key; |
196 key.username = username3_; | 208 key.username = username3_; |
197 key.password = password3_; | 209 key.password = password3_; |
198 key.realm = "google.com"; | 210 key.realm = "google.com"; |
199 fill_data_.other_possible_usernames[key].push_back(alternate_username3_); | 211 fill_data_.other_possible_usernames[key].push_back(alternate_username3_); |
200 | 212 |
201 // We need to set the origin so it matches the frame URL and the action so | 213 // We need to set the origin so it matches the frame URL and the action so |
202 // it matches the form action, otherwise we won't autocomplete. | 214 // it matches the form action, otherwise we won't autocomplete. |
203 std::string origin("data:text/html;charset=utf-8,"); | 215 UpdateOriginForHTML(kFormHTML); |
204 origin += kFormHTML; | |
205 fill_data_.basic_data.origin = GURL(origin); | |
206 fill_data_.basic_data.action = GURL("http://www.bidule.com"); | 216 fill_data_.basic_data.action = GURL("http://www.bidule.com"); |
207 | 217 |
208 LoadHTML(kFormHTML); | 218 LoadHTML(kFormHTML); |
209 | 219 |
210 // Now retrieves the input elements so the test can access them. | 220 // Now retrieve the input elements so the test can access them. |
| 221 UpdateUsernameAndPasswordElements(); |
| 222 } |
| 223 |
| 224 virtual void TearDown() { |
| 225 username_element_.reset(); |
| 226 password_element_.reset(); |
| 227 ChromeRenderViewTest::TearDown(); |
| 228 } |
| 229 |
| 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); |
| 233 } |
| 234 |
| 235 void UpdateUsernameAndPasswordElements() { |
211 WebDocument document = GetMainFrame()->document(); | 236 WebDocument document = GetMainFrame()->document(); |
212 WebElement element = | 237 WebElement element = |
213 document.getElementById(WebString::fromUTF8(kUsernameName)); | 238 document.getElementById(WebString::fromUTF8(kUsernameName)); |
214 ASSERT_FALSE(element.isNull()); | 239 ASSERT_FALSE(element.isNull()); |
215 username_element_ = element.to<blink::WebInputElement>(); | 240 username_element_ = element.to<blink::WebInputElement>(); |
216 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 241 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
217 ASSERT_FALSE(element.isNull()); | 242 ASSERT_FALSE(element.isNull()); |
218 password_element_ = element.to<blink::WebInputElement>(); | 243 password_element_ = element.to<blink::WebInputElement>(); |
219 } | 244 } |
220 | 245 |
221 virtual void TearDown() { | |
222 username_element_.reset(); | |
223 password_element_.reset(); | |
224 ChromeRenderViewTest::TearDown(); | |
225 } | |
226 | |
227 void ClearUsernameAndPasswordFields() { | 246 void ClearUsernameAndPasswordFields() { |
228 username_element_.setValue(""); | 247 username_element_.setValue(""); |
229 username_element_.setAutofilled(false); | 248 username_element_.setAutofilled(false); |
230 password_element_.setValue(""); | 249 password_element_.setValue(""); |
231 password_element_.setAutofilled(false); | 250 password_element_.setAutofilled(false); |
232 } | 251 } |
233 | 252 |
234 void SimulateUsernameChangeForElement(const std::string& username, | 253 void SimulateUsernameChangeForElement(const std::string& username, |
235 bool move_caret_to_end, | 254 bool move_caret_to_end, |
236 WebFrame* input_frame, | 255 WebFrame* input_frame, |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 WebDocument document = GetMainFrame()->document(); | 414 WebDocument document = GetMainFrame()->document(); |
396 WebElement element = | 415 WebElement element = |
397 document.getElementById(WebString::fromUTF8(kUsernameName)); | 416 document.getElementById(WebString::fromUTF8(kUsernameName)); |
398 ASSERT_FALSE(element.isNull()); | 417 ASSERT_FALSE(element.isNull()); |
399 username_element_ = element.to<blink::WebInputElement>(); | 418 username_element_ = element.to<blink::WebInputElement>(); |
400 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 419 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
401 ASSERT_FALSE(element.isNull()); | 420 ASSERT_FALSE(element.isNull()); |
402 password_element_ = element.to<blink::WebInputElement>(); | 421 password_element_ = element.to<blink::WebInputElement>(); |
403 | 422 |
404 // Set the expected form origin and action URLs. | 423 // Set the expected form origin and action URLs. |
405 std::string origin("data:text/html;charset=utf-8,"); | 424 UpdateOriginForHTML(kEmptyActionFormHTML); |
406 origin += kEmptyActionFormHTML; | 425 fill_data_.basic_data.action = fill_data_.basic_data.origin; |
407 fill_data_.basic_data.origin = GURL(origin); | |
408 fill_data_.basic_data.action = GURL(origin); | |
409 | 426 |
410 // Simulate the browser sending back the login info, it triggers the | 427 // Simulate the browser sending back the login info, it triggers the |
411 // autocomplete. | 428 // autocomplete. |
412 SimulateOnFillPasswordForm(fill_data_); | 429 SimulateOnFillPasswordForm(fill_data_); |
413 | 430 |
414 // The username and password should have been autocompleted. | 431 // The username and password should have been autocompleted. |
415 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | 432 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); |
416 } | 433 } |
417 | 434 |
418 // Tests that if a password is marked as readonly, neither field is autofilled | 435 // Tests that if a password is marked as readonly, neither field is autofilled |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 WebDocument document = GetMainFrame()->document(); | 517 WebDocument document = GetMainFrame()->document(); |
501 WebElement element = | 518 WebElement element = |
502 document.getElementById(WebString::fromUTF8(kUsernameName)); | 519 document.getElementById(WebString::fromUTF8(kUsernameName)); |
503 ASSERT_FALSE(element.isNull()); | 520 ASSERT_FALSE(element.isNull()); |
504 username_element_ = element.to<blink::WebInputElement>(); | 521 username_element_ = element.to<blink::WebInputElement>(); |
505 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 522 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
506 ASSERT_FALSE(element.isNull()); | 523 ASSERT_FALSE(element.isNull()); |
507 password_element_ = element.to<blink::WebInputElement>(); | 524 password_element_ = element.to<blink::WebInputElement>(); |
508 | 525 |
509 // Set the expected form origin URL. | 526 // Set the expected form origin URL. |
510 std::string origin("data:text/html;charset=utf-8,"); | 527 UpdateOriginForHTML(kTextFieldPasswordFormHTML); |
511 origin += kTextFieldPasswordFormHTML; | |
512 fill_data_.basic_data.origin = GURL(origin); | |
513 | 528 |
514 SimulateOnFillPasswordForm(fill_data_); | 529 SimulateOnFillPasswordForm(fill_data_); |
515 | 530 |
516 // Fields should still be empty. | 531 // Fields should still be empty. |
517 CheckTextFieldsState(std::string(), false, std::string(), false); | 532 CheckTextFieldsState(std::string(), false, std::string(), false); |
518 } | 533 } |
519 | 534 |
520 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) { | 535 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) { |
521 const char kPasswordFieldUsernameFormHTML[] = | 536 const char kPasswordFieldUsernameFormHTML[] = |
522 "<FORM name='LoginTestForm' action='http://www.bidule.com'>" | 537 "<FORM name='LoginTestForm' action='http://www.bidule.com'>" |
523 " <INPUT type='password' id='username'/>" | 538 " <INPUT type='password' id='username'/>" |
524 " <INPUT type='password' id='password'/>" | 539 " <INPUT type='password' id='password'/>" |
525 " <INPUT type='submit' value='Login'/>" | 540 " <INPUT type='submit' value='Login'/>" |
526 "</FORM>"; | 541 "</FORM>"; |
527 LoadHTML(kPasswordFieldUsernameFormHTML); | 542 LoadHTML(kPasswordFieldUsernameFormHTML); |
528 | 543 |
529 // Retrieve the input elements so the test can access them. | 544 // Retrieve the input elements so the test can access them. |
530 WebDocument document = GetMainFrame()->document(); | 545 WebDocument document = GetMainFrame()->document(); |
531 WebElement element = | 546 WebElement element = |
532 document.getElementById(WebString::fromUTF8(kUsernameName)); | 547 document.getElementById(WebString::fromUTF8(kUsernameName)); |
533 ASSERT_FALSE(element.isNull()); | 548 ASSERT_FALSE(element.isNull()); |
534 username_element_ = element.to<blink::WebInputElement>(); | 549 username_element_ = element.to<blink::WebInputElement>(); |
535 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 550 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
536 ASSERT_FALSE(element.isNull()); | 551 ASSERT_FALSE(element.isNull()); |
537 password_element_ = element.to<blink::WebInputElement>(); | 552 password_element_ = element.to<blink::WebInputElement>(); |
538 | 553 |
539 // Set the expected form origin URL. | 554 // Set the expected form origin URL. |
540 std::string origin("data:text/html;charset=utf-8,"); | 555 UpdateOriginForHTML(kPasswordFieldUsernameFormHTML); |
541 origin += kPasswordFieldUsernameFormHTML; | |
542 fill_data_.basic_data.origin = GURL(origin); | |
543 | 556 |
544 SimulateOnFillPasswordForm(fill_data_); | 557 SimulateOnFillPasswordForm(fill_data_); |
545 | 558 |
546 // Fields should still be empty. | 559 // Fields should still be empty. |
547 CheckTextFieldsState(std::string(), false, std::string(), false); | 560 CheckTextFieldsState(std::string(), false, std::string(), false); |
548 } | 561 } |
549 | 562 |
550 // Tests that having a matching username does not preclude the autocomplete. | 563 // Tests that having a matching username does not preclude the autocomplete. |
551 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) { | 564 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) { |
552 username_element_.setValue(WebString::fromUTF8(kAliceUsername)); | 565 username_element_.setValue(WebString::fromUTF8(kAliceUsername)); |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) { | 818 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) { |
806 // Trigger the initial autocomplete. | 819 // Trigger the initial autocomplete. |
807 SimulateOnFillPasswordForm(fill_data_); | 820 SimulateOnFillPasswordForm(fill_data_); |
808 | 821 |
809 // The username and password should have been autocompleted. | 822 // The username and password should have been autocompleted. |
810 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | 823 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); |
811 | 824 |
812 // However, it should only have completed with the suggested value, as tested | 825 // However, it should only have completed with the suggested value, as tested |
813 // above, and it should not have completed into the DOM accessible value for | 826 // above, and it should not have completed into the DOM accessible value for |
814 // the password field. | 827 // the password field. |
815 CheckTextFieldsDOMState(kAliceUsername, true, "", true); | 828 CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true); |
816 | 829 |
817 // Simulate a user click so that the password field's real value is filled. | 830 // Simulate a user click so that the password field's real value is filled. |
818 SimulateElementClick(kUsernameName); | 831 SimulateElementClick(kUsernameName); |
819 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); | 832 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); |
820 } | 833 } |
821 | 834 |
822 // Verfies that a DOM-activated UI event will not cause an autofill. | 835 // Verfies that a DOM-activated UI event will not cause an autofill. |
823 TEST_F(PasswordAutofillAgentTest, NoDOMActivationTest) { | 836 TEST_F(PasswordAutofillAgentTest, NoDOMActivationTest) { |
824 // Trigger the initial autocomplete. | 837 // Trigger the initial autocomplete. |
825 SimulateOnFillPasswordForm(fill_data_); | 838 SimulateOnFillPasswordForm(fill_data_); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
861 | 874 |
862 // Regression test for http://crbug.com/326679 | 875 // Regression test for http://crbug.com/326679 |
863 TEST_F(PasswordAutofillAgentTest, SelectUsernameWithPasswordAutofillOff) { | 876 TEST_F(PasswordAutofillAgentTest, SelectUsernameWithPasswordAutofillOff) { |
864 // Simulate the browser sending back the login info. | 877 // Simulate the browser sending back the login info. |
865 SimulateOnFillPasswordForm(fill_data_); | 878 SimulateOnFillPasswordForm(fill_data_); |
866 | 879 |
867 // Set the main password element to autocomplete='off' | 880 // Set the main password element to autocomplete='off' |
868 password_element_.setAttribute(WebString::fromUTF8("autocomplete"), | 881 password_element_.setAttribute(WebString::fromUTF8("autocomplete"), |
869 WebString::fromUTF8("off")); | 882 WebString::fromUTF8("off")); |
870 | 883 |
871 // Simulate the user changing the username to some known username. | 884 // Simulate the user changing the username to some known username. |
872 SimulateUsernameChange(kAliceUsername, true); | 885 SimulateUsernameChange(kAliceUsername, true); |
873 | 886 |
874 ExpectNoSuggestionsPopup(); | 887 ExpectNoSuggestionsPopup(); |
875 } | 888 } |
876 | 889 |
877 // Regression test for http://crbug.com/326679 | 890 // Regression test for http://crbug.com/326679 |
878 TEST_F(PasswordAutofillAgentTest, | 891 TEST_F(PasswordAutofillAgentTest, |
879 SelectUnknownUsernameWithPasswordAutofillOff) { | 892 SelectUnknownUsernameWithPasswordAutofillOff) { |
880 // Simulate the browser sending back the login info. | 893 // Simulate the browser sending back the login info. |
881 SimulateOnFillPasswordForm(fill_data_); | 894 SimulateOnFillPasswordForm(fill_data_); |
882 | 895 |
883 // Set the main password element to autocomplete='off' | 896 // Set the main password element to autocomplete='off' |
884 password_element_.setAttribute(WebString::fromUTF8("autocomplete"), | 897 password_element_.setAttribute(WebString::fromUTF8("autocomplete"), |
885 WebString::fromUTF8("off")); | 898 WebString::fromUTF8("off")); |
886 | 899 |
887 // Simulate the user changing the username to some unknown username. | 900 // Simulate the user changing the username to some unknown username. |
888 SimulateUsernameChange("foo", true); | 901 SimulateUsernameChange("foo", true); |
889 | 902 |
890 ExpectNoSuggestionsPopup(); | 903 ExpectNoSuggestionsPopup(); |
891 } | 904 } |
892 | 905 |
| 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(); |
| 914 |
| 915 // Simulate the browser sending back the login info, it triggers the |
| 916 // autocomplete. |
| 917 SimulateOnFillPasswordForm(fill_data_); |
| 918 |
| 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); |
| 924 |
| 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); |
| 940 |
| 941 // Simulate a user click so that the password field's real value is filled. |
| 942 SimulateElementClick(kUsernameName); |
| 943 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); |
| 944 |
| 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); |
| 952 } |
| 953 |
| 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(); |
| 962 |
| 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_); |
| 967 |
| 968 // The username and password should not yet have been autocompleted. |
| 969 CheckTextFieldsState(std::string(), false, std::string(), false); |
| 970 |
| 971 // Simulate a click just to force a user gesture, since the username value is |
| 972 // set directly. |
| 973 SimulateElementClick(kUsernameName); |
| 974 |
| 975 // Simulate the user entering her username. |
| 976 username_element_.setValue(ASCIIToUTF16(kAliceUsername), true); |
| 977 autofill_agent_->textFieldDidEndEditing(username_element_); |
| 978 |
| 979 // The username and password should now have been autocompleted. |
| 980 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); |
| 981 |
| 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); |
| 996 } |
| 997 |
893 } // namespace autofill | 998 } // namespace autofill |
OLD | NEW |