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 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 password_element_ = element.to<blink::WebInputElement>(); | 254 password_element_ = element.to<blink::WebInputElement>(); |
255 } | 255 } |
256 | 256 |
257 void ClearUsernameAndPasswordFields() { | 257 void ClearUsernameAndPasswordFields() { |
258 username_element_.setValue(""); | 258 username_element_.setValue(""); |
259 username_element_.setAutofilled(false); | 259 username_element_.setAutofilled(false); |
260 password_element_.setValue(""); | 260 password_element_.setValue(""); |
261 password_element_.setAutofilled(false); | 261 password_element_.setAutofilled(false); |
262 } | 262 } |
263 | 263 |
264 void SimulateUsernameChangeForElement(const std::string& username, | 264 void SimulateDidEndEditingWithNoChangeForElement(WebFrame* input_frame, |
265 bool move_caret_to_end, | 265 WebInputElement& input) { |
266 WebFrame* input_frame, | 266 autofill_agent_->textFieldDidEndEditing(input); |
267 WebInputElement& username_input, | 267 } |
268 bool is_user_input) { | 268 |
269 username_input.setValue(WebString::fromUTF8(username), is_user_input); | 269 void SimulateInputChangeForElement(const std::string& new_value, |
| 270 bool move_caret_to_end, |
| 271 WebFrame* input_frame, |
| 272 WebInputElement& input, |
| 273 bool is_user_input) { |
| 274 input.setValue(WebString::fromUTF8(new_value), is_user_input); |
270 // The field must have focus or AutofillAgent will think the | 275 // The field must have focus or AutofillAgent will think the |
271 // change should be ignored. | 276 // change should be ignored. |
272 while (!username_input.focused()) | 277 while (!input.focused()) |
273 input_frame->document().frame()->view()->advanceFocus(false); | 278 input_frame->document().frame()->view()->advanceFocus(false); |
274 if (move_caret_to_end) | 279 if (move_caret_to_end) |
275 username_input.setSelectionRange(username.length(), username.length()); | 280 input.setSelectionRange(new_value.length(), new_value.length()); |
276 if (is_user_input) | 281 if (is_user_input) |
277 password_autofill_agent()->FirstUserGestureObserved(); | 282 password_autofill_agent()->FirstUserGestureObserved(); |
278 autofill_agent_->textFieldDidChange(username_input); | 283 autofill_agent_->textFieldDidChange(input); |
279 // Processing is delayed because of a Blink bug: | 284 // Processing is delayed because of a Blink bug: |
280 // https://bugs.webkit.org/show_bug.cgi?id=16976 | 285 // https://bugs.webkit.org/show_bug.cgi?id=16976 |
281 // See PasswordAutofillAgent::TextDidChangeInTextField() for details. | 286 // See PasswordAutofillAgent::TextDidChangeInTextField() for details. |
282 | 287 |
283 // Autocomplete will trigger a style recalculation when we put up the next | 288 // Autocomplete will trigger a style recalculation when we put up the next |
284 // frame, but we don't want to wait that long. Instead, trigger a style | 289 // frame, but we don't want to wait that long. Instead, trigger a style |
285 // recalcuation manually after TextFieldDidChangeImpl runs. | 290 // recalcuation manually after TextFieldDidChangeImpl runs. |
286 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 291 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
287 &PasswordAutofillAgentTest::LayoutMainFrame, base::Unretained(this))); | 292 &PasswordAutofillAgentTest::LayoutMainFrame, base::Unretained(this))); |
288 | 293 |
(...skipping 14 matching lines...) Expand all Loading... |
303 autofill_agent_->OnFillPasswordSuggestion(blink_username, blink_password); | 308 autofill_agent_->OnFillPasswordSuggestion(blink_username, blink_password); |
304 } | 309 } |
305 | 310 |
306 void LayoutMainFrame() { | 311 void LayoutMainFrame() { |
307 GetMainFrame()->view()->layout(); | 312 GetMainFrame()->view()->layout(); |
308 } | 313 } |
309 | 314 |
310 void SimulateUsernameChange(const std::string& username, | 315 void SimulateUsernameChange(const std::string& username, |
311 bool move_caret_to_end, | 316 bool move_caret_to_end, |
312 bool is_user_input = false) { | 317 bool is_user_input = false) { |
313 SimulateUsernameChangeForElement(username, | 318 SimulateInputChangeForElement(username, |
314 move_caret_to_end, | 319 move_caret_to_end, |
315 GetMainFrame(), | 320 GetMainFrame(), |
316 username_element_, | 321 username_element_, |
317 is_user_input); | 322 is_user_input); |
318 } | 323 } |
319 | 324 |
320 // Tests that no suggestion popup is generated when the username_element_ is | 325 // Tests that no suggestion popup is generated when the username_element_ is |
321 // edited. | 326 // edited. |
322 void ExpectNoSuggestionsPopup() { | 327 void ExpectNoSuggestionsPopup() { |
323 // The first test below ensures that the suggestions have been handled by | 328 // The first test below ensures that the suggestions have been handled by |
324 // the password_autofill_agent, even though autocomplete='off' is set. The | 329 // the password_autofill_agent, even though autocomplete='off' is set. The |
325 // second check ensures that, although handled, no "show suggestions" IPC to | 330 // second check ensures that, although handled, no "show suggestions" IPC to |
326 // the browser was generated. | 331 // the browser was generated. |
327 // | 332 // |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 const WebInputElement& password_element, | 366 const WebInputElement& password_element, |
362 const std::string& password, | 367 const std::string& password, |
363 bool password_autofilled, | 368 bool password_autofilled, |
364 bool checkSuggestedValue) { | 369 bool checkSuggestedValue) { |
365 EXPECT_EQ(username, | 370 EXPECT_EQ(username, |
366 static_cast<std::string>(username_element.value().utf8())); | 371 static_cast<std::string>(username_element.value().utf8())); |
367 EXPECT_EQ(username_autofilled, username_element.isAutofilled()); | 372 EXPECT_EQ(username_autofilled, username_element.isAutofilled()); |
368 EXPECT_EQ(password, | 373 EXPECT_EQ(password, |
369 static_cast<std::string>( | 374 static_cast<std::string>( |
370 checkSuggestedValue ? password_element.suggestedValue().utf8() | 375 checkSuggestedValue ? password_element.suggestedValue().utf8() |
371 : password_element.value().utf8())); | 376 : password_element.value().utf8())) |
| 377 << "checkSuggestedValue == " << checkSuggestedValue; |
372 EXPECT_EQ(password_autofilled, password_element.isAutofilled()); | 378 EXPECT_EQ(password_autofilled, password_element.isAutofilled()); |
373 } | 379 } |
374 | 380 |
375 // Checks the DOM-accessible value of the username element and the | 381 // Checks the DOM-accessible value of the username element and the |
376 // *suggested* value of the password element. | 382 // *suggested* value of the password element. |
377 void CheckTextFieldsState(const std::string& username, | 383 void CheckTextFieldsState(const std::string& username, |
378 bool username_autofilled, | 384 bool username_autofilled, |
379 const std::string& password, | 385 const std::string& password, |
380 bool password_autofilled) { | 386 bool password_autofilled) { |
381 CheckTextFieldsStateForElements(username_element_, | 387 CheckTextFieldsStateForElements(username_element_, |
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 | 919 |
914 WebInputElement username_input = username_element.to<WebInputElement>(); | 920 WebInputElement username_input = username_element.to<WebInputElement>(); |
915 WebInputElement password_input = password_element.to<WebInputElement>(); | 921 WebInputElement password_input = password_element.to<WebInputElement>(); |
916 ASSERT_FALSE(username_element.isNull()); | 922 ASSERT_FALSE(username_element.isNull()); |
917 | 923 |
918 CheckTextFieldsStateForElements( | 924 CheckTextFieldsStateForElements( |
919 username_input, "", false, password_input, "", false, false); | 925 username_input, "", false, password_input, "", false, false); |
920 | 926 |
921 // Simulate the user typing in the username in the iframe which should cause | 927 // Simulate the user typing in the username in the iframe which should cause |
922 // an autofill. | 928 // an autofill. |
923 SimulateUsernameChangeForElement( | 929 SimulateInputChangeForElement( |
924 kAliceUsername, true, iframe, username_input, true); | 930 kAliceUsername, true, iframe, username_input, true); |
925 | 931 |
926 CheckTextFieldsStateForElements(username_input, | 932 CheckTextFieldsStateForElements(username_input, |
927 kAliceUsername, | 933 kAliceUsername, |
928 true, | 934 true, |
929 password_input, | 935 password_input, |
930 kAlicePassword, | 936 kAlicePassword, |
931 true, | 937 true, |
932 false); | 938 false); |
933 } | 939 } |
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1488 render_thread_->sink().ClearMessages(); | 1494 render_thread_->sink().ClearMessages(); |
1489 autofill_agent_->FormControlElementClicked(username_element_, true); | 1495 autofill_agent_->FormControlElementClicked(username_element_, true); |
1490 ExpectAllCredentials(); | 1496 ExpectAllCredentials(); |
1491 } | 1497 } |
1492 | 1498 |
1493 // The user types in a password, but then just before sending the form off, a | 1499 // The user types in a password, but then just before sending the form off, a |
1494 // script clears that password. This test checks that PasswordAutofillAgent can | 1500 // script clears that password. This test checks that PasswordAutofillAgent can |
1495 // still remember the password typed by the user. | 1501 // still remember the password typed by the user. |
1496 TEST_F(PasswordAutofillAgentTest, | 1502 TEST_F(PasswordAutofillAgentTest, |
1497 RememberLastNonEmptyPasswordOnSubmit_ScriptCleared) { | 1503 RememberLastNonEmptyPasswordOnSubmit_ScriptCleared) { |
1498 SimulateUsernameChangeForElement( | 1504 SimulateInputChangeForElement( |
1499 "temp", true, GetMainFrame(), username_element_, true); | 1505 "temp", true, GetMainFrame(), username_element_, true); |
1500 SimulateUsernameChangeForElement( | 1506 SimulateInputChangeForElement( |
1501 "random", true, GetMainFrame(), password_element_, true); | 1507 "random", true, GetMainFrame(), password_element_, true); |
1502 | 1508 |
1503 // Simulate that the password value was cleared by the site's JavaScript | 1509 // Simulate that the password value was cleared by the site's JavaScript |
1504 // before submit. | 1510 // before submit. |
1505 password_element_.setValue(WebString()); | 1511 password_element_.setValue(WebString()); |
1506 static_cast<content::RenderViewObserver*>(password_autofill_agent()) | 1512 static_cast<content::RenderViewObserver*>(password_autofill_agent()) |
1507 ->WillSubmitForm(GetMainFrame(), username_element_.form()); | 1513 ->WillSubmitForm(GetMainFrame(), username_element_.form()); |
1508 | 1514 |
1509 // Observe that the PasswordAutofillAgent still remembered the last non-empty | 1515 // Observe that the PasswordAutofillAgent still remembered the last non-empty |
1510 // password and sent that to the browser. | 1516 // password and sent that to the browser. |
1511 ExpectFormSubmittedWithPasswords("random", ""); | 1517 ExpectFormSubmittedWithPasswords("random", ""); |
1512 } | 1518 } |
1513 | 1519 |
1514 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but this time | 1520 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but this time |
1515 // it's the user who clears the password. This test checks that in that case, | 1521 // it's the user who clears the password. This test checks that in that case, |
1516 // the last non-empty password is not remembered. | 1522 // the last non-empty password is not remembered. |
1517 TEST_F(PasswordAutofillAgentTest, | 1523 TEST_F(PasswordAutofillAgentTest, |
1518 RememberLastNonEmptyPasswordOnSubmit_UserCleared) { | 1524 RememberLastNonEmptyPasswordOnSubmit_UserCleared) { |
1519 SimulateUsernameChangeForElement( | 1525 SimulateInputChangeForElement( |
1520 "temp", true, GetMainFrame(), username_element_, true); | 1526 "temp", true, GetMainFrame(), username_element_, true); |
1521 SimulateUsernameChangeForElement( | 1527 SimulateInputChangeForElement( |
1522 "random", true, GetMainFrame(), password_element_, true); | 1528 "random", true, GetMainFrame(), password_element_, true); |
1523 | 1529 |
1524 // Simulate that the user actually cleared the password again. | 1530 // Simulate that the user actually cleared the password again. |
1525 SimulateUsernameChangeForElement( | 1531 SimulateInputChangeForElement( |
1526 "", true, GetMainFrame(), password_element_, true); | 1532 "", true, GetMainFrame(), password_element_, true); |
1527 static_cast<content::RenderViewObserver*>(password_autofill_agent()) | 1533 static_cast<content::RenderViewObserver*>(password_autofill_agent()) |
1528 ->WillSubmitForm(GetMainFrame(), username_element_.form()); | 1534 ->WillSubmitForm(GetMainFrame(), username_element_.form()); |
1529 | 1535 |
1530 // Observe that the PasswordAutofillAgent respects the user having cleared the | 1536 // Observe that the PasswordAutofillAgent respects the user having cleared the |
1531 // password. | 1537 // password. |
1532 ExpectFormSubmittedWithPasswords("", ""); | 1538 ExpectFormSubmittedWithPasswords("", ""); |
1533 } | 1539 } |
1534 | 1540 |
1535 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but uses the | 1541 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but uses the |
1536 // new password instead of the current password. | 1542 // new password instead of the current password. |
1537 TEST_F(PasswordAutofillAgentTest, | 1543 TEST_F(PasswordAutofillAgentTest, |
1538 RememberLastNonEmptyPasswordOnSubmit_NewPassword) { | 1544 RememberLastNonEmptyPasswordOnSubmit_NewPassword) { |
1539 const char kNewPasswordFormHTML[] = | 1545 const char kNewPasswordFormHTML[] = |
1540 "<FORM name='LoginTestForm'>" | 1546 "<FORM name='LoginTestForm'>" |
1541 " <INPUT type='text' id='username' autocomplete='username'/>" | 1547 " <INPUT type='text' id='username' autocomplete='username'/>" |
1542 " <INPUT type='password' id='password' autocomplete='new-password'/>" | 1548 " <INPUT type='password' id='password' autocomplete='new-password'/>" |
1543 " <INPUT type='submit' value='Login'/>" | 1549 " <INPUT type='submit' value='Login'/>" |
1544 "</FORM>"; | 1550 "</FORM>"; |
1545 LoadHTML(kNewPasswordFormHTML); | 1551 LoadHTML(kNewPasswordFormHTML); |
1546 UpdateUsernameAndPasswordElements(); | 1552 UpdateUsernameAndPasswordElements(); |
1547 | 1553 |
1548 SimulateUsernameChangeForElement( | 1554 SimulateInputChangeForElement( |
1549 "temp", true, GetMainFrame(), username_element_, true); | 1555 "temp", true, GetMainFrame(), username_element_, true); |
1550 SimulateUsernameChangeForElement( | 1556 SimulateInputChangeForElement( |
1551 "random", true, GetMainFrame(), password_element_, true); | 1557 "random", true, GetMainFrame(), password_element_, true); |
1552 | 1558 |
1553 // Simulate that the password value was cleared by the site's JavaScript | 1559 // Simulate that the password value was cleared by the site's JavaScript |
1554 // before submit. | 1560 // before submit. |
1555 password_element_.setValue(WebString()); | 1561 password_element_.setValue(WebString()); |
1556 static_cast<content::RenderViewObserver*>(password_autofill_agent()) | 1562 static_cast<content::RenderViewObserver*>(password_autofill_agent()) |
1557 ->WillSubmitForm(GetMainFrame(), username_element_.form()); | 1563 ->WillSubmitForm(GetMainFrame(), username_element_.form()); |
1558 | 1564 |
1559 // Observe that the PasswordAutofillAgent still remembered the last non-empty | 1565 // Observe that the PasswordAutofillAgent still remembered the last non-empty |
1560 // password and sent that to the browser. | 1566 // password and sent that to the browser. |
1561 ExpectFormSubmittedWithPasswords("", "random"); | 1567 ExpectFormSubmittedWithPasswords("", "random"); |
1562 } | 1568 } |
1563 | 1569 |
| 1570 // The user first accepts a suggestion, but then overwrites the password. This |
| 1571 // test checks that the overwritten password is not reverted back by the user |
| 1572 // triggering autofill through focusing (but not changing) the username again. |
| 1573 TEST_F(PasswordAutofillAgentTest, PasswordNotOverwritten) { |
| 1574 // Simulate having credentials which needed to wait until the user starts |
| 1575 // typing the username to be filled (e.g., PSL-matched credentials). Those are |
| 1576 // the ones which can be filled as a result of TextFieldDidEndEditing. |
| 1577 fill_data_.wait_for_username = true; |
| 1578 // Simulate that the user typed her name to make the autofill work. |
| 1579 SimulateInputChangeForElement(kAliceUsername, |
| 1580 /*move_caret_to_end=*/true, |
| 1581 GetMainFrame(), |
| 1582 username_element_, |
| 1583 /*is_user_input=*/true); |
| 1584 SimulateOnFillPasswordForm(fill_data_); |
| 1585 |
| 1586 const std::string old_username(username_element_.value().utf8()); |
| 1587 const std::string old_password(password_element_.value().utf8()); |
| 1588 const std::string new_password(old_password + "modify"); |
| 1589 |
| 1590 // The user changes the password. |
| 1591 SimulateInputChangeForElement(new_password, |
| 1592 /*move_caret_to_end=*/true, |
| 1593 GetMainFrame(), |
| 1594 password_element_, |
| 1595 /*is_user_input=*/true); |
| 1596 |
| 1597 // The user switches back into the username field, but leaves that without |
| 1598 // changes. |
| 1599 SimulateDidEndEditingWithNoChangeForElement(GetMainFrame(), |
| 1600 username_element_); |
| 1601 |
| 1602 // The password should have stayed as the user changed it. |
| 1603 CheckTextFieldsDOMState(old_username, false, new_password, false); |
| 1604 // The password should not have a suggested value. |
| 1605 CheckTextFieldsState(old_username, false, std::string(), false); |
| 1606 } |
| 1607 |
| 1608 // Tests that inline autocompletion overwrites the previous password value when |
| 1609 // it should. |
| 1610 TEST_F(PasswordAutofillAgentTest, InlineAutocompleteOverwritesValue) { |
| 1611 // Simulate the browser sending back the login info. |
| 1612 SimulateOnFillPasswordForm(fill_data_); |
| 1613 |
| 1614 ClearUsernameAndPasswordFields(); |
| 1615 |
| 1616 // The user enters a password |
| 1617 SimulateInputChangeForElement("someOtherPassword", |
| 1618 /*move_caret_to_end=*/true, |
| 1619 GetMainFrame(), |
| 1620 password_element_, |
| 1621 /*is_user_input=*/true); |
| 1622 |
| 1623 // Simulate the user typing a stored username. |
| 1624 SimulateUsernameChange(kAliceUsername, true); |
| 1625 // The autofileld password should replace the typed one. |
| 1626 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true); |
| 1627 } |
| 1628 |
1564 } // namespace autofill | 1629 } // namespace autofill |
OLD | NEW |