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/strings/stringprintf.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/test/base/chrome_render_view_test.h"
9 #include "components/autofill/content/common/autofill_messages.h"
10 #include "components/autofill/content/renderer/autofill_agent.h"
11 #include "components/autofill/core/common/form_data.h"
12 #include "components/autofill/core/common/form_field_data.h"
13 #include "content/public/common/content_switches.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/WebKit/public/platform/WebString.h"
16 #include "third_party/WebKit/public/platform/WebURLRequest.h"
17 #include "third_party/WebKit/public/platform/WebVector.h"
18 #include "third_party/WebKit/public/web/WebDocument.h"
19 #include "third_party/WebKit/public/web/WebFormElement.h"
20 #include "third_party/WebKit/public/web/WebInputElement.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
23 using base::ASCIIToUTF16
;
24 using blink::WebDocument
;
25 using blink::WebElement
;
26 using blink::WebFormElement
;
27 using blink::WebFrame
;
28 using blink::WebLocalFrame
;
29 using blink::WebInputElement
;
30 using blink::WebString
;
31 using blink::WebURLRequest
;
32 using blink::WebVector
;
38 autofill::FormFieldData
,
40 bool> AutofillQueryParam
;
42 class AutofillRendererTest
: public ChromeRenderViewTest
{
44 AutofillRendererTest() {}
45 ~AutofillRendererTest() override
{}
48 void SetUp() override
{
49 ChromeRenderViewTest::SetUp();
51 // Don't want any delay for form state sync changes. This will still post a
52 // message so updates will get coalesced, but as soon as we spin the message
53 // loop, it will generate an update.
54 SendContentStateImmediately();
57 void SimulateRequestAutocompleteResult(
58 const blink::WebFormElement::AutocompleteResult
& result
,
59 const base::string16
& message
) {
60 AutofillMsg_RequestAutocompleteResult
msg(0, result
, message
, FormData());
61 static_cast<content::RenderViewObserver
*>(autofill_agent_
)
62 ->OnMessageReceived(msg
);
66 DISALLOW_COPY_AND_ASSIGN(AutofillRendererTest
);
69 TEST_F(AutofillRendererTest
, SendForms
) {
70 LoadHTML("<form method='POST'>"
71 " <input type='text' id='firstname'/>"
72 " <input type='text' id='middlename'/>"
73 " <input type='text' id='lastname' autoComplete='off'/>"
74 " <input type='hidden' id='email'/>"
75 " <select id='state'/>"
77 " <option>California</option>"
78 " <option>Texas</option>"
82 // Verify that "FormsSeen" sends the expected number of fields.
83 const IPC::Message
* message
= render_thread_
->sink().GetFirstMessageMatching(
84 AutofillHostMsg_FormsSeen::ID
);
85 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
86 AutofillHostMsg_FormsSeen::Param params
;
87 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
88 std::vector
<FormData
> forms
= params
.a
;
89 ASSERT_EQ(1UL, forms
.size());
90 ASSERT_EQ(4UL, forms
[0].fields
.size());
92 FormFieldData expected
;
94 expected
.name
= ASCIIToUTF16("firstname");
95 expected
.value
= base::string16();
96 expected
.form_control_type
= "text";
97 expected
.max_length
= WebInputElement::defaultMaxLength();
98 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[0]);
100 expected
.name
= ASCIIToUTF16("middlename");
101 expected
.value
= base::string16();
102 expected
.form_control_type
= "text";
103 expected
.max_length
= WebInputElement::defaultMaxLength();
104 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[1]);
106 expected
.name
= ASCIIToUTF16("lastname");
107 expected
.value
= base::string16();
108 expected
.form_control_type
= "text";
109 expected
.autocomplete_attribute
= "off";
110 expected
.max_length
= WebInputElement::defaultMaxLength();
111 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[2]);
112 expected
.autocomplete_attribute
= std::string(); // reset
114 expected
.name
= ASCIIToUTF16("state");
115 expected
.value
= ASCIIToUTF16("?");
116 expected
.form_control_type
= "select-one";
117 expected
.max_length
= 0;
118 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[3]);
120 render_thread_
->sink().ClearMessages();
122 // Dynamically create a new form. A new message should be sent for it, but
123 // not for the previous form.
125 "var newForm=document.createElement('form');"
126 "newForm.id='new_testform';"
127 "newForm.action='http://google.com';"
128 "newForm.method='post';"
129 "var newFirstname=document.createElement('input');"
130 "newFirstname.setAttribute('type', 'text');"
131 "newFirstname.setAttribute('id', 'second_firstname');"
132 "newFirstname.value = 'Bob';"
133 "var newLastname=document.createElement('input');"
134 "newLastname.setAttribute('type', 'text');"
135 "newLastname.setAttribute('id', 'second_lastname');"
136 "newLastname.value = 'Hope';"
137 "var newEmail=document.createElement('input');"
138 "newEmail.setAttribute('type', 'text');"
139 "newEmail.setAttribute('id', 'second_email');"
140 "newEmail.value = 'bobhope@example.com';"
141 "newForm.appendChild(newFirstname);"
142 "newForm.appendChild(newLastname);"
143 "newForm.appendChild(newEmail);"
144 "document.body.appendChild(newForm);");
145 msg_loop_
.RunUntilIdle();
147 message
= render_thread_
->sink().GetFirstMessageMatching(
148 AutofillHostMsg_FormsSeen::ID
);
149 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
150 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
152 ASSERT_EQ(1UL, forms
.size());
153 ASSERT_EQ(3UL, forms
[0].fields
.size());
155 expected
.form_control_type
= "text";
156 expected
.max_length
= WebInputElement::defaultMaxLength();
158 expected
.name
= ASCIIToUTF16("second_firstname");
159 expected
.value
= ASCIIToUTF16("Bob");
160 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[0]);
162 expected
.name
= ASCIIToUTF16("second_lastname");
163 expected
.value
= ASCIIToUTF16("Hope");
164 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[1]);
166 expected
.name
= ASCIIToUTF16("second_email");
167 expected
.value
= ASCIIToUTF16("bobhope@example.com");
168 EXPECT_FORM_FIELD_DATA_EQUALS(expected
, forms
[0].fields
[2]);
171 TEST_F(AutofillRendererTest
, EnsureNoFormSeenIfTooFewFields
) {
172 LoadHTML("<form method='POST'>"
173 " <input type='text' id='firstname'/>"
174 " <input type='text' id='middlename'/>"
177 // Verify that "FormsSeen" isn't sent, as there are too few fields.
178 const IPC::Message
* message
= render_thread_
->sink().GetFirstMessageMatching(
179 AutofillHostMsg_FormsSeen::ID
);
180 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
181 AutofillHostMsg_FormsSeen::Param params
;
182 AutofillHostMsg_FormsSeen::Read(message
, ¶ms
);
183 const std::vector
<FormData
>& forms
= params
.a
;
184 ASSERT_EQ(0UL, forms
.size());
187 TEST_F(AutofillRendererTest
, ShowAutofillWarning
) {
188 LoadHTML("<form method='POST' autocomplete='Off'>"
189 " <input id='firstname' autocomplete='OFF'/>"
190 " <input id='middlename'/>"
191 " <input id='lastname'/>"
194 // Verify that "QueryFormFieldAutofill" isn't sent prior to a user
196 const IPC::Message
* message0
= render_thread_
->sink().GetFirstMessageMatching(
197 AutofillHostMsg_QueryFormFieldAutofill::ID
);
198 EXPECT_EQ(static_cast<IPC::Message
*>(NULL
), message0
);
200 WebFrame
* web_frame
= GetMainFrame();
201 WebDocument document
= web_frame
->document();
202 WebInputElement firstname
=
203 document
.getElementById("firstname").to
<WebInputElement
>();
204 WebInputElement middlename
=
205 document
.getElementById("middlename").to
<WebInputElement
>();
207 // Simulate attempting to Autofill the form from the first element, which
208 // specifies autocomplete="off". This should still trigger an IPC which
209 // shouldn't display warnings.
210 static_cast<PageClickListener
*>(autofill_agent_
)
211 ->FormControlElementClicked(firstname
, true);
212 const IPC::Message
* message1
= render_thread_
->sink().GetFirstMessageMatching(
213 AutofillHostMsg_QueryFormFieldAutofill::ID
);
214 EXPECT_NE(static_cast<IPC::Message
*>(NULL
), message1
);
216 AutofillQueryParam query_param
;
217 AutofillHostMsg_QueryFormFieldAutofill::Read(message1
, &query_param
);
218 EXPECT_FALSE(query_param
.e
);
219 render_thread_
->sink().ClearMessages();
221 // Simulate attempting to Autofill the form from the second element, which
222 // does not specify autocomplete="off". This should trigger an IPC that will
223 // show warnings, as we *do* show warnings for elements that don't themselves
224 // set autocomplete="off", but for which the form does.
225 static_cast<PageClickListener
*>(autofill_agent_
)
226 ->FormControlElementClicked(middlename
, true);
227 const IPC::Message
* message2
= render_thread_
->sink().GetFirstMessageMatching(
228 AutofillHostMsg_QueryFormFieldAutofill::ID
);
229 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message2
);
231 AutofillHostMsg_QueryFormFieldAutofill::Read(message2
, &query_param
);
232 EXPECT_TRUE(query_param
.e
);
235 // Regression test for [ http://crbug.com/346010 ].
236 TEST_F(AutofillRendererTest
, DontCrashWhileAssociatingForms
) {
237 LoadHTML("<form id='form'>"
239 "<script id='script'>"
240 "document.documentElement.appendChild(foo);"
241 "newDoc = document.implementation.createDocument("
242 " 'http://www.w3.org/1999/xhtml', 'html');"
243 "foo.insertBefore(form, script);"
244 "newDoc.adoptNode(foo);"
250 class RequestAutocompleteRendererTest
: public AutofillRendererTest
{
252 RequestAutocompleteRendererTest()
253 : invoking_frame_(NULL
), sibling_frame_(NULL
) {}
254 ~RequestAutocompleteRendererTest() override
{}
257 void SetUp() override
{
258 AutofillRendererTest::SetUp();
260 // Bypass the HTTPS-only restriction to show requestAutocomplete.
261 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
262 command_line
->AppendSwitch(::switches::kReduceSecurityForTesting
);
264 GURL
url("data:text/html;charset=utf-8,"
265 "<form><input autocomplete=cc-number></form>");
266 const char kDoubleIframeHtml
[] = "<iframe id=subframe src='%s'></iframe>"
267 "<iframe id=sibling></iframe>";
268 LoadHTML(base::StringPrintf(kDoubleIframeHtml
, url
.spec().c_str()).c_str());
270 WebElement subframe
= GetMainFrame()->document().getElementById("subframe");
271 ASSERT_FALSE(subframe
.isNull());
272 invoking_frame_
= WebLocalFrame::fromFrameOwnerElement(subframe
);
273 ASSERT_TRUE(invoking_frame());
274 ASSERT_EQ(GetMainFrame(), invoking_frame()->parent());
276 WebElement sibling
= GetMainFrame()->document().getElementById("sibling");
277 ASSERT_FALSE(sibling
.isNull());
278 sibling_frame_
= WebLocalFrame::fromFrameOwnerElement(sibling
);
279 ASSERT_TRUE(sibling_frame());
281 WebVector
<WebFormElement
> forms
;
282 invoking_frame()->document().forms(forms
);
283 ASSERT_EQ(1U, forms
.size());
284 invoking_form_
= forms
[0];
285 ASSERT_FALSE(invoking_form().isNull());
287 render_thread_
->sink().ClearMessages();
289 // Invoke requestAutocomplete to show the dialog.
290 static_cast<blink::WebAutofillClient
*>(autofill_agent_
)
291 ->didRequestAutocomplete(invoking_form());
292 ASSERT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
293 AutofillHostMsg_RequestAutocomplete::ID
));
295 render_thread_
->sink().ClearMessages();
298 void TearDown() override
{
299 invoking_form_
.reset();
300 AutofillRendererTest::TearDown();
303 void NavigateFrame(WebFrame
* frame
) {
304 frame
->loadRequest(WebURLRequest(GURL("about:blank")));
305 ProcessPendingMessages();
308 const WebFormElement
& invoking_form() const { return invoking_form_
; }
309 WebLocalFrame
* invoking_frame() { return invoking_frame_
; }
310 WebFrame
* sibling_frame() { return sibling_frame_
; }
313 WebFormElement invoking_form_
;
314 WebLocalFrame
* invoking_frame_
;
315 WebFrame
* sibling_frame_
;
317 DISALLOW_COPY_AND_ASSIGN(RequestAutocompleteRendererTest
);
320 TEST_F(RequestAutocompleteRendererTest
, SiblingNavigateIgnored
) {
321 // Pretend that a sibling frame navigated. No cancel should be sent.
322 NavigateFrame(sibling_frame());
323 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
324 AutofillHostMsg_CancelRequestAutocomplete::ID
));
327 TEST_F(RequestAutocompleteRendererTest
, SubframeNavigateCancels
) {
328 // Pretend that the invoking frame navigated. A cancel should be sent.
329 NavigateFrame(invoking_frame());
330 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
331 AutofillHostMsg_CancelRequestAutocomplete::ID
));
334 TEST_F(RequestAutocompleteRendererTest
, MainFrameNavigateCancels
) {
335 // Pretend that the top-level frame navigated. A cancel should be sent.
336 NavigateFrame(GetMainFrame());
337 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
338 AutofillHostMsg_CancelRequestAutocomplete::ID
));
341 TEST_F(RequestAutocompleteRendererTest
, NoCancelOnSubframeNavigateAfterDone
) {
342 // Pretend that the dialog was cancelled.
343 SimulateRequestAutocompleteResult(
344 WebFormElement::AutocompleteResultErrorCancel
,
345 base::ASCIIToUTF16("Print me to the console"));
347 // Additional navigations should not crash nor send cancels.
348 NavigateFrame(invoking_frame());
349 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
350 AutofillHostMsg_CancelRequestAutocomplete::ID
));
353 TEST_F(RequestAutocompleteRendererTest
, NoCancelOnMainFrameNavigateAfterDone
) {
354 // Pretend that the dialog was cancelled.
355 SimulateRequestAutocompleteResult(
356 WebFormElement::AutocompleteResultErrorCancel
,
357 base::ASCIIToUTF16("Print me to the console"));
359 // Additional navigations should not crash nor send cancels.
360 NavigateFrame(GetMainFrame());
361 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
362 AutofillHostMsg_CancelRequestAutocomplete::ID
));
365 TEST_F(RequestAutocompleteRendererTest
, InvokingTwiceOnlyShowsOnce
) {
366 // Attempting to show the requestAutocomplete dialog again should be ignored.
367 static_cast<blink::WebAutofillClient
*>(autofill_agent_
)
368 ->didRequestAutocomplete(invoking_form());
369 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
370 AutofillHostMsg_RequestAutocomplete::ID
));
373 } // namespace autofill