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.
4 
5 #include <tuple>
6 
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h"
11 #include "build/build_config.h"
12 #include "chrome/test/base/chrome_render_view_test.h"
13 #include "components/autofill/content/renderer/autofill_agent.h"
14 #include "components/autofill/content/renderer/focus_test_utils.h"
15 #include "components/autofill/core/common/form_data.h"
16 #include "content/public/renderer/render_frame.h"
17 #include "content/public/renderer/render_view.h"
18 #include "mojo/public/cpp/bindings/associated_receiver_set.h"
19 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
22 #include "third_party/blink/public/web/web_document.h"
23 #include "third_party/blink/public/web/web_element.h"
24 #include "third_party/blink/public/web/web_form_element.h"
25 #include "third_party/blink/public/web/web_input_element.h"
26 #include "third_party/blink/public/web/web_local_frame.h"
27 
28 using blink::WebDocument;
29 using blink::WebElement;
30 using blink::WebInputElement;
31 using blink::WebString;
32 
33 namespace autofill {
34 
35 using mojom::SubmissionSource;
36 
37 namespace {
38 
39 class FakeContentAutofillDriver : public mojom::AutofillDriver {
40  public:
FakeContentAutofillDriver()41   FakeContentAutofillDriver() : did_unfocus_form_(false) {}
42 
~FakeContentAutofillDriver()43   ~FakeContentAutofillDriver() override {}
44 
BindReceiver(mojo::PendingAssociatedReceiver<mojom::AutofillDriver> receiver)45   void BindReceiver(
46       mojo::PendingAssociatedReceiver<mojom::AutofillDriver> receiver) {
47     receivers_.Add(this, std::move(receiver));
48   }
49 
did_unfocus_form() const50   bool did_unfocus_form() const { return did_unfocus_form_; }
51 
form_submitted() const52   const FormData* form_submitted() const { return form_submitted_.get(); }
53 
known_success() const54   bool known_success() const { return known_success_; }
55 
submission_source() const56   SubmissionSource submission_source() const { return submission_source_; }
57 
select_control_changed() const58   const FormFieldData* select_control_changed() const {
59     return select_control_changed_.get();
60   }
61 
62  private:
63   // mojom::AutofillDriver:
FormsSeen(const std::vector<FormData> & forms,base::TimeTicks timestamp)64   void FormsSeen(const std::vector<FormData>& forms,
65                  base::TimeTicks timestamp) override {}
66 
FormSubmitted(const FormData & form,bool known_success,SubmissionSource source)67   void FormSubmitted(const FormData& form,
68                      bool known_success,
69                      SubmissionSource source) override {
70     form_submitted_.reset(new FormData(form));
71     known_success_ = known_success;
72     submission_source_ = source;
73   }
74 
TextFieldDidChange(const FormData & form,const FormFieldData & field,const gfx::RectF & bounding_box,base::TimeTicks timestamp)75   void TextFieldDidChange(const FormData& form,
76                           const FormFieldData& field,
77                           const gfx::RectF& bounding_box,
78                           base::TimeTicks timestamp) override {}
79 
TextFieldDidScroll(const FormData & form,const FormFieldData & field,const gfx::RectF & bounding_box)80   void TextFieldDidScroll(const FormData& form,
81                           const FormFieldData& field,
82                           const gfx::RectF& bounding_box) override {}
83 
SelectControlDidChange(const FormData & form,const FormFieldData & field,const gfx::RectF & bounding_box)84   void SelectControlDidChange(const FormData& form,
85                               const FormFieldData& field,
86                               const gfx::RectF& bounding_box) override {
87     select_control_changed_ = std::make_unique<FormFieldData>(field);
88   }
89 
QueryFormFieldAutofill(int32_t id,const FormData & form,const FormFieldData & field,const gfx::RectF & bounding_box,bool autoselect_first_field)90   void QueryFormFieldAutofill(int32_t id,
91                               const FormData& form,
92                               const FormFieldData& field,
93                               const gfx::RectF& bounding_box,
94                               bool autoselect_first_field) override {}
95 
HidePopup()96   void HidePopup() override {}
97 
FocusNoLongerOnForm()98   void FocusNoLongerOnForm() override { did_unfocus_form_ = true; }
99 
FocusOnFormField(const FormData & form,const FormFieldData & field,const gfx::RectF & bounding_box)100   void FocusOnFormField(const FormData& form,
101                         const FormFieldData& field,
102                         const gfx::RectF& bounding_box) override {}
103 
DidFillAutofillFormData(const FormData & form,base::TimeTicks timestamp)104   void DidFillAutofillFormData(const FormData& form,
105                                base::TimeTicks timestamp) override {}
106 
DidPreviewAutofillFormData()107   void DidPreviewAutofillFormData() override {}
108 
DidEndTextFieldEditing()109   void DidEndTextFieldEditing() override {}
110 
SetDataList(const std::vector<base::string16> & values,const std::vector<base::string16> & labels)111   void SetDataList(const std::vector<base::string16>& values,
112                    const std::vector<base::string16>& labels) override {}
113 
SelectFieldOptionsDidChange(const autofill::FormData & form)114   void SelectFieldOptionsDidChange(const autofill::FormData& form) override {}
115 
116   // Records whether FocusNoLongerOnForm() get called.
117   bool did_unfocus_form_;
118 
119   // Records the form data received via FormSubmitted() call.
120   std::unique_ptr<FormData> form_submitted_;
121 
122   bool known_success_;
123 
124   SubmissionSource submission_source_;
125 
126   std::unique_ptr<FormFieldData> select_control_changed_;
127 
128   mojo::AssociatedReceiverSet<mojom::AutofillDriver> receivers_;
129 };
130 
131 // Helper function to verify the form-related messages received from the
132 // renderer. The same data is expected in both messages. Depending on
133 // |expect_submitted_message|, will verify presence of FormSubmitted message.
VerifyReceivedRendererMessages(const FakeContentAutofillDriver & fake_driver,const std::string & fname,const std::string & lname,bool expect_known_success,SubmissionSource expect_submission_source)134 void VerifyReceivedRendererMessages(
135     const FakeContentAutofillDriver& fake_driver,
136     const std::string& fname,
137     const std::string& lname,
138     bool expect_known_success,
139     SubmissionSource expect_submission_source) {
140   ASSERT_TRUE(fake_driver.form_submitted());
141 
142   // The tuple also includes a timestamp, which is ignored.
143   const FormData& submitted_form = *(fake_driver.form_submitted());
144   ASSERT_LE(2U, submitted_form.fields.size());
145   EXPECT_EQ(base::ASCIIToUTF16("fname"), submitted_form.fields[0].name);
146   EXPECT_EQ(base::UTF8ToUTF16(fname), submitted_form.fields[0].value);
147   EXPECT_EQ(base::ASCIIToUTF16("lname"), submitted_form.fields[1].name);
148   EXPECT_EQ(expect_known_success, fake_driver.known_success());
149   EXPECT_EQ(expect_submission_source,
150             mojo::ConvertTo<SubmissionSource>(fake_driver.submission_source()));
151 }
152 
VerifyReceivedAddressRendererMessages(const FakeContentAutofillDriver & fake_driver,const std::string & address,bool expect_known_success,SubmissionSource expect_submission_source)153 void VerifyReceivedAddressRendererMessages(
154     const FakeContentAutofillDriver& fake_driver,
155     const std::string& address,
156     bool expect_known_success,
157     SubmissionSource expect_submission_source) {
158   ASSERT_TRUE(fake_driver.form_submitted());
159 
160   // The tuple also includes a timestamp, which is ignored.
161   const FormData& submitted_form = *(fake_driver.form_submitted());
162   ASSERT_LE(1U, submitted_form.fields.size());
163   EXPECT_EQ(base::ASCIIToUTF16("address"), submitted_form.fields[0].name);
164   EXPECT_EQ(base::UTF8ToUTF16(address), submitted_form.fields[0].value);
165   EXPECT_EQ(expect_known_success, fake_driver.known_success());
166   EXPECT_EQ(expect_submission_source,
167             mojo::ConvertTo<SubmissionSource>(fake_driver.submission_source()));
168 }
169 
170 // Helper function to verify that NO form-related messages are received from the
171 // renderer.
VerifyNoSubmitMessagesReceived(const FakeContentAutofillDriver & fake_driver)172 void VerifyNoSubmitMessagesReceived(
173     const FakeContentAutofillDriver& fake_driver) {
174   // No submission messages sent.
175   EXPECT_EQ(nullptr, fake_driver.form_submitted());
176 }
177 
178 // Simulates receiving a message from the browser to fill a form.
SimulateOnFillForm(autofill::AutofillAgent * autofill_agent,blink::WebLocalFrame * main_frame)179 void SimulateOnFillForm(autofill::AutofillAgent* autofill_agent,
180                         blink::WebLocalFrame* main_frame) {
181   FormData data;
182   data.name = base::ASCIIToUTF16("name");
183   data.url = GURL("http://example.com/");
184   data.action = GURL("http://example.com/blade.php");
185   data.is_form_tag = true;  // Default value.
186 
187   FormFieldData field_data;
188   field_data.name = base::ASCIIToUTF16("fname");
189   field_data.value = base::ASCIIToUTF16("John");
190   field_data.is_autofilled = true;
191   data.fields.push_back(field_data);
192 
193   field_data.name = base::ASCIIToUTF16("lname");
194   field_data.value = base::ASCIIToUTF16("Smith");
195   field_data.is_autofilled = true;
196   data.fields.push_back(field_data);
197 
198   WebDocument document = main_frame->GetDocument();
199   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
200   ASSERT_FALSE(element.IsNull());
201 
202   // This call is necessary to setup the autofill agent appropriate for the
203   // user selection; simulates the menu actually popping up.
204   autofill_agent->FormControlElementClicked(element.To<WebInputElement>(),
205                                             false);
206 
207   autofill_agent->FillForm(0, data);
208 }
209 
210 // Simulates receiving a message from the browser to fill a form with an
211 // additional non-autofillable field.
SimulateOnFillFormWithNonFillableFields(autofill::AutofillAgent * autofill_agent,blink::WebLocalFrame * main_frame)212 void SimulateOnFillFormWithNonFillableFields(
213     autofill::AutofillAgent* autofill_agent,
214     blink::WebLocalFrame* main_frame) {
215   FormData data;
216   data.name = base::ASCIIToUTF16("name");
217   data.url = GURL("http://example.com/");
218   data.action = GURL("http://example.com/blade.php");
219   data.is_form_tag = true;  // Default value.
220 
221   FormFieldData field_data;
222   field_data.name = base::ASCIIToUTF16("fname");
223   field_data.value = base::ASCIIToUTF16("John");
224   field_data.is_autofilled = true;
225   data.fields.push_back(field_data);
226 
227   field_data.name = base::ASCIIToUTF16("lname");
228   field_data.value = base::ASCIIToUTF16("Smith");
229   field_data.is_autofilled = true;
230   data.fields.push_back(field_data);
231 
232   // Additional non-autofillable field.
233   field_data.name = base::ASCIIToUTF16("mname");
234   field_data.value = base::ASCIIToUTF16("James");
235   field_data.is_autofilled = false;
236   data.fields.push_back(field_data);
237 
238   WebDocument document = main_frame->GetDocument();
239   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
240   ASSERT_FALSE(element.IsNull());
241 
242   // This call is necessary to setup the autofill agent appropriate for the
243   // user selection; simulates the menu actually popping up.
244   autofill_agent->FormControlElementClicked(element.To<WebInputElement>(),
245                                             false);
246 
247   autofill_agent->FillForm(0, data);
248 }
249 
250 }  // end namespace
251 
252 class FormAutocompleteTest : public ChromeRenderViewTest {
253  public:
FormAutocompleteTest()254   FormAutocompleteTest() {}
~FormAutocompleteTest()255   ~FormAutocompleteTest() override {}
256 
257  protected:
SetUp()258   void SetUp() override {
259     ChromeRenderViewTest::SetUp();
260 
261     // We only use the fake driver for main frame
262     // because our test cases only involve the main frame.
263     blink::AssociatedInterfaceProvider* remote_interfaces =
264         view_->GetMainRenderFrame()->GetRemoteAssociatedInterfaces();
265     remote_interfaces->OverrideBinderForTesting(
266         mojom::AutofillDriver::Name_,
267         base::BindRepeating(&FormAutocompleteTest::BindAutofillDriver,
268                             base::Unretained(this)));
269 
270     focus_test_utils_ = std::make_unique<test::FocusTestUtils>(
271         base::BindRepeating(&FormAutocompleteTest::ExecuteJavaScriptForTests,
272                             base::Unretained(this)));
273   }
274 
BindAutofillDriver(mojo::ScopedInterfaceEndpointHandle handle)275   void BindAutofillDriver(mojo::ScopedInterfaceEndpointHandle handle) {
276     fake_driver_.BindReceiver(
277         mojo::PendingAssociatedReceiver<mojom::AutofillDriver>(
278             std::move(handle)));
279   }
280 
SimulateUserInput(const blink::WebString & id,const std::string & value)281   void SimulateUserInput(const blink::WebString& id, const std::string& value) {
282     WebDocument document = GetMainFrame()->GetDocument();
283     WebElement element = document.GetElementById(id);
284     ASSERT_FALSE(element.IsNull());
285     WebInputElement fname_element = element.To<WebInputElement>();
286     SimulateUserInputChangeForElement(&fname_element, value);
287   }
288 
GetFocusLog()289   std::string GetFocusLog() {
290     return focus_test_utils_->GetFocusLog(GetMainFrame()->GetDocument());
291   }
292 
293   FakeContentAutofillDriver fake_driver_;
294   std::unique_ptr<test::FocusTestUtils> focus_test_utils_;
295 
296  private:
297   DISALLOW_COPY_AND_ASSIGN(FormAutocompleteTest);
298 };
299 
300 // Tests that submitting a form generates FormSubmitted message with the form
301 // fields.
TEST_F(FormAutocompleteTest,NormalFormSubmit)302 TEST_F(FormAutocompleteTest, NormalFormSubmit) {
303   // Load a form.
304   LoadHTML(
305       "<html><form id='myForm' action='about:blank'>"
306       "<input name='fname' value='Rick'/>"
307       "<input name='lname' value='Deckard'/></form></html>");
308 
309   // Submit the form.
310   ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
311   base::RunLoop().RunUntilIdle();
312 
313   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
314                                  false /* expect_known_success */,
315                                  SubmissionSource::FORM_SUBMISSION);
316 }
317 
318 // Tests that FormSubmitted message is generated even the submit event isn't
319 // propagated by Javascript.
TEST_F(FormAutocompleteTest,SubmitEventPrevented)320 TEST_F(FormAutocompleteTest, SubmitEventPrevented) {
321   // Load a form.
322   LoadHTML(
323       "<html><form id='myForm'><input name='fname' value='Rick'/>"
324       "<input name='lname' value='Deckard'/><input type=submit></form>"
325       "</html>");
326 
327   // Submit the form.
328   ExecuteJavaScriptForTests(
329       "var form = document.forms[0];"
330       "form.onsubmit = function(event) { event.preventDefault(); };"
331       "document.querySelector('input[type=submit]').click();");
332   base::RunLoop().RunUntilIdle();
333 
334   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
335                                  false /* expect_known_success */,
336                                  SubmissionSource::FORM_SUBMISSION);
337 }
338 
339 // Tests that completing an Ajax request and having the form disappear will
340 // trigger submission from Autofill's point of view.
TEST_F(FormAutocompleteTest,AjaxSucceeded_NoLongerVisible)341 TEST_F(FormAutocompleteTest, AjaxSucceeded_NoLongerVisible) {
342   // Load a form.
343   LoadHTML(
344       "<html><form id='myForm' action='http://example.com/blade.php'>"
345       "<input name='fname' id='fname' value='Bob'/>"
346       "<input name='lname' value='Deckard'/><input type=submit></form></html>");
347 
348   // Simulate user input so that the form is "remembered".
349   WebDocument document = GetMainFrame()->GetDocument();
350   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
351   ASSERT_FALSE(element.IsNull());
352   WebInputElement fname_element = element.To<WebInputElement>();
353   SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
354 
355   // Simulate removing the form just before the ajax request completes.
356   ExecuteJavaScriptForTests(
357       "var element = document.getElementById('myForm');"
358       "element.parentNode.removeChild(element);");
359 
360   // Simulate an Ajax request completing.
361   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
362   base::RunLoop().RunUntilIdle();
363 
364   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
365                                  true /* expect_known_success */,
366                                  SubmissionSource::XHR_SUCCEEDED);
367 }
368 
369 // Tests that completing an Ajax request and having the form with a specific
370 // action disappear will trigger submission from Autofill's point of view, even
371 // if there is another form with the same data but different action on the page.
TEST_F(FormAutocompleteTest,AjaxSucceeded_NoLongerVisible_DifferentActionsSameData)372 TEST_F(FormAutocompleteTest,
373        AjaxSucceeded_NoLongerVisible_DifferentActionsSameData) {
374   // Load a form.
375   LoadHTML(
376       "<html><form id='myForm' action='http://example.com/blade.php'>"
377       "<input name='fname' id='fname' value='Bob'/>"
378       "<input name='lname' value='Deckard'/><input type=submit></form>"
379       "<form id='myForm2' action='http://example.com/runner.php'>"
380       "<input name='fname' id='fname2' value='Bob'/>"
381       "<input name='lname' value='Deckard'/><input type=submit></form></html>");
382 
383   // Simulate user input so that the form is "remembered".
384   WebDocument document = GetMainFrame()->GetDocument();
385   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
386   ASSERT_FALSE(element.IsNull());
387   WebInputElement fname_element = element.To<WebInputElement>();
388   SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
389 
390   // Simulate removing the form just before the ajax request completes.
391   ExecuteJavaScriptForTests(
392       "var element = document.getElementById('myForm');"
393       "element.parentNode.removeChild(element);");
394 
395   // Simulate an Ajax request completing.
396   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
397   base::RunLoop().RunUntilIdle();
398 
399   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
400                                  true /* expect_known_success */,
401                                  SubmissionSource::XHR_SUCCEEDED);
402 }
403 
404 // Tests that completing an Ajax request and having the form with no action
405 // specified disappear will trigger submission from Autofill's point of view,
406 // even if there is still another form with no action in the page. It will
407 // compare field data within the forms.
408 // TODO(kolos) Re-enable when the implementation of IsFormVisible is on-par
409 // for these platforms.
410 #if defined(OS_MACOSX)
411 #define MAYBE_NoLongerVisibleBothNoActions DISABLED_NoLongerVisibleBothNoActions
412 #else
413 #define MAYBE_NoLongerVisibleBothNoActions NoLongerVisibleBothNoActions
414 #endif
TEST_F(FormAutocompleteTest,MAYBE_NoLongerVisibleBothNoActions)415 TEST_F(FormAutocompleteTest, MAYBE_NoLongerVisibleBothNoActions) {
416   // Load a form.
417   LoadHTML(
418       "<html><form id='myForm'>"
419       "<input name='fname' id='fname' value='Bob'/>"
420       "<input name='lname' value='Deckard'/><input type=submit></form>"
421       "<form id='myForm2'>"
422       "<input name='fname' id='fname2' value='John'/>"
423       "<input name='lname' value='Doe'/><input type=submit></form></html>");
424 
425   // Simulate user input so that the form is "remembered".
426   WebDocument document = GetMainFrame()->GetDocument();
427   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
428   ASSERT_FALSE(element.IsNull());
429   WebInputElement fname_element = element.To<WebInputElement>();
430   SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
431 
432   // Simulate removing the form just before the ajax request completes.
433   ExecuteJavaScriptForTests(
434       "var element = document.getElementById('myForm');"
435       "element.parentNode.removeChild(element);");
436 
437   // Simulate an Ajax request completing.
438   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
439   base::RunLoop().RunUntilIdle();
440 
441   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
442                                  true /* expect_known_success */,
443                                  SubmissionSource::XHR_SUCCEEDED);
444 }
445 
446 // Tests that completing an Ajax request and having the form with no action
447 // specified disappear will trigger submission from Autofill's point of view.
TEST_F(FormAutocompleteTest,AjaxSucceeded_NoLongerVisible_NoAction)448 TEST_F(FormAutocompleteTest, AjaxSucceeded_NoLongerVisible_NoAction) {
449   // Load a form.
450   LoadHTML(
451       "<html><form id='myForm'>"
452       "<input name='fname' id='fname' value='Bob'/>"
453       "<input name='lname' value='Deckard'/><input type=submit></form></html>");
454 
455   // Simulate user input so that the form is "remembered".
456   WebDocument document = GetMainFrame()->GetDocument();
457   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
458   ASSERT_FALSE(element.IsNull());
459   WebInputElement fname_element = element.To<WebInputElement>();
460   SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
461 
462   // Simulate removing the form just before the ajax request completes.
463   ExecuteJavaScriptForTests(
464       "var element = document.getElementById('myForm');"
465       "element.parentNode.removeChild(element);");
466 
467   // Simulate an Ajax request completing.
468   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
469   base::RunLoop().RunUntilIdle();
470 
471   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
472                                  true /* expect_known_success */,
473                                  SubmissionSource::XHR_SUCCEEDED);
474 }
475 
476 // Tests that completing an Ajax request but leaving a form visible will not
477 // trigger submission from Autofill's point of view.
TEST_F(FormAutocompleteTest,AjaxSucceeded_StillVisible)478 TEST_F(FormAutocompleteTest, AjaxSucceeded_StillVisible) {
479   // Load a form.
480   LoadHTML(
481       "<html><form id='myForm' action='http://example.com/blade.php'>"
482       "<input name='fname' id='fname' value='Bob'/>"
483       "<input name='lname' value='Deckard'/><input type=submit></form></html>");
484 
485   // Simulate user input so that the form is "remembered".
486   WebDocument document = GetMainFrame()->GetDocument();
487   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
488   ASSERT_FALSE(element.IsNull());
489   WebInputElement fname_element = element.To<WebInputElement>();
490   SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
491 
492   // Simulate an Ajax request completing.
493   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
494   base::RunLoop().RunUntilIdle();
495 
496   // No submission messages sent.
497   VerifyNoSubmitMessagesReceived(fake_driver_);
498 }
499 
500 // Tests that completing an Ajax request without any prior form interaction
501 // does not trigger form submission from Autofill's point of view.
TEST_F(FormAutocompleteTest,AjaxSucceeded_NoFormInteractionInvisible)502 TEST_F(FormAutocompleteTest, AjaxSucceeded_NoFormInteractionInvisible) {
503   // Load a form.
504   LoadHTML(
505       "<html><form id='myForm' action='http://example.com/blade.php'>"
506       "<input name='fname' id='fname' value='Bob'/>"
507       "<input name='lname' value='Deckard'/><input type=submit></form></html>");
508 
509   // No form interaction.
510 
511   // Simulate removing the form just before the ajax request completes.
512   ExecuteJavaScriptForTests(
513       "var element = document.getElementById('myForm');"
514       "element.parentNode.removeChild(element);");
515 
516   // Simulate an Ajax request completing without prior user interaction.
517   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
518   base::RunLoop().RunUntilIdle();
519 
520   // No submission messages sent.
521   VerifyNoSubmitMessagesReceived(fake_driver_);
522 }
523 
524 // Tests that completing an Ajax request after having autofilled a form,
525 // with the form disappearing, will trigger submission from Autofill's
526 // point of view.
TEST_F(FormAutocompleteTest,AjaxSucceeded_FilledFormIsInvisible)527 TEST_F(FormAutocompleteTest, AjaxSucceeded_FilledFormIsInvisible) {
528   // Load a form.
529   LoadHTML(
530       "<html><form id='myForm' action='http://example.com/blade.php'>"
531       "<input name='fname' id='fname'/>"
532       "<input name='lname'/></form></html>");
533 
534   // Simulate filling a form using Autofill.
535   SimulateOnFillForm(autofill_agent_, GetMainFrame());
536 
537   // Simulate user input since ajax request doesn't fire submission message
538   // if there is no user input.
539   SimulateUserInput(WebString::FromUTF8("fname"), std::string("Rick"));
540 
541   // Simulate removing the form just before the ajax request completes.
542   ExecuteJavaScriptForTests(
543       "var element = document.getElementById('myForm');"
544       "element.parentNode.removeChild(element);");
545 
546   // Simulate an Ajax request completing.
547   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
548   base::RunLoop().RunUntilIdle();
549 
550   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Smith",
551                                  true /* expect_known_success */,
552                                  SubmissionSource::XHR_SUCCEEDED);
553 }
554 
555 // Tests that completing an Ajax request after having autofilled a form,
556 // without the form disappearing, will not trigger submission from Autofill's
557 // point of view.
TEST_F(FormAutocompleteTest,AjaxSucceeded_FilledFormStillVisible)558 TEST_F(FormAutocompleteTest, AjaxSucceeded_FilledFormStillVisible) {
559   // Load a form.
560   LoadHTML(
561       "<html><form id='myForm' action='http://example.com/blade.php'>"
562       "<input name='fname' id='fname' value='Rick'/>"
563       "<input name='lname' value='Deckard'/></form></html>");
564 
565   // Simulate filling a form using Autofill.
566   SimulateOnFillForm(autofill_agent_, GetMainFrame());
567 
568   // Form still visible.
569 
570   // Simulate an Ajax request completing.
571   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
572   base::RunLoop().RunUntilIdle();
573 
574   // No submission messages sent.
575   VerifyNoSubmitMessagesReceived(fake_driver_);
576 }
577 
578 // Tests that correct focus, change and blur events are emitted during the
579 // autofilling process when there is an initial focused element in a form
580 // having non-fillable fields.
TEST_F(FormAutocompleteTest,VerifyFocusAndBlurEventsAfterAutofill)581 TEST_F(FormAutocompleteTest, VerifyFocusAndBlurEventsAfterAutofill) {
582   // Load a form.
583   LoadHTML(
584       "<html><form id='myForm'>"
585       "<label>First Name:</label><input id='fname' name='0'/><br/>"
586       "<label>Last Name:</label> <input id='lname' name='1'/><br/>"
587       "<label>Middle Name:</label><input id='mname' name='2'/><br/>"
588       "</form></html>");
589 
590   focus_test_utils_->SetUpFocusLogging();
591   focus_test_utils_->FocusElement("fname");
592 
593   // Simulate filling the form using Autofill.
594   SimulateOnFillFormWithNonFillableFields(autofill_agent_, GetMainFrame());
595   base::RunLoop().RunUntilIdle();
596 
597   // Expected Result in order:
598   // * Change fname
599   // * Blur fname
600   // * Focus lname
601   // * Change lname
602   // * Blur lname
603   // * Focus fname
604   EXPECT_EQ(GetFocusLog(), "c0b0f1c1b1f0");
605 }
606 
607 // Tests that correct focus, change and blur events are emitted during the
608 // autofilling process when there is an initial focused element.
TEST_F(FormAutocompleteTest,VerifyFocusAndBlurEventsAfterAutofillWithFocusedElement)609 TEST_F(FormAutocompleteTest,
610        VerifyFocusAndBlurEventsAfterAutofillWithFocusedElement) {
611   // Load a form.
612   LoadHTML(
613       "<html><form id='myForm'>"
614       "<label>First Name:</label><input id='fname' name='0'/><br/>"
615       "<label>Last Name:</label> <input id='lname' name='1'/><br/>"
616       "</form></html>");
617 
618   focus_test_utils_->SetUpFocusLogging();
619   focus_test_utils_->FocusElement("fname");
620 
621   // Simulate filling the form using Autofill.
622   SimulateOnFillForm(autofill_agent_, GetMainFrame());
623   base::RunLoop().RunUntilIdle();
624 
625   // Expected Result in order:
626   // * Change fname
627   // * Blur fname
628   // * Focus lname
629   // * Change lname
630   // * Blur lname
631   // * Focus fname
632   EXPECT_EQ(GetFocusLog(), "c0b0f1c1b1f0");
633 }
634 
635 // Tests that correct focus, change and blur events are emitted during the
636 // autofilling process when there is an initial focused element in a form having
637 // single field.
TEST_F(FormAutocompleteTest,VerifyFocusAndBlurEventAfterAutofillWithFocusedElementForSingleElement)638 TEST_F(FormAutocompleteTest,
639        VerifyFocusAndBlurEventAfterAutofillWithFocusedElementForSingleElement) {
640   // Load a form.
641   LoadHTML(
642       "<html><form id='myForm'>"
643       "<label>First Name:</label><input id='fname' name='0'/><br/>"
644       "</form></html>");
645 
646   focus_test_utils_->SetUpFocusLogging();
647   focus_test_utils_->FocusElement("fname");
648 
649   // Simulate filling the form using Autofill.
650   SimulateOnFillForm(autofill_agent_, GetMainFrame());
651   base::RunLoop().RunUntilIdle();
652 
653   EXPECT_EQ(GetFocusLog(), "");
654 }
655 
656 // Tests that completing an Ajax request without a form present will still
657 // trigger submission, if all the inputs the user has modified disappear.
TEST_F(FormAutocompleteTest,AjaxSucceeded_FormlessElements)658 TEST_F(FormAutocompleteTest, AjaxSucceeded_FormlessElements) {
659   // Load a "form." Note that kRequiredFieldsForUpload fields are required
660   // for the formless logic to trigger, so we add a throwaway third field.
661   LoadHTML(
662       "<head><title>Checkout</title></head>"
663       "<input type='text' name='fname' id='fname'/>"
664       "<input type='text' name='lname' value='Puckett'/>"
665       "<input type='number' name='number' value='34'/>");
666 
667   // Simulate user input.
668   WebDocument document = GetMainFrame()->GetDocument();
669   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
670   ASSERT_FALSE(element.IsNull());
671   WebInputElement fname_element = element.To<WebInputElement>();
672   SimulateUserInputChangeForElement(&fname_element, std::string("Kirby"));
673 
674   // Remove element from view.
675   ExecuteJavaScriptForTests(
676       "var element = document.getElementById('fname');"
677       "element.style.display = 'none';");
678 
679   // Simulate AJAX request.
680   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
681   base::RunLoop().RunUntilIdle();
682 
683   VerifyReceivedRendererMessages(fake_driver_, "Kirby", "Puckett",
684                                  true /* expect_known_success */,
685                                  SubmissionSource::XHR_SUCCEEDED);
686 }
687 
688 // Unit test for CollectFormlessElements.
TEST_F(FormAutocompleteTest,CollectFormlessElements)689 TEST_F(FormAutocompleteTest, CollectFormlessElements) {
690   LoadHTML(
691       "<html><title>Checkout</title></head>"
692       "<input type='text' name='text_input'/>"
693       "<input type='checkbox' name='check_input'/>"
694       "<input type='number' name='number_input'/>"
695       "<select name='select_input'/>"
696       "  <option value='option_1'></option>"
697       "  <option value='option_2'></option>"
698       "</select>"
699       "<form><input type='text' name='excluded'/></form>"
700       "</html>");
701 
702   FormData result;
703   autofill_agent_->CollectFormlessElements(&result);
704 
705   // Asserting size 4 also ensures that 'excluded' field inside <form> is not
706   // collected.
707   ASSERT_EQ(4U, result.fields.size());
708   EXPECT_EQ(base::ASCIIToUTF16("text_input"), result.fields[0].name);
709   EXPECT_EQ(base::ASCIIToUTF16("check_input"), result.fields[1].name);
710   EXPECT_EQ(base::ASCIIToUTF16("number_input"), result.fields[2].name);
711   EXPECT_EQ(base::ASCIIToUTF16("select_input"), result.fields[3].name);
712 }
713 
714 // Unit test for AutofillAgent::AcceptDataListSuggestion.
TEST_F(FormAutocompleteTest,AcceptDataListSuggestion)715 TEST_F(FormAutocompleteTest, AcceptDataListSuggestion) {
716   LoadHTML(
717       "<html>"
718       "<input id='empty' type='email' multiple />"
719       "<input id='multi_one' type='email' multiple value='one@example.com'/>"
720       "<input id='multi_two' type='email' multiple"
721       "  value='one@example.com,two@example.com'/>"
722       "<input id='multi_trailing' type='email' multiple"
723       "  value='one@example.com,two@example.com,'/>"
724       "<input id='not_multi' type='email'"
725       "  value='one@example.com,two@example.com,'/>"
726       "<input id='not_email' type='text' multiple"
727       "  value='one@example.com,two@example.com,'/>"
728       "</html>");
729   WebDocument document = GetMainFrame()->GetDocument();
730 
731   // Each case tests a different field value with the same suggestion.
732   const base::string16 kSuggestion =
733       base::ASCIIToUTF16("suggestion@example.com");
734   struct TestCase {
735     std::string id;
736     std::string expected;
737   } cases[] = {
738       // Empty text field; expect to populate with suggestion.
739       {"empty", "suggestion@example.com"},
740       // Single entry; expect to replace with suggestion.
741       {"multi_one", "suggestion@example.com"},
742       // Two comma-separated entries; expect to replace second with suggestion.
743       {"multi_two", "one@example.com,suggestion@example.com"},
744       // Two comma-separated entries with trailing comma; expect to append
745       // suggestion.
746       {"multi_trailing",
747        "one@example.com,two@example.com,suggestion@example.com"},
748       // Do not apply this logic for a non-multiple or non-email field.
749       {"not_multi", "suggestion@example.com"},
750       {"not_email", "suggestion@example.com"},
751   };
752 
753   for (const auto& c : cases) {
754     WebElement element = document.GetElementById(WebString::FromUTF8(c.id));
755     ASSERT_FALSE(element.IsNull());
756     WebInputElement* input_element = blink::ToWebInputElement(&element);
757     ASSERT_TRUE(input_element);
758     // Select this element in |autofill_agent_|.
759     autofill_agent_->FormControlElementClicked(element.To<WebInputElement>(),
760                                                false);
761 
762     autofill_agent_->AcceptDataListSuggestion(kSuggestion);
763     EXPECT_EQ(c.expected, input_element->Value().Utf8()) << "Case id: " << c.id;
764   }
765 }
766 
767 // Test that a FocusNoLongerOnForm message is sent if focus goes from an
768 // interacted form to an element outside the form.
TEST_F(FormAutocompleteTest,InteractedFormNoLongerFocused_FocusNoLongerOnForm)769 TEST_F(FormAutocompleteTest,
770        InteractedFormNoLongerFocused_FocusNoLongerOnForm) {
771   // Load a form.
772   LoadHTML(
773       "<html><input type='text' id='different'/>"
774       "<form id='myForm' action='http://example.com/blade.php'>"
775       "<input name='fname' id='fname' value='Bob'/>"
776       "<input name='lname' value='Deckard'/><input type=submit></form></html>");
777 
778   // Simulate user input so that the form is "remembered".
779   WebDocument document = GetMainFrame()->GetDocument();
780   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
781   ASSERT_FALSE(element.IsNull());
782   WebInputElement fname_element = element.To<WebInputElement>();
783   SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
784 
785   ASSERT_FALSE(fake_driver_.did_unfocus_form());
786 
787   // Change focus to a different node outside the form.
788   WebElement different =
789       document.GetElementById(WebString::FromUTF8("different"));
790   SetFocused(different);
791 
792   base::RunLoop run_loop;
793   run_loop.RunUntilIdle();
794 
795   EXPECT_TRUE(fake_driver_.did_unfocus_form());
796 }
797 
798 // Test that a FocusNoLongerOnForm message is sent if focus goes from one
799 // interacted form to another.
TEST_F(FormAutocompleteTest,InteractingInDifferentForms_FocusNoLongerOnForm)800 TEST_F(FormAutocompleteTest, InteractingInDifferentForms_FocusNoLongerOnForm) {
801   // Load a form.
802   LoadHTML(
803       "<html><form id='myForm' action='http://example.com/blade.php'>"
804       "<input name='fname' id='fname' value='Bob'/>"
805       "<input name='lname' value='Deckard'/><input type=submit></form>"
806       "<form id='myForm2' action='http://example.com/runner.php'>"
807       "<input name='fname' id='fname2' value='Bob'/>"
808       "<input name='lname' value='Deckard'/><input type=submit></form></html>");
809 
810   // Simulate user input in the first form so that the form is "remembered".
811   WebDocument document = GetMainFrame()->GetDocument();
812   WebElement element = document.GetElementById(WebString::FromUTF8("fname"));
813   ASSERT_FALSE(element.IsNull());
814   WebInputElement fname_element = element.To<WebInputElement>();
815   SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
816 
817   ASSERT_FALSE(fake_driver_.did_unfocus_form());
818 
819   // Simulate user input in the second form so that a "no longer focused"
820   // message is sent for the first form.
821   document = GetMainFrame()->GetDocument();
822   element = document.GetElementById(WebString::FromUTF8("fname2"));
823   ASSERT_FALSE(element.IsNull());
824   fname_element = element.To<WebInputElement>();
825   SimulateUserInputChangeForElement(&fname_element, std::string("John"));
826 
827   base::RunLoop run_loop;
828   run_loop.RunUntilIdle();
829 
830   EXPECT_TRUE(fake_driver_.did_unfocus_form());
831 }
832 
833 // Tests that submitting a form that has autocomplete="off" generates
834 // WillSubmitForm and FormSubmitted messages.
TEST_F(FormAutocompleteTest,AutoCompleteOffFormSubmit)835 TEST_F(FormAutocompleteTest, AutoCompleteOffFormSubmit) {
836   // Load a form.
837   LoadHTML(
838       "<html><form id='myForm' autocomplete='off' action='about:blank'>"
839       "<input name='fname' value='Rick'/>"
840       "<input name='lname' value='Deckard'/>"
841       "</form></html>");
842 
843   // Submit the form.
844   ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
845   base::RunLoop().RunUntilIdle();
846 
847   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
848                                  false /* expect_known_success */,
849                                  SubmissionSource::FORM_SUBMISSION);
850 }
851 
852 // Tests that fields with autocomplete off are submitted.
TEST_F(FormAutocompleteTest,AutoCompleteOffInputSubmit)853 TEST_F(FormAutocompleteTest, AutoCompleteOffInputSubmit) {
854   // Load a form.
855   LoadHTML(
856       "<html><form id='myForm' action='about:blank'>"
857       "<input name='fname' value='Rick'/>"
858       "<input name='lname' value='Deckard' autocomplete='off'/>"
859       "</form></html>");
860 
861   // Submit the form.
862   ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
863   base::RunLoop().RunUntilIdle();
864 
865   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
866                                  false /* expect_known_success */,
867                                  SubmissionSource::FORM_SUBMISSION);
868 }
869 
870 // Tests that submitting a form that has been dynamically set as autocomplete
871 // off generates WillSubmitForm and FormSubmitted messages.
872 // Note: We previously did the opposite, for bug http://crbug.com/36520
TEST_F(FormAutocompleteTest,DynamicAutoCompleteOffFormSubmit)873 TEST_F(FormAutocompleteTest, DynamicAutoCompleteOffFormSubmit) {
874   LoadHTML(
875       "<html><form id='myForm' action='about:blank'>"
876       "<input name='fname' value='Rick'/>"
877       "<input name='lname' value='Deckard'/></form></html>");
878 
879   WebElement element =
880       GetMainFrame()->GetDocument().GetElementById(blink::WebString("myForm"));
881   ASSERT_FALSE(element.IsNull());
882   blink::WebFormElement form = element.To<blink::WebFormElement>();
883   EXPECT_TRUE(form.AutoComplete());
884 
885   // Dynamically mark the form as autocomplete off.
886   ExecuteJavaScriptForTests(
887       "document.getElementById('myForm')."
888       "setAttribute('autocomplete', 'off');");
889   base::RunLoop().RunUntilIdle();
890   EXPECT_FALSE(form.AutoComplete());
891 
892   // Submit the form.
893   ExecuteJavaScriptForTests("document.getElementById('myForm').submit();");
894   base::RunLoop().RunUntilIdle();
895 
896   VerifyReceivedRendererMessages(fake_driver_, "Rick", "Deckard",
897                                  false /* expect_known_success */,
898                                  SubmissionSource::FORM_SUBMISSION);
899 }
900 
TEST_F(FormAutocompleteTest,FormSubmittedByDOMMutationAfterXHR)901 TEST_F(FormAutocompleteTest, FormSubmittedByDOMMutationAfterXHR) {
902   LoadHTML(
903       "<html>"
904       "<input type='text' id='address_field' name='address' autocomplete='on'>"
905       "</html>");
906 
907   SimulateUserInput(WebString::FromUTF8("address_field"), std::string("City"));
908 
909   // Simulate an Ajax request completing.
910   static_cast<blink::WebAutofillClient*>(autofill_agent_)->AjaxSucceeded();
911 
912   // Hide elements to simulate successful form submission.
913   std::string hide_elements =
914       "var address = document.getElementById('address_field');"
915       "address.style = 'display:none';";
916 
917   ExecuteJavaScriptForTests(hide_elements.c_str());
918   base::RunLoop().RunUntilIdle();
919 
920   VerifyReceivedAddressRendererMessages(
921       fake_driver_, "City", true /* expect_known_success */,
922       SubmissionSource::DOM_MUTATION_AFTER_XHR);
923 }
924 
TEST_F(FormAutocompleteTest,FormSubmittedBySameDocumentNavigation)925 TEST_F(FormAutocompleteTest, FormSubmittedBySameDocumentNavigation) {
926   LoadHTML(
927       "<html>"
928       "<input type='text' id='address_field' name='address' autocomplete='on'>"
929       "</html>");
930 
931   SimulateUserInput(WebString::FromUTF8("address_field"), std::string("City"));
932 
933   // Hide elements to simulate successful form submission.
934   std::string hide_elements =
935       "var address = document.getElementById('address_field');"
936       "address.style = 'display:none';";
937 
938   ExecuteJavaScriptForTests(hide_elements.c_str());
939 
940   // Simulate same document navigation.
941   autofill_agent_->form_tracker_for_testing()->DidCommitProvisionalLoad(
942       true /*is_same_document_navigation*/, ui::PAGE_TRANSITION_LINK);
943   base::RunLoop().RunUntilIdle();
944 
945   VerifyReceivedAddressRendererMessages(
946       fake_driver_, "City", true /* expect_known_success */,
947       SubmissionSource::SAME_DOCUMENT_NAVIGATION);
948 }
949 
TEST_F(FormAutocompleteTest,FormSubmittedByProbablyFormSubmitted)950 TEST_F(FormAutocompleteTest, FormSubmittedByProbablyFormSubmitted) {
951   LoadHTML(
952       "<html>"
953       "<input type='text' id='address_field' name='address' autocomplete='on'>"
954       "</html>");
955 
956   SimulateUserInput(WebString::FromUTF8("address_field"), std::string("City"));
957 
958   // Hide elements to simulate successful form submission.
959   std::string hide_elements =
960       "var address = document.getElementById('address_field');"
961       "address.style = 'display:none';";
962 
963   ExecuteJavaScriptForTests(hide_elements.c_str());
964 
965   // Simulate navigation.
966   autofill_agent_->form_tracker_for_testing()
967       ->FireProbablyFormSubmittedForTesting();
968 
969   base::RunLoop().RunUntilIdle();
970 
971   VerifyReceivedAddressRendererMessages(
972       fake_driver_, "City", false /* expect_known_success */,
973       SubmissionSource::PROBABLY_FORM_SUBMITTED);
974 }
975 
TEST_F(FormAutocompleteTest,SelectControlChanged)976 TEST_F(FormAutocompleteTest, SelectControlChanged) {
977   LoadHTML(
978       "<html>"
979       "<form>"
980       "<select id='color'><option value='red'>red</option><option "
981       "value='blue'>blue</option></select>"
982       "</form>"
983       "</html>");
984 
985   std::string change_value =
986       "var color = document.getElementById('color');"
987       "color.selectedIndex = 1;";
988 
989   ExecuteJavaScriptForTests(change_value.c_str());
990   WebElement element =
991       GetMainFrame()->GetDocument().GetElementById(blink::WebString("color"));
992   static_cast<blink::WebAutofillClient*>(autofill_agent_)
993       ->SelectControlDidChange(
994           *reinterpret_cast<blink::WebFormControlElement*>(&element));
995   base::RunLoop().RunUntilIdle();
996 
997   const FormFieldData* field = fake_driver_.select_control_changed();
998   ASSERT_TRUE(field);
999   EXPECT_EQ(base::ASCIIToUTF16("color"), field->name);
1000   EXPECT_EQ(base::ASCIIToUTF16("blue"), field->value);
1001 }
1002 
1003 }  // namespace autofill
1004