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
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/files/file_util.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/test/base/chrome_render_view_test.h"
10 #include "chrome/test/base/ui_test_utils.h"
11 #include "components/autofill/content/common/autofill_messages.h"
12 #include "components/autofill/content/renderer/autofill_agent.h"
13 #include "components/autofill/core/common/form_data.h"
14 #include "components/autofill/core/common/form_field_data.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/renderer/render_frame.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/WebKit/public/platform/WebString.h"
19 #include "third_party/WebKit/public/platform/WebURLRequest.h"
20 #include "third_party/WebKit/public/platform/WebVector.h"
21 #include "third_party/WebKit/public/web/WebDocument.h"
22 #include "third_party/WebKit/public/web/WebFormElement.h"
23 #include "third_party/WebKit/public/web/WebInputElement.h"
24 #include "third_party/WebKit/public/web/WebLocalFrame.h"
26 using base::ASCIIToUTF16
;
27 using blink::WebDocument
;
28 using blink::WebElement
;
29 using blink::WebFormElement
;
30 using blink::WebFrame
;
31 using blink::WebLocalFrame
;
32 using blink::WebInputElement
;
33 using blink::WebString
;
34 using blink::WebURLRequest
;
35 using blink::WebVector
;
41 autofill::FormFieldData
,
43 bool> AutofillQueryParam
;
45 class AutofillRendererTest
: public ChromeRenderViewTest
{
47 AutofillRendererTest() {}
48 ~AutofillRendererTest() override
{}
51 void SetUp() override
{
52 ChromeRenderViewTest::SetUp();
54 // Don't want any delay for form state sync changes. This will still post a
55 // message so updates will get coalesced, but as soon as we spin the message
56 // loop, it will generate an update.
57 SendContentStateImmediately();
60 void SimulateRequestAutocompleteResult(
61 blink::WebFrame
* invoking_frame
,
62 const blink::WebFormElement::AutocompleteResult
& result
,
63 const base::string16
& message
) {
64 AutofillMsg_RequestAutocompleteResult
msg(0, result
, message
, FormData());
65 content::RenderFrame::FromWebFrame(invoking_frame
)->OnMessageReceived(msg
);
69 DISALLOW_COPY_AND_ASSIGN(AutofillRendererTest
);
72 TEST_F(AutofillRendererTest
, SendForms
) {
73 LoadHTML("<form method='POST'>"
74 " <input type='text' id='firstname'/>"
75 " <input type='text' id='middlename'/>"
76 " <input type='text' id='lastname' autoComplete='off'/>"
77 " <input type='hidden' id='email'/>"
78 " <select id='state'/>"
80 " <option>California</option>"
81 " <option>Texas</option>"
85 // Verify that "FormsSeen" sends the expected number of fields.
86 const IPC::Message
* message
= render_thread_
->sink().GetFirstMessageMatching(
87 AutofillHostMsg_FormsSeen::ID
);
88 ASSERT_NE(nullptr, message
);
89 AutofillHostMsg_FormsSeen::Param params
;
90 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
91 std::vector
<FormData
> forms
= get
<0>(params
);
92 ASSERT_EQ(1UL, forms
.size());
93 ASSERT_EQ(4UL, forms
[0].fields
.size());
95 FormFieldData expected
;
97 expected
.name
= ASCIIToUTF16("firstname");
98 expected
.value
= base::string16();
99 expected
.form_control_type
= "text";
100 expected
.max_length
= WebInputElement::defaultMaxLength();
101 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[0]);
103 expected
.name
= ASCIIToUTF16("middlename");
104 expected
.value
= base::string16();
105 expected
.form_control_type
= "text";
106 expected
.max_length
= WebInputElement::defaultMaxLength();
107 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[1]);
109 expected
.name
= ASCIIToUTF16("lastname");
110 expected
.value
= base::string16();
111 expected
.form_control_type
= "text";
112 expected
.autocomplete_attribute
= "off";
113 expected
.max_length
= WebInputElement::defaultMaxLength();
114 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[2]);
115 expected
.autocomplete_attribute
= std::string(); // reset
117 expected
.name
= ASCIIToUTF16("state");
118 expected
.value
= ASCIIToUTF16("?");
119 expected
.form_control_type
= "select-one";
120 expected
.max_length
= 0;
121 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[3]);
123 render_thread_
->sink().ClearMessages();
125 // Dynamically create a new form. A new message should be sent for it, but
126 // not for the previous form.
128 "var newForm=document.createElement('form');"
129 "newForm.id='new_testform';"
130 "newForm.action='http://google.com';"
131 "newForm.method='post';"
132 "var newFirstname=document.createElement('input');"
133 "newFirstname.setAttribute('type', 'text');"
134 "newFirstname.setAttribute('id', 'second_firstname');"
135 "newFirstname.value = 'Bob';"
136 "var newLastname=document.createElement('input');"
137 "newLastname.setAttribute('type', 'text');"
138 "newLastname.setAttribute('id', 'second_lastname');"
139 "newLastname.value = 'Hope';"
140 "var newEmail=document.createElement('input');"
141 "newEmail.setAttribute('type', 'text');"
142 "newEmail.setAttribute('id', 'second_email');"
143 "newEmail.value = 'bobhope@example.com';"
144 "newForm.appendChild(newFirstname);"
145 "newForm.appendChild(newLastname);"
146 "newForm.appendChild(newEmail);"
147 "document.body.appendChild(newForm);");
148 msg_loop_
.RunUntilIdle();
150 message
= render_thread_
->sink().GetFirstMessageMatching(
151 AutofillHostMsg_FormsSeen::ID
);
152 ASSERT_NE(nullptr, message
);
153 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
154 forms
= get
<0>(params
);
155 ASSERT_EQ(1UL, forms
.size());
156 ASSERT_EQ(3UL, forms
[0].fields
.size());
158 expected
.form_control_type
= "text";
159 expected
.max_length
= WebInputElement::defaultMaxLength();
161 expected
.name
= ASCIIToUTF16("second_firstname");
162 expected
.value
= ASCIIToUTF16("Bob");
163 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[0]);
165 expected
.name
= ASCIIToUTF16("second_lastname");
166 expected
.value
= ASCIIToUTF16("Hope");
167 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[1]);
169 expected
.name
= ASCIIToUTF16("second_email");
170 expected
.value
= ASCIIToUTF16("bobhope@example.com");
171 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[2]);
174 TEST_F(AutofillRendererTest
, EnsureNoFormSeenIfTooFewFields
) {
175 LoadHTML("<form method='POST'>"
176 " <input type='text' id='firstname'/>"
177 " <input type='text' id='middlename'/>"
180 // Verify that "FormsSeen" isn't sent, as there are too few fields.
181 const IPC::Message
* message
= render_thread_
->sink().GetFirstMessageMatching(
182 AutofillHostMsg_FormsSeen::ID
);
183 ASSERT_NE(nullptr, message
);
184 AutofillHostMsg_FormsSeen::Param params
;
185 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
186 const std::vector
<FormData
>& forms
= get
<0>(params
);
187 ASSERT_EQ(0UL, forms
.size());
190 TEST_F(AutofillRendererTest
, ShowAutofillWarning
) {
191 LoadHTML("<form method='POST' autocomplete='Off'>"
192 " <input id='firstname' autocomplete='OFF'/>"
193 " <input id='middlename'/>"
194 " <input id='lastname'/>"
197 // Verify that "QueryFormFieldAutofill" isn't sent prior to a user
199 const IPC::Message
* message0
= render_thread_
->sink().GetFirstMessageMatching(
200 AutofillHostMsg_QueryFormFieldAutofill::ID
);
201 EXPECT_EQ(nullptr, message0
);
203 WebFrame
* web_frame
= GetMainFrame();
204 WebDocument document
= web_frame
->document();
205 WebInputElement firstname
=
206 document
.getElementById("firstname").to
<WebInputElement
>();
207 WebInputElement middlename
=
208 document
.getElementById("middlename").to
<WebInputElement
>();
210 // Simulate attempting to Autofill the form from the first element, which
211 // specifies autocomplete="off". This should still trigger an IPC which
212 // shouldn't display warnings.
213 static_cast<PageClickListener
*>(autofill_agent_
)
214 ->FormControlElementClicked(firstname
, true);
215 const IPC::Message
* message1
= render_thread_
->sink().GetFirstMessageMatching(
216 AutofillHostMsg_QueryFormFieldAutofill::ID
);
217 EXPECT_NE(nullptr, message1
);
219 AutofillQueryParam query_param
;
220 AutofillHostMsg_QueryFormFieldAutofill::Read(message1
, &query_param
);
221 EXPECT_FALSE(get
<4>(query_param
));
222 render_thread_
->sink().ClearMessages();
224 // Simulate attempting to Autofill the form from the second element, which
225 // does not specify autocomplete="off". This should trigger an IPC that will
226 // show warnings, as we *do* show warnings for elements that don't themselves
227 // set autocomplete="off", but for which the form does.
228 static_cast<PageClickListener
*>(autofill_agent_
)
229 ->FormControlElementClicked(middlename
, true);
230 const IPC::Message
* message2
= render_thread_
->sink().GetFirstMessageMatching(
231 AutofillHostMsg_QueryFormFieldAutofill::ID
);
232 ASSERT_NE(nullptr, message2
);
234 AutofillHostMsg_QueryFormFieldAutofill::Read(message2
, &query_param
);
235 EXPECT_TRUE(get
<4>(query_param
));
238 // Regression test for [ http://crbug.com/346010 ].
239 TEST_F(AutofillRendererTest
, DontCrashWhileAssociatingForms
) {
240 LoadHTML("<form id='form'>"
242 "<script id='script'>"
243 "document.documentElement.appendChild(foo);"
244 "newDoc = document.implementation.createDocument("
245 " 'http://www.w3.org/1999/xhtml', 'html');"
246 "foo.insertBefore(form, script);"
247 "newDoc.adoptNode(foo);"
253 TEST_F(AutofillRendererTest
, DynamicallyAddedUnownedFormElements
) {
254 std::string html_data
;
255 base::FilePath test_path
= ui_test_utils::GetTestFilePath(
256 base::FilePath(FILE_PATH_LITERAL("autofill")),
257 base::FilePath(FILE_PATH_LITERAL("autofill_noform_dynamic.html")));
258 ASSERT_TRUE(base::ReadFileToString(test_path
, &html_data
));
259 LoadHTML(html_data
.c_str());
261 // Verify that "FormsSeen" sends the expected number of fields.
262 const IPC::Message
* message
= render_thread_
->sink().GetFirstMessageMatching(
263 AutofillHostMsg_FormsSeen::ID
);
264 ASSERT_NE(nullptr, message
);
265 AutofillHostMsg_FormsSeen::Param params
;
266 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
267 std::vector
<FormData
> forms
= get
<0>(params
);
268 ASSERT_EQ(1UL, forms
.size());
269 ASSERT_EQ(7UL, forms
[0].fields
.size());
271 render_thread_
->sink().ClearMessages();
273 ExecuteJavaScript("AddFields()");
274 msg_loop_
.RunUntilIdle();
276 message
= render_thread_
->sink().GetFirstMessageMatching(
277 AutofillHostMsg_FormsSeen::ID
);
278 ASSERT_NE(nullptr, message
);
279 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
280 forms
= get
<0>(params
);
281 ASSERT_EQ(1UL, forms
.size());
282 ASSERT_EQ(9UL, forms
[0].fields
.size());
284 FormFieldData expected
;
286 expected
.name
= ASCIIToUTF16("EMAIL_ADDRESS");
287 expected
.value
.clear();
288 expected
.form_control_type
= "text";
289 expected
.max_length
= WebInputElement::defaultMaxLength();
290 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[7]);
292 expected
.name
= ASCIIToUTF16("PHONE_HOME_WHOLE_NUMBER");
293 expected
.value
.clear();
294 expected
.form_control_type
= "text";
295 expected
.max_length
= WebInputElement::defaultMaxLength();
296 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[8]);
299 class RequestAutocompleteRendererTest
: public AutofillRendererTest
{
301 RequestAutocompleteRendererTest()
302 : invoking_frame_(NULL
), sibling_frame_(NULL
) {}
303 ~RequestAutocompleteRendererTest() override
{}
306 void SetUp() override
{
307 AutofillRendererTest::SetUp();
309 // Bypass the HTTPS-only restriction to show requestAutocomplete.
310 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
311 command_line
->AppendSwitch(::switches::kReduceSecurityForTesting
);
313 GURL
url("data:text/html;charset=utf-8,"
314 "<form><input autocomplete=cc-number></form>");
315 const char kDoubleIframeHtml
[] = "<iframe id=subframe src='%s'></iframe>"
316 "<iframe id=sibling></iframe>";
317 LoadHTML(base::StringPrintf(kDoubleIframeHtml
, url
.spec().c_str()).c_str());
319 WebElement subframe
= GetMainFrame()->document().getElementById("subframe");
320 ASSERT_FALSE(subframe
.isNull());
321 invoking_frame_
= WebLocalFrame::fromFrameOwnerElement(subframe
);
322 ASSERT_TRUE(invoking_frame());
323 ASSERT_EQ(GetMainFrame(), invoking_frame()->parent());
325 WebElement sibling
= GetMainFrame()->document().getElementById("sibling");
326 ASSERT_FALSE(sibling
.isNull());
327 sibling_frame_
= WebLocalFrame::fromFrameOwnerElement(sibling
);
328 ASSERT_TRUE(sibling_frame());
330 WebVector
<WebFormElement
> forms
;
331 invoking_frame()->document().forms(forms
);
332 ASSERT_EQ(1U, forms
.size());
333 invoking_form_
= forms
[0];
334 ASSERT_FALSE(invoking_form().isNull());
336 render_thread_
->sink().ClearMessages();
338 // Invoke requestAutocomplete to show the dialog.
339 invoking_frame_
->autofillClient()->didRequestAutocomplete(invoking_form());
340 ASSERT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
341 AutofillHostMsg_RequestAutocomplete::ID
));
343 render_thread_
->sink().ClearMessages();
346 void TearDown() override
{
347 invoking_form_
.reset();
348 AutofillRendererTest::TearDown();
351 void NavigateFrame(WebFrame
* frame
) {
352 frame
->loadRequest(WebURLRequest(GURL("about:blank")));
353 ProcessPendingMessages();
356 const WebFormElement
& invoking_form() const { return invoking_form_
; }
357 WebLocalFrame
* invoking_frame() { return invoking_frame_
; }
358 WebFrame
* sibling_frame() { return sibling_frame_
; }
361 WebFormElement invoking_form_
;
362 WebLocalFrame
* invoking_frame_
;
363 WebFrame
* sibling_frame_
;
366 DISALLOW_COPY_AND_ASSIGN(RequestAutocompleteRendererTest
);
369 TEST_F(RequestAutocompleteRendererTest
, InvokingTwiceOnlyShowsOnce
) {
370 // Attempting to show the requestAutocomplete dialog again should be ignored.
371 invoking_frame_
->autofillClient()->didRequestAutocomplete(invoking_form());
372 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
373 AutofillHostMsg_RequestAutocomplete::ID
));
376 } // namespace autofill