Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / chrome / renderer / autofill / form_autocomplete_browsertest.cc
blob9bd6e8912a4ce711299149f6084a5826f6555614
1 // Copyright (c) 2011 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/strings/utf_string_conversions.h"
6 #include "base/time/time.h"
7 #include "chrome/test/base/chrome_render_view_test.h"
8 #include "components/autofill/content/common/autofill_messages.h"
9 #include "components/autofill/content/renderer/autofill_agent.h"
10 #include "components/autofill/core/common/form_data.h"
11 #include "content/public/test/mock_render_thread.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/WebKit/public/web/WebDocument.h"
14 #include "third_party/WebKit/public/web/WebElement.h"
15 #include "third_party/WebKit/public/web/WebFormElement.h"
16 #include "third_party/WebKit/public/web/WebInputElement.h"
17 #include "third_party/WebKit/public/web/WebLocalFrame.h"
19 using blink::WebDocument;
20 using blink::WebElement;
21 using blink::WebInputElement;
22 using blink::WebString;
24 typedef ChromeRenderViewTest FormAutocompleteTest;
26 namespace autofill {
28 namespace {
30 // Helper function to verify the form-related messages received from the
31 // renderer. The same data is expected in both messages. Depending on
32 // |expect_submitted_message|, will verify presence of FormSubmitted message.
33 void VerifyReceivedRendererMessages(content::MockRenderThread* render_thread,
34 const std::string& fname,
35 const std::string& lname,
36 bool expect_submitted_message) {
37 const IPC::Message* will_submit_message =
38 render_thread->sink().GetFirstMessageMatching(
39 AutofillHostMsg_WillSubmitForm::ID);
40 const IPC::Message* submitted_message =
41 render_thread->sink().GetFirstMessageMatching(
42 AutofillHostMsg_FormSubmitted::ID);
43 ASSERT_TRUE(will_submit_message != NULL);
44 ASSERT_EQ(expect_submitted_message, submitted_message != NULL);
46 // The tuple also includes a timestamp, which is ignored.
47 base::Tuple<FormData, base::TimeTicks> will_submit_forms;
48 AutofillHostMsg_WillSubmitForm::Read(will_submit_message, &will_submit_forms);
49 ASSERT_EQ(2U, base::get<0>(will_submit_forms).fields.size());
51 FormFieldData& will_submit_form_field =
52 base::get<0>(will_submit_forms).fields[0];
53 EXPECT_EQ(WebString("fname"), will_submit_form_field.name);
54 EXPECT_EQ(WebString(base::UTF8ToUTF16(fname)), will_submit_form_field.value);
55 will_submit_form_field = base::get<0>(will_submit_forms).fields[1];
56 EXPECT_EQ(WebString("lname"), will_submit_form_field.name);
57 EXPECT_EQ(WebString(base::UTF8ToUTF16(lname)), will_submit_form_field.value);
59 if (expect_submitted_message) {
60 base::Tuple<FormData> submitted_forms;
61 AutofillHostMsg_FormSubmitted::Read(submitted_message, &submitted_forms);
62 ASSERT_EQ(2U, base::get<0>(submitted_forms).fields.size());
64 FormFieldData& submitted_field = base::get<0>(submitted_forms).fields[0];
65 EXPECT_EQ(WebString("fname"), submitted_field.name);
66 EXPECT_EQ(WebString(base::UTF8ToUTF16(fname)), submitted_field.value);
67 submitted_field = base::get<0>(submitted_forms).fields[1];
68 EXPECT_EQ(WebString("lname"), submitted_field.name);
69 EXPECT_EQ(WebString(base::UTF8ToUTF16(lname)), submitted_field.value);
73 // Helper function to verify that NO form-related messages are received from the
74 // renderer.
75 void VerifyNoSubmitMessagesReceived(content::MockRenderThread* render_thread) {
76 // No submission messages sent.
77 const IPC::Message* will_submit_message =
78 render_thread->sink().GetFirstMessageMatching(
79 AutofillHostMsg_WillSubmitForm::ID);
80 const IPC::Message* submitted_message =
81 render_thread->sink().GetFirstMessageMatching(
82 AutofillHostMsg_FormSubmitted::ID);
83 EXPECT_EQ(NULL, will_submit_message);
84 EXPECT_EQ(NULL, submitted_message);
87 // Simulates receiving a message from the browser to fill a form.
88 void SimulateOnFillForm(content::MockRenderThread* render_thread,
89 autofill::AutofillAgent* autofill_agent,
90 blink::WebFrame* main_frame) {
91 WebDocument document = main_frame->document();
92 WebElement element =
93 document.getElementById(WebString::fromUTF8("fname"));
94 ASSERT_FALSE(element.isNull());
96 // This call is necessary to setup the autofill agent appropriate for the
97 // user selection; simulates the menu actually popping up.
98 render_thread->sink().ClearMessages();
99 static_cast<autofill::PageClickListener*>(autofill_agent)
100 ->FormControlElementClicked(element.to<WebInputElement>(), false);
102 FormData data;
103 data.name = base::ASCIIToUTF16("name");
104 data.origin = GURL("origin");
105 data.action = GURL("blade.php");
106 data.is_form_tag = true; // Default value.
108 FormFieldData field_data;
109 field_data.name = base::ASCIIToUTF16("fname");
110 field_data.value = base::ASCIIToUTF16("John");
111 field_data.is_autofilled = true;
112 data.fields.push_back(field_data);
114 field_data.name = base::ASCIIToUTF16("lname");
115 field_data.value = base::ASCIIToUTF16("Smith");
116 field_data.is_autofilled = true;
117 data.fields.push_back(field_data);
119 AutofillMsg_FillForm msg(0, 0, data);
120 static_cast<content::RenderFrameObserver*>(autofill_agent)
121 ->OnMessageReceived(msg);
124 } // end namespace
126 // Tests that submitting a form generates WillSubmitForm and FormSubmitted
127 // messages with the form fields.
128 TEST_F(FormAutocompleteTest, NormalFormSubmit) {
129 // Load a form.
130 LoadHTML("<html><form id='myForm'><input name='fname' value='Rick'/>"
131 "<input name='lname' value='Deckard'/></form></html>");
133 // Submit the form.
134 ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
135 ProcessPendingMessages();
137 VerifyReceivedRendererMessages(render_thread_.get(), "Rick", "Deckard",
138 true /* expect_submitted_message */);
141 // Tests that submitting a form that prevents the submit event from propagating
142 // will only send the WillSubmitForm message.
143 TEST_F(FormAutocompleteTest, SubmitEventPrevented) {
144 // Load a form.
145 LoadHTML(
146 "<html><form id='myForm'><input name='fname' value='Rick'/>"
147 "<input name='lname' value='Deckard'/><input type=submit></form>"
148 "</html>");
150 // Submit the form.
151 ExecuteJavaScriptForTests(
152 "var form = document.forms[0];"
153 "form.onsubmit = function(event) { event.preventDefault(); };"
154 "document.querySelector('input[type=submit]').click();");
155 ProcessPendingMessages();
157 VerifyReceivedRendererMessages(render_thread_.get(), "Rick", "Deckard",
158 false /* expect_submitted_message */);
161 // Tests that completing an Ajax request and having the form disappear will
162 // trigger submission from Autofill's point of view.
163 TEST_F(FormAutocompleteTest, AjaxSucceeded_NoLongerVisible) {
164 // Load a form.
165 LoadHTML(
166 "<html><form id='myForm' action='blade.php'>"
167 "<input name='fname' id='fname' value='Bob'/>"
168 "<input name='lname' value='Deckard'/><input type=submit></form></html>");
170 // Simulate user input so that the form is "remembered".
171 WebDocument document = GetMainFrame()->document();
172 WebElement element =
173 document.getElementById(WebString::fromUTF8("fname"));
174 ASSERT_FALSE(element.isNull());
175 WebInputElement fname_element = element.to<WebInputElement>();
176 SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
178 // Simulate removing the form just before the ajax request completes.
179 ExecuteJavaScriptForTests("var element = document.getElementById('myForm');"
180 "element.parentNode.removeChild(element);");
182 // Simulate an Ajax request completing.
183 static_cast<blink::WebAutofillClient*>(autofill_agent_)->ajaxSucceeded();
184 ProcessPendingMessages();
186 VerifyReceivedRendererMessages(render_thread_.get(), "Rick", "Deckard",
187 true /* expect_submitted_message */);
190 // Tests that completing an Ajax request but leaving a form visible will not
191 // trigger submission from Autofill's point of view.
192 TEST_F(FormAutocompleteTest, AjaxSucceeded_StillVisible) {
193 // Load a form.
194 LoadHTML(
195 "<html><form id='myForm' action='blade.php'>"
196 "<input name='fname' id='fname' value='Bob'/>"
197 "<input name='lname' value='Deckard'/><input type=submit></form></html>");
199 // Simulate user input so that the form is "remembered".
200 WebDocument document = GetMainFrame()->document();
201 WebElement element =
202 document.getElementById(WebString::fromUTF8("fname"));
203 ASSERT_FALSE(element.isNull());
204 WebInputElement fname_element = element.to<WebInputElement>();
205 SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
207 // Simulate an Ajax request completing.
208 static_cast<blink::WebAutofillClient*>(autofill_agent_)->ajaxSucceeded();
209 ProcessPendingMessages();
211 // No submission messages sent.
212 VerifyNoSubmitMessagesReceived(render_thread_.get());
215 // Tests that completing an Ajax request without any prior form interaction
216 // does not trigger form submission from Autofill's point of view.
217 TEST_F(FormAutocompleteTest, AjaxSucceeded_NoFormInteractionInvisible) {
218 // Load a form.
219 LoadHTML(
220 "<html><form id='myForm' action='blade.php'>"
221 "<input name='fname' id='fname' value='Bob'/>"
222 "<input name='lname' value='Deckard'/><input type=submit></form></html>");
224 // No form interaction.
226 // Simulate removing the form just before the ajax request completes.
227 ExecuteJavaScriptForTests("var element = document.getElementById('myForm');"
228 "element.parentNode.removeChild(element);");
230 // Simulate an Ajax request completing without prior user interaction.
231 static_cast<blink::WebAutofillClient*>(autofill_agent_)->ajaxSucceeded();
232 ProcessPendingMessages();
234 // No submission messages sent.
235 VerifyNoSubmitMessagesReceived(render_thread_.get());
238 // Tests that completing an Ajax request after having autofilled a form,
239 // with the form disappearing, will trigger submission from Autofill's
240 // point of view.
241 TEST_F(FormAutocompleteTest, AjaxSucceeded_FilledFormIsInvisible) {
242 // Load a form.
243 LoadHTML(
244 "<html><form id='myForm' action='blade.php'>"
245 "<input name='fname' id='fname'/>"
246 "<input name='lname'/></form></html>");
248 // Simulate filling a form using Autofill.
249 SimulateOnFillForm(render_thread_.get(), autofill_agent_, GetMainFrame());
251 // Simulate removing the form just before the ajax request completes.
252 ExecuteJavaScriptForTests("var element = document.getElementById('myForm');"
253 "element.parentNode.removeChild(element);");
255 // Simulate an Ajax request completing.
256 static_cast<blink::WebAutofillClient*>(autofill_agent_)->ajaxSucceeded();
257 ProcessPendingMessages();
259 VerifyReceivedRendererMessages(render_thread_.get(), "John", "Smith",
260 true /* expect_submitted_message */);
263 // Tests that completing an Ajax request after having autofilled a form,
264 // without the form disappearing, will not trigger submission from Autofill's
265 // point of view.
266 TEST_F(FormAutocompleteTest, AjaxSucceeded_FilledFormStillVisible) {
267 // Load a form.
268 LoadHTML(
269 "<html><form id='myForm' action='blade.php'>"
270 "<input name='fname' id='fname' value='Rick'/>"
271 "<input name='lname' value='Deckard'/></form></html>");
273 // Simulate filling a form using Autofill.
274 SimulateOnFillForm(render_thread_.get(), autofill_agent_, GetMainFrame());
276 // Form still visible.
278 // Simulate an Ajax request completing.
279 static_cast<blink::WebAutofillClient*>(autofill_agent_)->ajaxSucceeded();
280 ProcessPendingMessages();
282 // No submission messages sent.
283 VerifyNoSubmitMessagesReceived(render_thread_.get());
286 // Tests that submitting a form that has autocomplete="off" generates
287 // WillSubmitForm and FormSubmitted messages.
288 TEST_F(FormAutocompleteTest, AutoCompleteOffFormSubmit) {
289 // Load a form.
290 LoadHTML("<html><form id='myForm' autocomplete='off'>"
291 "<input name='fname' value='Rick'/>"
292 "<input name='lname' value='Deckard'/>"
293 "</form></html>");
295 // Submit the form.
296 ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
297 ProcessPendingMessages();
299 VerifyReceivedRendererMessages(render_thread_.get(), "Rick", "Deckard",
300 true /* expect_submitted_message */);
303 // Tests that fields with autocomplete off are submitted.
304 TEST_F(FormAutocompleteTest, AutoCompleteOffInputSubmit) {
305 // Load a form.
306 LoadHTML("<html><form id='myForm'>"
307 "<input name='fname' value='Rick'/>"
308 "<input name='lname' value='Deckard' autocomplete='off'/>"
309 "</form></html>");
311 // Submit the form.
312 ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
313 ProcessPendingMessages();
315 VerifyReceivedRendererMessages(render_thread_.get(), "Rick", "Deckard",
316 true /* expect_submitted_message */);
319 // Tests that submitting a form that has been dynamically set as autocomplete
320 // off generates WillSubmitForm and FormSubmitted messages.
321 // Note: We previously did the opposite, for bug http://crbug.com/36520
322 TEST_F(FormAutocompleteTest, DynamicAutoCompleteOffFormSubmit) {
323 LoadHTML("<html><form id='myForm'><input name='fname' value='Rick'/>"
324 "<input name='lname' value='Deckard'/></form></html>");
326 WebElement element =
327 GetMainFrame()->document().getElementById(blink::WebString("myForm"));
328 ASSERT_FALSE(element.isNull());
329 blink::WebFormElement form = element.to<blink::WebFormElement>();
330 EXPECT_TRUE(form.autoComplete());
332 // Dynamically mark the form as autocomplete off.
333 ExecuteJavaScriptForTests(
334 "document.getElementById('myForm')."
335 "setAttribute('autocomplete', 'off');");
336 ProcessPendingMessages();
337 EXPECT_FALSE(form.autoComplete());
339 // Submit the form.
340 ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
341 ProcessPendingMessages();
343 VerifyReceivedRendererMessages(render_thread_.get(), "Rick", "Deckard",
344 true /* expect_submitted_message */);
347 } // namespace autofill