Add testing/scripts/OWNERS
[chromium-blink-merge.git] / chrome / renderer / autofill / password_generation_agent_browsertest.cc
blobd456a77a33c03c2427611155259340262b1053a3
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 "base/test/histogram_tester.h"
10 #include "chrome/test/base/chrome_render_view_test.h"
11 #include "components/autofill/content/common/autofill_messages.h"
12 #include "components/autofill/content/renderer/autofill_agent.h"
13 #include "components/autofill/content/renderer/test_password_generation_agent.h"
14 #include "components/autofill/core/common/form_data.h"
15 #include "components/autofill/core/common/password_generation_util.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/WebKit/public/platform/WebString.h"
18 #include "third_party/WebKit/public/web/WebDocument.h"
19 #include "third_party/WebKit/public/web/WebLocalFrame.h"
20 #include "third_party/WebKit/public/web/WebWidget.h"
22 using blink::WebDocument;
23 using blink::WebElement;
24 using blink::WebInputElement;
25 using blink::WebNode;
26 using blink::WebString;
28 namespace autofill {
30 class PasswordGenerationAgentTest : public ChromeRenderViewTest {
31 public:
32 PasswordGenerationAgentTest() {}
34 void TearDown() override {
35 LoadHTML("");
36 ChromeRenderViewTest::TearDown();
39 void SetNotBlacklistedMessage(const char* form_str) {
40 autofill::PasswordForm form;
41 form.origin =
42 GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str));
43 AutofillMsg_FormNotBlacklisted msg(0, form);
44 password_generation_->OnMessageReceived(msg);
47 void SetAccountCreationFormsDetectedMessage(const char* form_str) {
48 autofill::FormData form;
49 form.origin =
50 GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str));
51 std::vector<autofill::FormData> forms;
52 forms.push_back(form);
53 AutofillMsg_AccountCreationFormsDetected msg(0, forms);
54 password_generation_->OnMessageReceived(msg);
57 void ExpectPasswordGenerationAvailable(const char* element_id,
58 bool available) {
59 WebDocument document = GetMainFrame()->document();
60 WebElement element =
61 document.getElementById(WebString::fromUTF8(element_id));
62 ASSERT_FALSE(element.isNull());
63 ExecuteJavaScript(
64 base::StringPrintf("document.getElementById('%s').focus();",
65 element_id).c_str());
66 if (available) {
67 ASSERT_EQ(1u, password_generation_->messages().size());
68 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
69 password_generation_->messages()[0]->type());
70 } else {
71 EXPECT_EQ(0u, password_generation_->messages().size());
73 password_generation_->clear_messages();
76 private:
77 DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgentTest);
80 const char kSigninFormHTML[] =
81 "<FORM name = 'blah' action = 'http://www.random.com/'> "
82 " <INPUT type = 'text' id = 'username'/> "
83 " <INPUT type = 'password' id = 'password'/> "
84 " <INPUT type = 'submit' value = 'LOGIN' />"
85 "</FORM>";
87 const char kAccountCreationFormHTML[] =
88 "<FORM name = 'blah' action = 'http://www.random.com/'> "
89 " <INPUT type = 'text' id = 'username'/> "
90 " <INPUT type = 'password' id = 'first_password' "
91 " autocomplete = 'off' size = 5/>"
92 " <INPUT type = 'password' id = 'second_password' size = 5/> "
93 " <INPUT type = 'text' id = 'address'/> "
94 " <INPUT type = 'submit' value = 'LOGIN' />"
95 "</FORM>";
97 const char kHiddenPasswordAccountCreationFormHTML[] =
98 "<FORM name = 'blah' action = 'http://www.random.com/'> "
99 " <INPUT type = 'text' id = 'username'/> "
100 " <INPUT type = 'password' id = 'first_password'/> "
101 " <INPUT type = 'password' id = 'second_password' style='display:none'/> "
102 " <INPUT type = 'submit' value = 'LOGIN' />"
103 "</FORM>";
105 const char kInvalidActionAccountCreationFormHTML[] =
106 "<FORM name = 'blah' action = 'invalid'> "
107 " <INPUT type = 'text' id = 'username'/> "
108 " <INPUT type = 'password' id = 'first_password'/> "
109 " <INPUT type = 'password' id = 'second_password'/> "
110 " <INPUT type = 'submit' value = 'LOGIN' />"
111 "</FORM>";
113 TEST_F(PasswordGenerationAgentTest, DetectionTest) {
114 // Don't shown the icon for non account creation forms.
115 LoadHTML(kSigninFormHTML);
116 ExpectPasswordGenerationAvailable("password", false);
118 // We don't show the decoration yet because the feature isn't enabled.
119 LoadHTML(kAccountCreationFormHTML);
120 ExpectPasswordGenerationAvailable("first_password", false);
122 // Pretend like We have received message indicating site is not blacklisted,
123 // and we have received message indicating the form is classified as
124 // ACCOUNT_CREATION_FORM form Autofill server. We should show the icon.
125 LoadHTML(kAccountCreationFormHTML);
126 SetNotBlacklistedMessage(kAccountCreationFormHTML);
127 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
128 ExpectPasswordGenerationAvailable("first_password", true);
130 // This doesn't trigger because hidden password fields are ignored.
131 LoadHTML(kHiddenPasswordAccountCreationFormHTML);
132 SetNotBlacklistedMessage(kHiddenPasswordAccountCreationFormHTML);
133 SetAccountCreationFormsDetectedMessage(
134 kHiddenPasswordAccountCreationFormHTML);
135 ExpectPasswordGenerationAvailable("first_password", false);
137 // This doesn't trigger because the form action is invalid.
138 LoadHTML(kInvalidActionAccountCreationFormHTML);
139 SetNotBlacklistedMessage(kInvalidActionAccountCreationFormHTML);
140 SetAccountCreationFormsDetectedMessage(kInvalidActionAccountCreationFormHTML);
141 ExpectPasswordGenerationAvailable("first_password", false);
144 TEST_F(PasswordGenerationAgentTest, FillTest) {
145 // Make sure that we are enabled before loading HTML.
146 LoadHTML(kAccountCreationFormHTML);
148 WebDocument document = GetMainFrame()->document();
149 WebElement element =
150 document.getElementById(WebString::fromUTF8("first_password"));
151 ASSERT_FALSE(element.isNull());
152 WebInputElement first_password_element = element.to<WebInputElement>();
153 element = document.getElementById(WebString::fromUTF8("second_password"));
154 ASSERT_FALSE(element.isNull());
155 WebInputElement second_password_element = element.to<WebInputElement>();
157 // Both password fields should be empty.
158 EXPECT_TRUE(first_password_element.value().isNull());
159 EXPECT_TRUE(second_password_element.value().isNull());
161 base::string16 password = base::ASCIIToUTF16("random_password");
162 AutofillMsg_GeneratedPasswordAccepted msg(0, password);
163 password_generation_->OnMessageReceived(msg);
165 // Password fields are filled out and set as being autofilled.
166 EXPECT_EQ(password, first_password_element.value());
167 EXPECT_EQ(password, second_password_element.value());
168 EXPECT_TRUE(first_password_element.isAutofilled());
169 EXPECT_TRUE(second_password_element.isAutofilled());
171 // Focus moved to the next input field.
172 // TODO(zysxqn): Change this back to the address element once Bug 90224
173 // https://bugs.webkit.org/show_bug.cgi?id=90224 has been fixed.
174 element = document.getElementById(WebString::fromUTF8("first_password"));
175 ASSERT_FALSE(element.isNull());
176 EXPECT_EQ(element, document.focusedElement());
179 TEST_F(PasswordGenerationAgentTest, EditingTest) {
180 LoadHTML(kAccountCreationFormHTML);
181 SetNotBlacklistedMessage(kAccountCreationFormHTML);
182 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
184 WebDocument document = GetMainFrame()->document();
185 WebElement element =
186 document.getElementById(WebString::fromUTF8("first_password"));
187 ASSERT_FALSE(element.isNull());
188 WebInputElement first_password_element = element.to<WebInputElement>();
189 element = document.getElementById(WebString::fromUTF8("second_password"));
190 ASSERT_FALSE(element.isNull());
191 WebInputElement second_password_element = element.to<WebInputElement>();
193 base::string16 password = base::ASCIIToUTF16("random_password");
194 AutofillMsg_GeneratedPasswordAccepted msg(0, password);
195 password_generation_->OnMessageReceived(msg);
197 // Passwords start out the same.
198 EXPECT_EQ(password, first_password_element.value());
199 EXPECT_EQ(password, second_password_element.value());
201 // After editing the first field they are still the same.
202 base::string16 edited_password = base::ASCIIToUTF16("edited_password");
203 first_password_element.setValue(edited_password);
204 // Cast to WebAutofillClient where textFieldDidChange() is public.
205 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
206 first_password_element);
207 // textFieldDidChange posts a task, so we need to wait until it's been
208 // processed.
209 base::MessageLoop::current()->RunUntilIdle();
210 EXPECT_EQ(edited_password, first_password_element.value());
211 EXPECT_EQ(edited_password, second_password_element.value());
213 // Verify that password mirroring works correctly even when the password
214 // is deleted.
215 base::string16 empty_password;
216 first_password_element.setValue(empty_password);
217 // Cast to WebAutofillClient where textFieldDidChange() is public.
218 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
219 first_password_element);
220 // textFieldDidChange posts a task, so we need to wait until it's been
221 // processed.
222 base::MessageLoop::current()->RunUntilIdle();
223 EXPECT_EQ(empty_password, first_password_element.value());
224 EXPECT_EQ(empty_password, second_password_element.value());
227 TEST_F(PasswordGenerationAgentTest, BlacklistedTest) {
228 // Did not receive not blacklisted message. Don't show password generation
229 // icon.
230 LoadHTML(kAccountCreationFormHTML);
231 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
232 ExpectPasswordGenerationAvailable("first_password", false);
234 // Receive one not blacklisted message for non account creation form. Don't
235 // show password generation icon.
236 LoadHTML(kAccountCreationFormHTML);
237 SetNotBlacklistedMessage(kSigninFormHTML);
238 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
239 ExpectPasswordGenerationAvailable("first_password", false);
241 // Receive one not blackliste message for account creation form. Show password
242 // generation icon.
243 LoadHTML(kAccountCreationFormHTML);
244 SetNotBlacklistedMessage(kAccountCreationFormHTML);
245 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
246 ExpectPasswordGenerationAvailable("first_password", true);
248 // Receive two not blacklisted messages, one is for account creation form and
249 // the other is not. Show password generation icon.
250 LoadHTML(kAccountCreationFormHTML);
251 SetNotBlacklistedMessage(kAccountCreationFormHTML);
252 SetNotBlacklistedMessage(kSigninFormHTML);
253 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
254 ExpectPasswordGenerationAvailable("first_password", true);
257 TEST_F(PasswordGenerationAgentTest, AccountCreationFormsDetectedTest) {
258 // Did not receive account creation forms detected messege. Don't show
259 // password generation icon.
260 LoadHTML(kAccountCreationFormHTML);
261 SetNotBlacklistedMessage(kAccountCreationFormHTML);
262 ExpectPasswordGenerationAvailable("first_password", false);
264 // Receive the account creation forms detected message. Show password
265 // generation icon.
266 LoadHTML(kAccountCreationFormHTML);
267 SetNotBlacklistedMessage(kAccountCreationFormHTML);
268 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
269 ExpectPasswordGenerationAvailable("first_password", true);
272 TEST_F(PasswordGenerationAgentTest, MaximumOfferSize) {
273 base::HistogramTester histogram_tester;
275 LoadHTML(kAccountCreationFormHTML);
276 SetNotBlacklistedMessage(kAccountCreationFormHTML);
277 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
278 ExpectPasswordGenerationAvailable("first_password", true);
280 WebDocument document = GetMainFrame()->document();
281 WebElement element =
282 document.getElementById(WebString::fromUTF8("first_password"));
283 ASSERT_FALSE(element.isNull());
284 WebInputElement first_password_element = element.to<WebInputElement>();
286 // Make a password just under 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 show the UI.
297 ASSERT_EQ(1u, password_generation_->messages().size());
298 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
299 password_generation_->messages()[0]->type());
300 password_generation_->clear_messages();
302 // Simulate a user typing a password just over maximum offer size.
303 first_password_element.setValue(
304 base::ASCIIToUTF16(
305 std::string(password_generation_->kMaximumOfferSize + 1, 'a')));
306 // Cast to WebAutofillClient where textFieldDidChange() is public.
307 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
308 first_password_element);
309 // textFieldDidChange posts a task, so we need to wait until it's been
310 // processed.
311 base::MessageLoop::current()->RunUntilIdle();
312 // There should now be a message to hide the UI.
313 ASSERT_EQ(1u, password_generation_->messages().size());
314 EXPECT_EQ(AutofillHostMsg_HidePasswordGenerationPopup::ID,
315 password_generation_->messages()[0]->type());
316 password_generation_->clear_messages();
318 // Simulate the user deleting characters. The generation popup should be shown
319 // again.
320 first_password_element.setValue(
321 base::ASCIIToUTF16(
322 std::string(password_generation_->kMaximumOfferSize, 'a')));
323 // Cast to WebAutofillClient where textFieldDidChange() is public.
324 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
325 first_password_element);
326 // textFieldDidChange posts a task, so we need to wait until it's been
327 // processed.
328 base::MessageLoop::current()->RunUntilIdle();
329 // There should now be a message to show the UI.
330 ASSERT_EQ(1u, password_generation_->messages().size());
331 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
332 password_generation_->messages()[0]->type());
333 password_generation_->clear_messages();
335 // Change focus. Bubble should be hidden, but that is handled by AutofilAgent,
336 // so no messages are sent.
337 ExecuteJavaScript("document.getElementById('username').focus();");
338 EXPECT_EQ(0u, password_generation_->messages().size());
339 password_generation_->clear_messages();
341 // Focusing the password field will bring up the generation UI again.
342 ExecuteJavaScript("document.getElementById('first_password').focus();");
343 EXPECT_EQ(1u, password_generation_->messages().size());
344 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
345 password_generation_->messages()[0]->type());
346 password_generation_->clear_messages();
348 // Loading a different page triggers UMA stat upload. Verify that only one
349 // display event is sent even though
350 LoadHTML(kSigninFormHTML);
352 histogram_tester.ExpectBucketCount(
353 "PasswordGeneration.Event",
354 autofill::password_generation::GENERATION_POPUP_SHOWN,
358 TEST_F(PasswordGenerationAgentTest, DynamicFormTest) {
359 LoadHTML(kSigninFormHTML);
360 SetNotBlacklistedMessage(kSigninFormHTML);
361 SetAccountCreationFormsDetectedMessage(kSigninFormHTML);
363 ExecuteJavaScript(
364 "var form = document.createElement('form');"
365 "var username = document.createElement('input');"
366 "username.type = 'text';"
367 "username.id = 'dynamic_username';"
368 "var first_password = document.createElement('input');"
369 "first_password.type = 'password';"
370 "first_password.id = 'first_password';"
371 "first_password.name = 'first_password';"
372 "var second_password = document.createElement('input');"
373 "second_password.type = 'password';"
374 "second_password.id = 'second_password';"
375 "second_password.name = 'second_password';"
376 "form.appendChild(username);"
377 "form.appendChild(first_password);"
378 "form.appendChild(second_password);"
379 "document.body.appendChild(form);");
380 ProcessPendingMessages();
381 // TODO(gcasto): I'm slighty worried about flakes in this test where
382 // didAssociateFormControls() isn't called. If this turns out to be a problem
383 // adding a call to OnDynamicFormsSeen(GetMainFrame()) will fix it, though
384 // it will weaken the test.
385 ExpectPasswordGenerationAvailable("first_password", true);
388 } // namespace autofill