Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / chrome / renderer / autofill / password_generation_agent_browsertest.cc
blob60bdaa3efa8a9c77e86dc2d7997968038f342b55
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <string.h>
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/test/base/chrome_render_view_test.h"
10 #include "components/autofill/content/common/autofill_messages.h"
11 #include "components/autofill/content/renderer/autofill_agent.h"
12 #include "components/autofill/content/renderer/test_password_generation_agent.h"
13 #include "components/autofill/core/common/form_data.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/WebKit/public/platform/WebString.h"
16 #include "third_party/WebKit/public/web/WebDocument.h"
17 #include "third_party/WebKit/public/web/WebLocalFrame.h"
18 #include "third_party/WebKit/public/web/WebWidget.h"
20 using blink::WebDocument;
21 using blink::WebElement;
22 using blink::WebInputElement;
23 using blink::WebNode;
24 using blink::WebString;
26 namespace autofill {
28 class PasswordGenerationAgentTest : public ChromeRenderViewTest {
29 public:
30 PasswordGenerationAgentTest() {}
32 virtual void TearDown() {
33 LoadHTML("");
34 ChromeRenderViewTest::TearDown();
37 void SetNotBlacklistedMessage(const char* form_str) {
38 autofill::PasswordForm form;
39 form.origin =
40 GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str));
41 AutofillMsg_FormNotBlacklisted msg(0, form);
42 password_generation_->OnMessageReceived(msg);
45 void SetAccountCreationFormsDetectedMessage(const char* form_str) {
46 autofill::FormData form;
47 form.origin =
48 GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str));
49 std::vector<autofill::FormData> forms;
50 forms.push_back(form);
51 AutofillMsg_AccountCreationFormsDetected msg(0, forms);
52 password_generation_->OnMessageReceived(msg);
55 void ExpectPasswordGenerationAvailable(const char* element_id,
56 bool available) {
57 WebDocument document = GetMainFrame()->document();
58 WebElement element =
59 document.getElementById(WebString::fromUTF8(element_id));
60 ASSERT_FALSE(element.isNull());
61 ExecuteJavaScript(
62 base::StringPrintf("document.getElementById('%s').focus();",
63 element_id).c_str());
64 if (available) {
65 ASSERT_EQ(1u, password_generation_->messages().size());
66 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
67 password_generation_->messages()[0]->type());
68 } else {
69 EXPECT_EQ(0u, password_generation_->messages().size());
71 password_generation_->clear_messages();
74 private:
75 DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgentTest);
78 const char kSigninFormHTML[] =
79 "<FORM name = 'blah' action = 'http://www.random.com/'> "
80 " <INPUT type = 'text' id = 'username'/> "
81 " <INPUT type = 'password' id = 'password'/> "
82 " <INPUT type = 'submit' value = 'LOGIN' />"
83 "</FORM>";
85 const char kAccountCreationFormHTML[] =
86 "<FORM name = 'blah' action = 'http://www.random.com/'> "
87 " <INPUT type = 'text' id = 'username'/> "
88 " <INPUT type = 'password' id = 'first_password' "
89 " autocomplete = 'off' size = 5/>"
90 " <INPUT type = 'password' id = 'second_password' size = 5/> "
91 " <INPUT type = 'text' id = 'address'/> "
92 " <INPUT type = 'submit' value = 'LOGIN' />"
93 "</FORM>";
95 const char kHiddenPasswordAccountCreationFormHTML[] =
96 "<FORM name = 'blah' action = 'http://www.random.com/'> "
97 " <INPUT type = 'text' id = 'username'/> "
98 " <INPUT type = 'password' id = 'first_password'/> "
99 " <INPUT type = 'password' id = 'second_password' style='display:none'/> "
100 " <INPUT type = 'submit' value = 'LOGIN' />"
101 "</FORM>";
103 const char kInvalidActionAccountCreationFormHTML[] =
104 "<FORM name = 'blah' action = 'invalid'> "
105 " <INPUT type = 'text' id = 'username'/> "
106 " <INPUT type = 'password' id = 'first_password'/> "
107 " <INPUT type = 'password' id = 'second_password'/> "
108 " <INPUT type = 'submit' value = 'LOGIN' />"
109 "</FORM>";
111 TEST_F(PasswordGenerationAgentTest, DetectionTest) {
112 // Don't shown the icon for non account creation forms.
113 LoadHTML(kSigninFormHTML);
114 ExpectPasswordGenerationAvailable("password", false);
116 // We don't show the decoration yet because the feature isn't enabled.
117 LoadHTML(kAccountCreationFormHTML);
118 ExpectPasswordGenerationAvailable("first_password", false);
120 // Pretend like We have received message indicating site is not blacklisted,
121 // and we have received message indicating the form is classified as
122 // ACCOUNT_CREATION_FORM form Autofill server. We should show the icon.
123 LoadHTML(kAccountCreationFormHTML);
124 SetNotBlacklistedMessage(kAccountCreationFormHTML);
125 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
126 ExpectPasswordGenerationAvailable("first_password", true);
128 // This doesn't trigger because hidden password fields are ignored.
129 LoadHTML(kHiddenPasswordAccountCreationFormHTML);
130 SetNotBlacklistedMessage(kHiddenPasswordAccountCreationFormHTML);
131 SetAccountCreationFormsDetectedMessage(
132 kHiddenPasswordAccountCreationFormHTML);
133 ExpectPasswordGenerationAvailable("first_password", false);
135 // This doesn't trigger because the form action is invalid.
136 LoadHTML(kInvalidActionAccountCreationFormHTML);
137 SetNotBlacklistedMessage(kInvalidActionAccountCreationFormHTML);
138 SetAccountCreationFormsDetectedMessage(kInvalidActionAccountCreationFormHTML);
139 ExpectPasswordGenerationAvailable("first_password", false);
142 TEST_F(PasswordGenerationAgentTest, FillTest) {
143 // Make sure that we are enabled before loading HTML.
144 LoadHTML(kAccountCreationFormHTML);
146 WebDocument document = GetMainFrame()->document();
147 WebElement element =
148 document.getElementById(WebString::fromUTF8("first_password"));
149 ASSERT_FALSE(element.isNull());
150 WebInputElement first_password_element = element.to<WebInputElement>();
151 element = document.getElementById(WebString::fromUTF8("second_password"));
152 ASSERT_FALSE(element.isNull());
153 WebInputElement second_password_element = element.to<WebInputElement>();
155 // Both password fields should be empty.
156 EXPECT_TRUE(first_password_element.value().isNull());
157 EXPECT_TRUE(second_password_element.value().isNull());
159 base::string16 password = base::ASCIIToUTF16("random_password");
160 AutofillMsg_GeneratedPasswordAccepted msg(0, password);
161 password_generation_->OnMessageReceived(msg);
163 // Password fields are filled out and set as being autofilled.
164 EXPECT_EQ(password, first_password_element.value());
165 EXPECT_EQ(password, second_password_element.value());
166 EXPECT_TRUE(first_password_element.isAutofilled());
167 EXPECT_TRUE(second_password_element.isAutofilled());
169 // Focus moved to the next input field.
170 // TODO(zysxqn): Change this back to the address element once Bug 90224
171 // https://bugs.webkit.org/show_bug.cgi?id=90224 has been fixed.
172 element = document.getElementById(WebString::fromUTF8("first_password"));
173 ASSERT_FALSE(element.isNull());
174 EXPECT_EQ(element, document.focusedElement());
177 TEST_F(PasswordGenerationAgentTest, EditingTest) {
178 LoadHTML(kAccountCreationFormHTML);
179 SetNotBlacklistedMessage(kAccountCreationFormHTML);
180 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
182 WebDocument document = GetMainFrame()->document();
183 WebElement element =
184 document.getElementById(WebString::fromUTF8("first_password"));
185 ASSERT_FALSE(element.isNull());
186 WebInputElement first_password_element = element.to<WebInputElement>();
187 element = document.getElementById(WebString::fromUTF8("second_password"));
188 ASSERT_FALSE(element.isNull());
189 WebInputElement second_password_element = element.to<WebInputElement>();
191 base::string16 password = base::ASCIIToUTF16("random_password");
192 AutofillMsg_GeneratedPasswordAccepted msg(0, password);
193 password_generation_->OnMessageReceived(msg);
195 // Passwords start out the same.
196 EXPECT_EQ(password, first_password_element.value());
197 EXPECT_EQ(password, second_password_element.value());
199 // After editing the first field they are still the same.
200 base::string16 edited_password = base::ASCIIToUTF16("edited_password");
201 first_password_element.setValue(edited_password);
202 // Cast to WebAutofillClient where textFieldDidChange() is public.
203 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
204 first_password_element);
205 // textFieldDidChange posts a task, so we need to wait until it's been
206 // processed.
207 base::MessageLoop::current()->RunUntilIdle();
209 EXPECT_EQ(edited_password, first_password_element.value());
210 EXPECT_EQ(edited_password, second_password_element.value());
213 TEST_F(PasswordGenerationAgentTest, BlacklistedTest) {
214 // Did not receive not blacklisted message. Don't show password generation
215 // icon.
216 LoadHTML(kAccountCreationFormHTML);
217 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
218 ExpectPasswordGenerationAvailable("first_password", false);
220 // Receive one not blacklisted message for non account creation form. Don't
221 // show password generation icon.
222 LoadHTML(kAccountCreationFormHTML);
223 SetNotBlacklistedMessage(kSigninFormHTML);
224 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
225 ExpectPasswordGenerationAvailable("first_password", false);
227 // Receive one not blackliste message for account creation form. Show password
228 // generation icon.
229 LoadHTML(kAccountCreationFormHTML);
230 SetNotBlacklistedMessage(kAccountCreationFormHTML);
231 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
232 ExpectPasswordGenerationAvailable("first_password", true);
234 // Receive two not blacklisted messages, one is for account creation form and
235 // the other is not. Show password generation icon.
236 LoadHTML(kAccountCreationFormHTML);
237 SetNotBlacklistedMessage(kAccountCreationFormHTML);
238 SetNotBlacklistedMessage(kSigninFormHTML);
239 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
240 ExpectPasswordGenerationAvailable("first_password", true);
243 TEST_F(PasswordGenerationAgentTest, AccountCreationFormsDetectedTest) {
244 // Did not receive account creation forms detected messege. Don't show
245 // password generation icon.
246 LoadHTML(kAccountCreationFormHTML);
247 SetNotBlacklistedMessage(kAccountCreationFormHTML);
248 ExpectPasswordGenerationAvailable("first_password", false);
250 // Receive the account creation forms detected message. Show password
251 // generation icon.
252 LoadHTML(kAccountCreationFormHTML);
253 SetNotBlacklistedMessage(kAccountCreationFormHTML);
254 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
255 ExpectPasswordGenerationAvailable("first_password", true);
258 TEST_F(PasswordGenerationAgentTest, MaximumOfferSize) {
259 LoadHTML(kAccountCreationFormHTML);
260 SetNotBlacklistedMessage(kAccountCreationFormHTML);
261 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
262 ExpectPasswordGenerationAvailable("first_password", true);
264 WebDocument document = GetMainFrame()->document();
265 WebElement element =
266 document.getElementById(WebString::fromUTF8("first_password"));
267 ASSERT_FALSE(element.isNull());
268 WebInputElement first_password_element = element.to<WebInputElement>();
270 // Make a password just under maximum offer size.
271 first_password_element.setValue(
272 base::ASCIIToUTF16(
273 std::string(password_generation_->kMaximumOfferSize - 1, 'a')));
274 // Cast to WebAutofillClient where textFieldDidChange() is public.
275 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
276 first_password_element);
277 // textFieldDidChange posts a task, so we need to wait until it's been
278 // processed.
279 base::MessageLoop::current()->RunUntilIdle();
280 // There should now be a message to show the UI.
281 ASSERT_EQ(1u, password_generation_->messages().size());
282 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
283 password_generation_->messages()[0]->type());
284 password_generation_->clear_messages();
286 // Simulate a user typing a password just over maximum offer size.
287 first_password_element.setValue(
288 base::ASCIIToUTF16(
289 std::string(password_generation_->kMaximumOfferSize + 1, 'a')));
290 // Cast to WebAutofillClient where textFieldDidChange() is public.
291 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
292 first_password_element);
293 // textFieldDidChange posts a task, so we need to wait until it's been
294 // processed.
295 base::MessageLoop::current()->RunUntilIdle();
296 // There should now be a message to hide the UI.
297 ASSERT_EQ(1u, password_generation_->messages().size());
298 EXPECT_EQ(AutofillHostMsg_HidePasswordGenerationPopup::ID,
299 password_generation_->messages()[0]->type());
300 password_generation_->clear_messages();
302 // Simulate the user deleting characters. The generation popup should be shown
303 // again.
304 first_password_element.setValue(
305 base::ASCIIToUTF16(
306 std::string(password_generation_->kMaximumOfferSize, 'a')));
307 // Cast to WebAutofillClient where textFieldDidChange() is public.
308 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
309 first_password_element);
310 // textFieldDidChange posts a task, so we need to wait until it's been
311 // processed.
312 base::MessageLoop::current()->RunUntilIdle();
313 // There should now be a message to show the UI.
314 ASSERT_EQ(1u, password_generation_->messages().size());
315 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
316 password_generation_->messages()[0]->type());
317 password_generation_->clear_messages();
319 // Change focus. Bubble should be hidden, but that is handled by AutofilAgent,
320 // so no messages are sent.
321 ExecuteJavaScript("document.getElementById('username').focus();");
322 EXPECT_EQ(0u, password_generation_->messages().size());
323 password_generation_->clear_messages();
325 // Focusing the password field will bring up the generation UI again.
326 ExecuteJavaScript("document.getElementById('first_password').focus();");
327 EXPECT_EQ(1u, password_generation_->messages().size());
328 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
329 password_generation_->messages()[0]->type());
330 password_generation_->clear_messages();
333 } // namespace autofill