1 // Copyright 2019 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 "components/autofill/content/renderer/form_cache.h"
6 
7 #include "base/strings/utf_string_conversions.h"
8 #include "components/autofill/content/renderer/focus_test_utils.h"
9 #include "components/autofill/content/renderer/form_autofill_util.h"
10 #include "components/autofill/core/common/form_field_data.h"
11 #include "content/public/test/render_view_test.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/blink/public/web/web_document.h"
14 #include "third_party/blink/public/web/web_input_element.h"
15 #include "third_party/blink/public/web/web_local_frame.h"
16 #include "third_party/blink/public/web/web_select_element.h"
17 
18 using base::ASCIIToUTF16;
19 using blink::WebDocument;
20 using blink::WebElement;
21 using blink::WebInputElement;
22 using blink::WebSelectElement;
23 using blink::WebString;
24 
25 namespace autofill {
26 
GetFormByName(const std::vector<FormData> & forms,base::StringPiece name)27 const FormData* GetFormByName(const std::vector<FormData>& forms,
28                               base::StringPiece name) {
29   for (const FormData& form : forms) {
30     if (form.name == ASCIIToUTF16(name))
31       return &form;
32   }
33   return nullptr;
34 }
35 
36 class FormCacheBrowserTest : public content::RenderViewTest {
37  public:
FormCacheBrowserTest()38   FormCacheBrowserTest() {
39     focus_test_utils_ = std::make_unique<test::FocusTestUtils>(
40         base::BindRepeating(&FormCacheBrowserTest::ExecuteJavaScriptForTests,
41                             base::Unretained(this)));
42   }
43   ~FormCacheBrowserTest() override = default;
44   FormCacheBrowserTest(const FormCacheBrowserTest&) = delete;
45   FormCacheBrowserTest& operator=(const FormCacheBrowserTest&) = delete;
46 
47  protected:
GetFocusLog()48   std::string GetFocusLog() {
49     return focus_test_utils_->GetFocusLog(GetMainFrame()->GetDocument());
50   }
51 
52   std::unique_ptr<test::FocusTestUtils> focus_test_utils_;
53 };
54 
TEST_F(FormCacheBrowserTest,ExtractForms)55 TEST_F(FormCacheBrowserTest, ExtractForms) {
56   LoadHTML(R"(
57     <form id="form1">
58       <input type="text" name="foo1">
59       <input type="text" name="foo2">
60       <input type="text" name="foo3">
61     </form>
62     <input type="text" name="unowned_element">
63   )");
64 
65   FormCache form_cache(GetMainFrame());
66   std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
67 
68   const FormData* form1 = GetFormByName(forms, "form1");
69   ASSERT_TRUE(form1);
70   EXPECT_EQ(3u, form1->fields.size());
71 
72   const FormData* unowned_form = GetFormByName(forms, "");
73   ASSERT_TRUE(unowned_form);
74   EXPECT_EQ(1u, unowned_form->fields.size());
75 }
76 
TEST_F(FormCacheBrowserTest,ExtractFormsTwice)77 TEST_F(FormCacheBrowserTest, ExtractFormsTwice) {
78   LoadHTML(R"(
79     <form id="form1">
80       <input type="text" name="foo1">
81       <input type="text" name="foo2">
82       <input type="text" name="foo3">
83     </form>
84     <input type="text" name="unowned_element">
85   )");
86 
87   FormCache form_cache(GetMainFrame());
88   std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
89 
90   forms = form_cache.ExtractNewForms(nullptr);
91   // As nothing has changed, there are no new forms and |forms| should be empty.
92   EXPECT_TRUE(forms.empty());
93 }
94 
TEST_F(FormCacheBrowserTest,ExtractFormsAfterModification)95 TEST_F(FormCacheBrowserTest, ExtractFormsAfterModification) {
96   LoadHTML(R"(
97     <form id="form1">
98       <input type="text" name="foo1">
99       <input type="text" name="foo2">
100       <input type="text" name="foo3">
101     </form>
102     <input type="text" name="unowned_element">
103   )");
104 
105   FormCache form_cache(GetMainFrame());
106   std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
107 
108   // Append an input element to the form and to the list of unowned inputs.
109   ExecuteJavaScriptForTests(R"(
110     var new_input_1 = document.createElement("input");
111     new_input_1.setAttribute("type", "text");
112     new_input_1.setAttribute("name", "foo4");
113 
114     var form1 = document.getElementById("form1");
115     form1.appendChild(new_input_1);
116 
117     var new_input_2 = document.createElement("input");
118     new_input_2.setAttribute("type", "text");
119     new_input_2.setAttribute("name", "unowned_element_2");
120     document.body.appendChild(new_input_2);
121   )");
122 
123   forms = form_cache.ExtractNewForms(nullptr);
124 
125   const FormData* form1 = GetFormByName(forms, "form1");
126   ASSERT_TRUE(form1);
127   EXPECT_EQ(4u, form1->fields.size());
128 
129   const FormData* unowned_form = GetFormByName(forms, "");
130   ASSERT_TRUE(unowned_form);
131   EXPECT_EQ(2u, unowned_form->fields.size());
132 }
133 
TEST_F(FormCacheBrowserTest,FillAndClear)134 TEST_F(FormCacheBrowserTest, FillAndClear) {
135   LoadHTML(R"(
136     <input type="text" name="text" id="text">
137     <input type="checkbox" checked name="checkbox" id="checkbox">
138     <select name="select" id="select">
139       <option value="first">first</option>
140       <option value="second" selected>second</option>
141     </select>
142   )");
143 
144   FormCache form_cache(GetMainFrame());
145   std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
146 
147   ASSERT_EQ(1u, forms.size());
148   FormData values_to_fill = forms[0];
149   values_to_fill.fields[0].value = ASCIIToUTF16("test");
150   values_to_fill.fields[0].is_autofilled = true;
151   values_to_fill.fields[1].check_status =
152       FormFieldData::CheckStatus::kCheckableButUnchecked;
153   values_to_fill.fields[1].is_autofilled = true;
154   values_to_fill.fields[2].value = ASCIIToUTF16("first");
155   values_to_fill.fields[2].is_autofilled = true;
156 
157   WebDocument doc = GetMainFrame()->GetDocument();
158   auto text = doc.GetElementById("text").To<WebInputElement>();
159   auto checkbox = doc.GetElementById("checkbox").To<WebInputElement>();
160   auto select_element = doc.GetElementById("select").To<WebSelectElement>();
161 
162   form_util::FillForm(values_to_fill, text);
163 
164   EXPECT_EQ("test", text.Value().Ascii());
165   EXPECT_FALSE(checkbox.IsChecked());
166   EXPECT_EQ("first", select_element.Value().Ascii());
167 
168   // Validate that clearing works, in particular that the previous values
169   // were saved correctly.
170   form_cache.ClearSectionWithElement(text);
171 
172   EXPECT_EQ("", text.Value().Ascii());
173   EXPECT_TRUE(checkbox.IsChecked());
174   EXPECT_EQ("second", select_element.Value().Ascii());
175 }
176 
177 // Tests that correct focus, change and blur events are emitted during the
178 // autofilling and clearing of the form with an initially focused element.
TEST_F(FormCacheBrowserTest,VerifyFocusAndBlurEventsAfterAutofillAndClearingWithFocusElement)179 TEST_F(FormCacheBrowserTest,
180        VerifyFocusAndBlurEventsAfterAutofillAndClearingWithFocusElement) {
181   // Load a form.
182   LoadHTML(
183       "<html><form id='myForm'>"
184       "<label>First Name:</label><input id='fname' name='0'/><br/>"
185       "<label>Last Name:</label> <input id='lname' name='1'/><br/>"
186       "</form></html>");
187 
188   focus_test_utils_->SetUpFocusLogging();
189   focus_test_utils_->FocusElement("fname");
190 
191   FormCache form_cache(GetMainFrame());
192   std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
193 
194   ASSERT_EQ(2u, forms.size());
195   FormData values_to_fill = forms[0];
196   values_to_fill.fields[0].value = ASCIIToUTF16("John");
197   values_to_fill.fields[0].is_autofilled = true;
198   values_to_fill.fields[1].value = ASCIIToUTF16("Smith");
199   values_to_fill.fields[1].is_autofilled = true;
200 
201   auto fname = GetMainFrame()
202                    ->GetDocument()
203                    .GetElementById("fname")
204                    .To<WebInputElement>();
205 
206   // Simulate filling the form using Autofill.
207   form_util::FillForm(values_to_fill, fname);
208 
209   // Simulate clearing the form.
210   form_cache.ClearSectionWithElement(fname);
211 
212   // Expected Result in order:
213   // - from filling
214   //  * Change fname
215   //  * Blur fname
216   //  * Focus lname
217   //  * Change lname
218   //  * Blur lname
219   //  * Focus fname
220   // - from clearing
221   //  * Change fname
222   //  * Blur fname
223   //  * Focus lname
224   //  * Change lname
225   //  * Blur lname
226   //  * Focus fname
227   EXPECT_EQ(GetFocusLog(), "c0b0f1c1b1f0c0b0f1c1b1f0");
228 }
229 
TEST_F(FormCacheBrowserTest,FreeDataOnElementRemoval)230 TEST_F(FormCacheBrowserTest, FreeDataOnElementRemoval) {
231   LoadHTML(R"(
232     <div id="container">
233       <input type="text" name="text" id="text">
234       <input type="checkbox" checked name="checkbox" id="checkbox">
235       <select name="select" id="select">
236         <option value="first">first</option>
237         <option value="second" selected>second</option>
238       </select>
239     </div>
240   )");
241 
242   FormCache form_cache(GetMainFrame());
243   form_cache.ExtractNewForms(nullptr);
244 
245   EXPECT_EQ(1u, form_cache.initial_select_values_.size());
246   EXPECT_EQ(1u, form_cache.initial_checked_state_.size());
247 
248   ExecuteJavaScriptForTests(R"(
249     const container = document.getElementById('container');
250     while (container.childElementCount > 0) {
251       container.removeChild(container.children.item(0));
252     }
253   )");
254 
255   std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
256   EXPECT_EQ(0u, forms.size());
257   EXPECT_EQ(0u, form_cache.initial_select_values_.size());
258   EXPECT_EQ(0u, form_cache.initial_checked_state_.size());
259 }
260 
261 }  // namespace autofill
262