Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(528)

Unified Diff: components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc

Issue 369323003: Implement autocomplete='current-password' and 'new-password'. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments from vabr@. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
diff --git a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
index c38ff86a3fbdba7b71be36986466b9fef49efa81..57ac2053d9ba42c0655fb17b7e72a8ea5814e719 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -39,11 +39,11 @@ class PasswordFormBuilder {
// |name_and_id|, |value|, and |autocomplete| attributes. The |autocomplete|
// argument can take two special values, namely:
// 1.) NULL, causing no autocomplete attribute to be added,
- // 2.) "", causing an empty attribute (i.e. autocomplete='') to be added.
+ // 2.) "", causing an empty attribute (i.e. autocomplete="") to be added.
void AddUsernameField(const char* name_and_id,
const char* value,
const char* autocomplete) {
- std::string autocomplete_attribute(autocomplete != NULL ?
+ std::string autocomplete_attribute(autocomplete ?
base::StringPrintf("autocomplete=\"%s\"", autocomplete) : "");
base::StringAppendF(
&html_,
@@ -52,12 +52,17 @@ class PasswordFormBuilder {
}
// Appends a new password-type field at the end of the form, having the
- // specified |name_and_id| and |value| attributes.
- void AddPasswordField(const char* name_and_id, const char* value) {
+ // specified |name_and_id|, |value|, and |autocomplete| attributes. Special
+ // values for |autocomplete| are the same as in AddUsernameField.
+ void AddPasswordField(const char* name_and_id,
+ const char* value,
+ const char* autocomplete) {
+ std::string autocomplete_attribute(autocomplete ?
+ base::StringPrintf("autocomplete=\"%s\"", autocomplete): "");
base::StringAppendF(
&html_,
- "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\"/>",
- name_and_id, name_and_id, value);
+ "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>",
+ name_and_id, name_and_id, value, autocomplete_attribute.c_str());
}
// Appends a new submit-type field at the end of the form.
@@ -111,7 +116,7 @@ TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username", "johnsmith", NULL);
builder.AddSubmitButton();
- builder.AddPasswordField("password", "secret");
+ builder.AddPasswordField("password", "secret", NULL);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
@@ -135,7 +140,7 @@ TEST_F(PasswordFormConversionUtilsTest, InvalidWebFormElementToPasswordForm) {
PasswordFormBuilder builder("invalid_target");
builder.AddUsernameField("username", "johnsmith", NULL);
builder.AddSubmitButton();
- builder.AddPasswordField("password", "secret");
+ builder.AddPasswordField("password", "secret", NULL);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
@@ -147,11 +152,11 @@ TEST_F(PasswordFormConversionUtilsTest,
WebFormWithMultipleUseNameAndPassWordFieldsToPasswordForm) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", NULL);
- builder.AddPasswordField("password1", "oldsecret");
+ builder.AddPasswordField("password1", "oldsecret", NULL);
builder.AddUsernameField("username2", "William", NULL);
- builder.AddPasswordField("password2", "secret");
+ builder.AddPasswordField("password2", "secret", NULL);
builder.AddUsernameField("username3", "Smith", NULL);
- builder.AddPasswordField("password3", "secret");
+ builder.AddPasswordField("password3", "secret", NULL);
builder.AddSubmitButton();
std::string html = builder.ProduceHTML();
@@ -185,9 +190,9 @@ TEST_F(PasswordFormConversionUtilsTest,
WebFormwithThreeDifferentPasswordsToPasswordForm) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", NULL);
- builder.AddPasswordField("password1", "alpha");
- builder.AddPasswordField("password2", "beta");
- builder.AddPasswordField("password3", "gamma");
+ builder.AddPasswordField("password1", "alpha", NULL);
+ builder.AddPasswordField("password2", "beta", NULL);
+ builder.AddPasswordField("password3", "gamma", NULL);
builder.AddSubmitButton();
std::string html = builder.ProduceHTML();
@@ -218,12 +223,12 @@ TEST_F(PasswordFormConversionUtilsTest,
{{"username", NULL, "username"}, "username1", "John", "Smith"},
{{"username", "username", "username"}, "username1", "John",
"William+Smith"},
- // When there is an empty autocomplete attribute (i.e. autocomplete=''),
+ // When there is an empty autocomplete attribute (i.e. autocomplete=""),
// it should have the same effect as having no attribute whatsoever.
{{"", "", ""}, "username2", "William", "John+Smith"},
{{"", "", "username"}, "username3", "Smith", ""},
{{"username", "", "username"}, "username1", "John", "Smith"},
- // Whether attribute values are upper or mixed case, it should not matter.
+ // It should not matter if attribute values are upper or mixed case.
{{"USERNAME", NULL, "uSeRNaMe"}, "username1", "John", "Smith"},
{{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}};
@@ -233,7 +238,7 @@ TEST_F(PasswordFormConversionUtilsTest,
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", cases[i].autocomplete[0]);
builder.AddUsernameField("username2", "William", cases[i].autocomplete[1]);
- builder.AddPasswordField("password", "secret");
+ builder.AddPasswordField("password", "secret", NULL);
builder.AddUsernameField("username3", "Smith", cases[i].autocomplete[2]);
builder.AddSubmitButton();
std::string html = builder.ProduceHTML();
@@ -253,4 +258,129 @@ TEST_F(PasswordFormConversionUtilsTest,
}
}
+TEST_F(PasswordFormConversionUtilsTest,
+ PasswordFieldsWithAutocompleteAttributes) {
+ // Each test case consists of a set of parameters to be plugged into the
+ // PasswordFormBuilder below, plus the corresponding expectations.
+ struct TestCase {
+ const char* autocomplete[3];
+ const char* expected_password_element;
+ const char* expected_password_value;
+ const char* expected_new_password_element;
+ const char* expected_new_password_value;
+ } cases[] = {
+ // When there are elements marked with autocomplete='current-password',
+ // but no elements with 'new-password', we should treat the first of the
+ // former kind as the current password, and ignore all other password
+ // fields, assuming they are not intentionally not marked. They might be
+ // for other purposes, such as PINs, OTPs, and the like. Actual values in
+ // the password fields should be ignored in all cases below.
+ {{"current-password", NULL, NULL}, "password1", "alpha", "", ""},
+ {{NULL, "current-password", NULL}, "password2", "beta", "", ""},
+ {{NULL, NULL, "current-password"}, "password3", "gamma", "", ""},
+ {{NULL, "current-password", "current-password"},
+ "password2", "beta", "", ""},
+ {{"current-password", NULL, "current-password"},
+ "password1", "alpha", "", ""},
+ {{"current-password", "current-password", NULL},
+ "password1", "alpha", "", ""},
+ {{"current-password", "current-password", "current-password"},
+ "password1", "alpha", "", ""},
+ // The same goes vice versa for autocomplete='new-password'.
+ {{"new-password", NULL, NULL}, "", "", "password1", "alpha"},
+ {{NULL, "new-password", NULL}, "", "", "password2", "beta"},
+ {{NULL, NULL, "new-password"}, "", "", "password3", "gamma"},
+ {{NULL, "new-password", "new-password"}, "", "", "password2", "beta"},
+ {{"new-password", NULL, "new-password"}, "", "", "password1", "alpha"},
+ {{"new-password", "new-password", NULL}, "", "", "password1", "alpha"},
+ {{"new-password", "new-password", "new-password"},
+ "", "", "password1", "alpha"},
+ // When there is one element marked with autocomplete='current-password',
+ // and one with 'new-password', just comply, regardless of their order.
+ // Ignore the unmarked password field(s) for the same reason as above.
+ {{"current-password", "new-password", NULL},
+ "password1", "alpha", "password2", "beta"},
+ {{"current-password", NULL, "new-password"},
+ "password1", "alpha", "password3", "gamma"},
+ {{NULL, "current-password", "new-password"},
+ "password2", "beta", "password3", "gamma"},
+ {{"new-password", "current-password", NULL},
+ "password2", "beta", "password1", "alpha"},
+ {{"new-password", NULL, "current-password"},
+ "password3", "gamma", "password1", "alpha"},
+ {{NULL, "new-password", "current-password"},
+ "password3", "gamma", "password2", "beta"},
+ // In case of duplicated elements of either kind, go with the first one of
+ // its kind.
+ {{"current-password", "current-password", "new-password"},
+ "password1", "alpha", "password3", "gamma"},
+ {{"current-password", "new-password", "current-password"},
+ "password1", "alpha", "password2", "beta"},
+ {{"new-password", "current-password", "current-password"},
+ "password2", "beta", "password1", "alpha"},
+ {{"current-password", "new-password", "new-password"},
+ "password1", "alpha", "password2", "beta"},
+ {{"new-password", "current-password", "new-password"},
+ "password2", "beta", "password1", "alpha"},
+ {{"new-password", "new-password", "current-password"},
+ "password3", "gamma", "password1", "alpha"},
+ // When there is an empty autocomplete attribute (i.e. autocomplete=""),
+ // it should have the same effect as having no attribute whatsoever.
+ {{"current-password", "", ""},
+ "password1", "alpha", "", ""},
+ {{"", "", "new-password"},
+ "", "", "password3", "gamma"},
+ {{"", "new-password", ""},
+ "", "", "password2", "beta"},
+ {{"", "current-password", "current-password"},
+ "password2", "beta", "", ""},
+ {{"new-password", "", "new-password"}, "", "", "password1", "alpha"},
+ {{"new-password", "", "current-password"},
+ "password3", "gamma", "password1", "alpha"},
+ // It should not matter if attribute values are upper or mixed case.
+ {{NULL, "current-password", NULL},
+ "password2", "beta", "", ""},
+ {{NULL, "CURRENT-PASSWORD", NULL},
+ "password2", "beta", "", ""},
+ {{NULL, "new-password", NULL},
+ "", "", "password2", "beta"},
+ {{NULL, "nEw-PaSsWoRd", NULL},
+ "", "", "password2", "beta"}};
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Iteration " << i);
+
+ PasswordFormBuilder builder(kTestFormActionURL);
+ builder.AddPasswordField("password1", "alpha", cases[i].autocomplete[0]);
+ builder.AddUsernameField("username1", "William", NULL);
+ builder.AddPasswordField("password2", "beta", cases[i].autocomplete[1]);
+ builder.AddUsernameField("username2", "Smith", NULL);
+ builder.AddPasswordField("password3", "gamma", cases[i].autocomplete[2]);
+ builder.AddSubmitButton();
+ std::string html = builder.ProduceHTML();
+
+ scoped_ptr<PasswordForm> password_form;
+ ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
+ ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get());
+
+ // Any constellation of password autocomplete attributes should have no
+ // effect on that the first text-type input field before a password field
+ // should be selected as the username.
+ // TODO(engedy): Double-check whether this is the intended behavior.
+ EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
+ EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
+ EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
+ password_form->password_element);
+ EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
+ password_form->password_value);
+ EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
+ password_form->new_password_element);
+ EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
+ password_form->new_password_value);
+ ASSERT_EQ(1u, password_form->other_possible_usernames.size());
+ EXPECT_EQ(base::UTF8ToUTF16("Smith"),
+ password_form->other_possible_usernames[0]);
+ }
+}
+
} // namespace autofill

Powered by Google App Engine
This is Rietveld 408576698