Chromium Code Reviews| 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 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 const char kJavaScriptClick[] = | 135 const char kJavaScriptClick[] = |
| 136 "var event = new MouseEvent('click', {" | 136 "var event = new MouseEvent('click', {" |
| 137 " 'view': window," | 137 " 'view': window," |
| 138 " 'bubbles': true," | 138 " 'bubbles': true," |
| 139 " 'cancelable': true" | 139 " 'cancelable': true" |
| 140 "});" | 140 "});" |
| 141 "var form = document.getElementById('myform1');" | 141 "var form = document.getElementById('myform1');" |
| 142 "form.dispatchEvent(event);" | 142 "form.dispatchEvent(event);" |
| 143 "console.log('clicked!');"; | 143 "console.log('clicked!');"; |
| 144 | 144 |
| 145 const char kOnChangeDetectionScript[] = | |
| 146 "<script>" | |
| 147 " usernameOnchangeCalled = false;" | |
| 148 " passwordOnchangeCalled = false;" | |
| 149 " document.getElementById('username').onchange = function() {" | |
| 150 " usernameOnchangeCalled = true;" | |
| 151 " };" | |
| 152 " document.getElementById('password').onchange = function() {" | |
| 153 " passwordOnchangeCalled = true;" | |
| 154 " };" | |
| 155 "</script>"; | |
| 156 | |
| 145 } // namespace | 157 } // namespace |
| 146 | 158 |
| 147 namespace autofill { | 159 namespace autofill { |
| 148 | 160 |
| 149 class PasswordAutofillAgentTest : public ChromeRenderViewTest { | 161 class PasswordAutofillAgentTest : public ChromeRenderViewTest { |
| 150 public: | 162 public: |
| 151 PasswordAutofillAgentTest() { | 163 PasswordAutofillAgentTest() { |
| 152 } | 164 } |
| 153 | 165 |
| 154 // Simulates the fill password form message being sent to the renderer. | 166 // Simulates the fill password form message being sent to the renderer. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 fill_data_.additional_logins[username3_] = password3; | 203 fill_data_.additional_logins[username3_] = password3; |
| 192 | 204 |
| 193 UsernamesCollectionKey key; | 205 UsernamesCollectionKey key; |
| 194 key.username = username3_; | 206 key.username = username3_; |
| 195 key.password = password3_; | 207 key.password = password3_; |
| 196 key.realm = "google.com"; | 208 key.realm = "google.com"; |
| 197 fill_data_.other_possible_usernames[key].push_back(alternate_username3_); | 209 fill_data_.other_possible_usernames[key].push_back(alternate_username3_); |
| 198 | 210 |
| 199 // We need to set the origin so it matches the frame URL and the action so | 211 // We need to set the origin so it matches the frame URL and the action so |
| 200 // it matches the form action, otherwise we won't autocomplete. | 212 // it matches the form action, otherwise we won't autocomplete. |
| 201 std::string origin("data:text/html;charset=utf-8,"); | 213 UpdateOriginForHTML(kFormHTML); |
| 202 origin += kFormHTML; | |
| 203 fill_data_.basic_data.origin = GURL(origin); | |
| 204 fill_data_.basic_data.action = GURL("http://www.bidule.com"); | 214 fill_data_.basic_data.action = GURL("http://www.bidule.com"); |
| 205 | 215 |
| 206 LoadHTML(kFormHTML); | 216 LoadHTML(kFormHTML); |
| 207 | 217 |
| 208 // Now retrieves the input elements so the test can access them. | 218 // Now retrieve the input elements so the test can access them. |
| 219 UpdateUsernameAndPasswordElements(); | |
| 220 } | |
| 221 | |
| 222 virtual void TearDown() { | |
| 223 username_element_.reset(); | |
| 224 password_element_.reset(); | |
| 225 ChromeRenderViewTest::TearDown(); | |
| 226 } | |
| 227 | |
| 228 void UpdateOriginForHTML(const std::string& html) { | |
| 229 std::string origin = "data:text/html;charset=utf-8," + html; | |
| 230 fill_data_.basic_data.origin = GURL(origin); | |
| 231 } | |
| 232 | |
| 233 void UpdateUsernameAndPasswordElements() { | |
| 209 WebDocument document = GetMainFrame()->document(); | 234 WebDocument document = GetMainFrame()->document(); |
| 210 WebElement element = | 235 WebElement element = |
| 211 document.getElementById(WebString::fromUTF8(kUsernameName)); | 236 document.getElementById(WebString::fromUTF8(kUsernameName)); |
| 212 ASSERT_FALSE(element.isNull()); | 237 ASSERT_FALSE(element.isNull()); |
| 213 username_element_ = element.to<blink::WebInputElement>(); | 238 username_element_ = element.to<blink::WebInputElement>(); |
| 214 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 239 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
| 215 ASSERT_FALSE(element.isNull()); | 240 ASSERT_FALSE(element.isNull()); |
| 216 password_element_ = element.to<blink::WebInputElement>(); | 241 password_element_ = element.to<blink::WebInputElement>(); |
| 217 } | 242 } |
| 218 | 243 |
| 219 virtual void TearDown() { | |
| 220 username_element_.reset(); | |
| 221 password_element_.reset(); | |
| 222 ChromeRenderViewTest::TearDown(); | |
| 223 } | |
| 224 | |
| 225 void ClearUsernameAndPasswordFields() { | 244 void ClearUsernameAndPasswordFields() { |
| 226 username_element_.setValue(""); | 245 username_element_.setValue(""); |
| 227 username_element_.setAutofilled(false); | 246 username_element_.setAutofilled(false); |
| 228 password_element_.setValue(""); | 247 password_element_.setValue(""); |
| 229 password_element_.setAutofilled(false); | 248 password_element_.setAutofilled(false); |
| 230 } | 249 } |
| 231 | 250 |
| 232 void SimulateUsernameChangeForElement(const std::string& username, | 251 void SimulateUsernameChangeForElement(const std::string& username, |
| 233 bool move_caret_to_end, | 252 bool move_caret_to_end, |
| 234 WebFrame* input_frame, | 253 WebFrame* input_frame, |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 WebDocument document = GetMainFrame()->document(); | 390 WebDocument document = GetMainFrame()->document(); |
| 372 WebElement element = | 391 WebElement element = |
| 373 document.getElementById(WebString::fromUTF8(kUsernameName)); | 392 document.getElementById(WebString::fromUTF8(kUsernameName)); |
| 374 ASSERT_FALSE(element.isNull()); | 393 ASSERT_FALSE(element.isNull()); |
| 375 username_element_ = element.to<blink::WebInputElement>(); | 394 username_element_ = element.to<blink::WebInputElement>(); |
| 376 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 395 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
| 377 ASSERT_FALSE(element.isNull()); | 396 ASSERT_FALSE(element.isNull()); |
| 378 password_element_ = element.to<blink::WebInputElement>(); | 397 password_element_ = element.to<blink::WebInputElement>(); |
| 379 | 398 |
| 380 // Set the expected form origin and action URLs. | 399 // Set the expected form origin and action URLs. |
| 381 std::string origin("data:text/html;charset=utf-8,"); | 400 UpdateOriginForHTML(kEmptyActionFormHTML); |
| 382 origin += kEmptyActionFormHTML; | 401 fill_data_.basic_data.action = fill_data_.basic_data.origin; |
| 383 fill_data_.basic_data.origin = GURL(origin); | |
| 384 fill_data_.basic_data.action = GURL(origin); | |
| 385 | 402 |
| 386 // Simulate the browser sending back the login info, it triggers the | 403 // Simulate the browser sending back the login info, it triggers the |
| 387 // autocomplete. | 404 // autocomplete. |
| 388 SimulateOnFillPasswordForm(fill_data_); | 405 SimulateOnFillPasswordForm(fill_data_); |
| 389 | 406 |
| 390 // The username and password should have been autocompleted. | 407 // The username and password should have been autocompleted. |
| 391 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | 408 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); |
| 392 } | 409 } |
| 393 | 410 |
| 394 // Tests that if a password is marked as readonly, neither field is autofilled | 411 // 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... | |
| 476 WebDocument document = GetMainFrame()->document(); | 493 WebDocument document = GetMainFrame()->document(); |
| 477 WebElement element = | 494 WebElement element = |
| 478 document.getElementById(WebString::fromUTF8(kUsernameName)); | 495 document.getElementById(WebString::fromUTF8(kUsernameName)); |
| 479 ASSERT_FALSE(element.isNull()); | 496 ASSERT_FALSE(element.isNull()); |
| 480 username_element_ = element.to<blink::WebInputElement>(); | 497 username_element_ = element.to<blink::WebInputElement>(); |
| 481 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 498 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
| 482 ASSERT_FALSE(element.isNull()); | 499 ASSERT_FALSE(element.isNull()); |
| 483 password_element_ = element.to<blink::WebInputElement>(); | 500 password_element_ = element.to<blink::WebInputElement>(); |
| 484 | 501 |
| 485 // Set the expected form origin URL. | 502 // Set the expected form origin URL. |
| 486 std::string origin("data:text/html;charset=utf-8,"); | 503 UpdateOriginForHTML(kTextFieldPasswordFormHTML); |
| 487 origin += kTextFieldPasswordFormHTML; | |
| 488 fill_data_.basic_data.origin = GURL(origin); | |
| 489 | 504 |
| 490 SimulateOnFillPasswordForm(fill_data_); | 505 SimulateOnFillPasswordForm(fill_data_); |
| 491 | 506 |
| 492 // Fields should still be empty. | 507 // Fields should still be empty. |
| 493 CheckTextFieldsState(std::string(), false, std::string(), false); | 508 CheckTextFieldsState(std::string(), false, std::string(), false); |
| 494 } | 509 } |
| 495 | 510 |
| 496 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) { | 511 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) { |
| 497 const char kPasswordFieldUsernameFormHTML[] = | 512 const char kPasswordFieldUsernameFormHTML[] = |
| 498 "<FORM name='LoginTestForm' action='http://www.bidule.com'>" | 513 "<FORM name='LoginTestForm' action='http://www.bidule.com'>" |
| 499 " <INPUT type='password' id='username'/>" | 514 " <INPUT type='password' id='username'/>" |
| 500 " <INPUT type='password' id='password'/>" | 515 " <INPUT type='password' id='password'/>" |
| 501 " <INPUT type='submit' value='Login'/>" | 516 " <INPUT type='submit' value='Login'/>" |
| 502 "</FORM>"; | 517 "</FORM>"; |
| 503 LoadHTML(kPasswordFieldUsernameFormHTML); | 518 LoadHTML(kPasswordFieldUsernameFormHTML); |
| 504 | 519 |
| 505 // Retrieve the input elements so the test can access them. | 520 // Retrieve the input elements so the test can access them. |
| 506 WebDocument document = GetMainFrame()->document(); | 521 WebDocument document = GetMainFrame()->document(); |
| 507 WebElement element = | 522 WebElement element = |
| 508 document.getElementById(WebString::fromUTF8(kUsernameName)); | 523 document.getElementById(WebString::fromUTF8(kUsernameName)); |
| 509 ASSERT_FALSE(element.isNull()); | 524 ASSERT_FALSE(element.isNull()); |
| 510 username_element_ = element.to<blink::WebInputElement>(); | 525 username_element_ = element.to<blink::WebInputElement>(); |
| 511 element = document.getElementById(WebString::fromUTF8(kPasswordName)); | 526 element = document.getElementById(WebString::fromUTF8(kPasswordName)); |
| 512 ASSERT_FALSE(element.isNull()); | 527 ASSERT_FALSE(element.isNull()); |
| 513 password_element_ = element.to<blink::WebInputElement>(); | 528 password_element_ = element.to<blink::WebInputElement>(); |
| 514 | 529 |
| 515 // Set the expected form origin URL. | 530 // Set the expected form origin URL. |
| 516 std::string origin("data:text/html;charset=utf-8,"); | 531 UpdateOriginForHTML(kPasswordFieldUsernameFormHTML); |
| 517 origin += kPasswordFieldUsernameFormHTML; | |
| 518 fill_data_.basic_data.origin = GURL(origin); | |
| 519 | 532 |
| 520 SimulateOnFillPasswordForm(fill_data_); | 533 SimulateOnFillPasswordForm(fill_data_); |
| 521 | 534 |
| 522 // Fields should still be empty. | 535 // Fields should still be empty. |
| 523 CheckTextFieldsState(std::string(), false, std::string(), false); | 536 CheckTextFieldsState(std::string(), false, std::string(), false); |
| 524 } | 537 } |
| 525 | 538 |
| 526 // Tests that having a matching username does not preclude the autocomplete. | 539 // Tests that having a matching username does not preclude the autocomplete. |
| 527 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) { | 540 TEST_F(PasswordAutofillAgentTest, InitialAutocompleteForMatchingFilledField) { |
| 528 username_element_.setValue(WebString::fromUTF8(kAliceUsername)); | 541 username_element_.setValue(WebString::fromUTF8(kAliceUsername)); |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 800 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) { | 813 TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) { |
| 801 // Trigger the initial autocomplete. | 814 // Trigger the initial autocomplete. |
| 802 SimulateOnFillPasswordForm(fill_data_); | 815 SimulateOnFillPasswordForm(fill_data_); |
| 803 | 816 |
| 804 // The username and password should have been autocompleted. | 817 // The username and password should have been autocompleted. |
| 805 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | 818 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); |
| 806 | 819 |
| 807 // However, it should only have completed with the suggested value, as tested | 820 // However, it should only have completed with the suggested value, as tested |
| 808 // above, and it should not have completed into the DOM accessible value for | 821 // above, and it should not have completed into the DOM accessible value for |
| 809 // the password field. | 822 // the password field. |
| 810 CheckTextFieldsDOMState(kAliceUsername, true, "", true); | 823 CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true); |
| 811 | 824 |
| 812 // Simulate a user click so that the password field's real value is filled. | 825 // Simulate a user click so that the password field's real value is filled. |
| 813 SimulateElementClick(kUsernameName); | 826 SimulateElementClick(kUsernameName); |
| 814 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); | 827 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); |
| 815 } | 828 } |
| 816 | 829 |
| 817 // Verfies that a DOM-activated UI event will not cause an autofill. | 830 // Verfies that a DOM-activated UI event will not cause an autofill. |
| 818 TEST_F(PasswordAutofillAgentTest, NoDOMActivationTest) { | 831 TEST_F(PasswordAutofillAgentTest, NoDOMActivationTest) { |
| 819 // Trigger the initial autocomplete. | 832 // Trigger the initial autocomplete. |
| 820 SimulateOnFillPasswordForm(fill_data_); | 833 SimulateOnFillPasswordForm(fill_data_); |
| 821 | 834 |
| 822 ExecuteJavaScript(kJavaScriptClick); | 835 ExecuteJavaScript(kJavaScriptClick); |
| 823 CheckTextFieldsDOMState(kAliceUsername, true, "", true); | 836 CheckTextFieldsDOMState(kAliceUsername, true, "", true); |
| 824 } | 837 } |
| 825 | 838 |
| 839 // Verifies that password autofill triggers onChange events in JavaScript for | |
| 840 // forms that are filled on page load. | |
| 841 TEST_F(PasswordAutofillAgentTest, | |
| 842 PasswordAutofillTriggersOnChangeEventsOnLoad) { | |
| 843 std::string html = std::string(kFormHTML) + kOnChangeDetectionScript; | |
| 844 LoadHTML(html.c_str()); | |
| 845 UpdateOriginForHTML(html); | |
| 846 UpdateUsernameAndPasswordElements(); | |
| 847 | |
| 848 // Simulate the browser sending back the login info, it triggers the | |
| 849 // autocomplete. | |
| 850 SimulateOnFillPasswordForm(fill_data_); | |
| 851 | |
| 852 // The username and password should have been autocompleted... | |
| 853 CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); | |
| 854 // ... but since there hasn't been a user gesture yet, the autocompleted | |
| 855 // password should only be visible to the user. | |
| 856 CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true); | |
| 857 | |
| 858 | |
|
Garrett Casto
2014/01/09 19:14:32
Extra space.
Ilya Sherman
2014/01/10 06:32:49
Done.
| |
| 859 // A JavaScript onChange event should have been triggered for the username, | |
| 860 // but not yet for the password. | |
| 861 int username_onchange_called = -1; | |
| 862 int password_onchange_called = -1; | |
| 863 ASSERT_TRUE( | |
| 864 ExecuteJavaScriptAndReturnIntValue( | |
| 865 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"), | |
| 866 &username_onchange_called)); | |
| 867 EXPECT_EQ(1, username_onchange_called); | |
| 868 ASSERT_TRUE( | |
| 869 ExecuteJavaScriptAndReturnIntValue( | |
| 870 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"), | |
| 871 &password_onchange_called)); | |
| 872 EXPECT_EQ(0, password_onchange_called); | |
| 873 | |
| 874 // Simulate a user click so that the password field's real value is filled. | |
| 875 SimulateElementClick(kUsernameName); | |
| 876 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); | |
| 877 | |
| 878 // Now, a JavaScript onChange event should have been triggered for the | |
| 879 // password as well. | |
| 880 ASSERT_TRUE( | |
| 881 ExecuteJavaScriptAndReturnIntValue( | |
| 882 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"), | |
| 883 &password_onchange_called)); | |
| 884 EXPECT_EQ(1, password_onchange_called); | |
| 885 } | |
| 886 | |
| 887 // Verifies that password autofill triggers onChange events in JavaScript for | |
| 888 // forms that are filled after page load. | |
| 889 TEST_F(PasswordAutofillAgentTest, | |
| 890 PasswordAutofillTriggersOnChangeEventsWaitForUsername) { | |
| 891 std::string html = std::string(kFormHTML) + kOnChangeDetectionScript; | |
| 892 LoadHTML(html.c_str()); | |
| 893 UpdateOriginForHTML(html); | |
| 894 UpdateUsernameAndPasswordElements(); | |
| 895 | |
| 896 // Simulate the browser sending back the login info, it triggers the | |
| 897 // autocomplete. | |
| 898 fill_data_.wait_for_username = true; | |
| 899 SimulateOnFillPasswordForm(fill_data_); | |
| 900 | |
| 901 // The username and password should not yet have been autocompleted. | |
| 902 CheckTextFieldsState(std::string(), false, std::string(), false); | |
| 903 | |
| 904 // Simulate a click just to force a user gesture, since the username value is | |
| 905 // set directly. | |
| 906 SimulateElementClick(kUsernameName); | |
| 907 | |
| 908 // Simulate the user entering her username. | |
| 909 username_element_.setValue(ASCIIToUTF16(kAliceUsername), true); | |
| 910 autofill_agent_->textFieldDidEndEditing(username_element_); | |
| 911 | |
| 912 // The username and password should now have been autocompleted. | |
| 913 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); | |
| 914 | |
| 915 // JavaScript onChange events should have been triggered both for the username | |
| 916 // and for the password. | |
| 917 int username_onchange_called = -1; | |
| 918 int password_onchange_called = -1; | |
| 919 ASSERT_TRUE( | |
| 920 ExecuteJavaScriptAndReturnIntValue( | |
| 921 ASCIIToUTF16("usernameOnchangeCalled ? 1 : 0"), | |
| 922 &username_onchange_called)); | |
| 923 EXPECT_EQ(1, username_onchange_called); | |
| 924 ASSERT_TRUE( | |
| 925 ExecuteJavaScriptAndReturnIntValue( | |
| 926 ASCIIToUTF16("passwordOnchangeCalled ? 1 : 0"), | |
| 927 &password_onchange_called)); | |
| 928 EXPECT_EQ(1, password_onchange_called); | |
| 929 } | |
| 930 | |
| 826 } // namespace autofill | 931 } // namespace autofill |
| OLD | NEW |