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. 4 5 #include "base/strings/utf_string_conversions.h" 6 #include "chrome/test/base/chrome_render_view_test.h" 7 #include "components/autofill/core/common/autofill_messages.h" 8 #include "components/autofill/core/common/form_data.h" 9 #include "components/autofill/core/common/form_field_data.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 #include "third_party/WebKit/public/platform/WebString.h" 12 #include "third_party/WebKit/public/web/WebDocument.h" 13 #include "third_party/WebKit/public/web/WebInputElement.h" 14 15 using WebKit::WebDocument; 16 using WebKit::WebFrame; 17 using WebKit::WebInputElement; 18 using WebKit::WebString; 19 20 namespace autofill { 21 22 typedef Tuple5<int, 23 autofill::FormData, 24 autofill::FormFieldData, 25 gfx::RectF, 26 bool> AutofillQueryParam; 27 28 TEST_F(ChromeRenderViewTest, SendForms) { 29 // Don't want any delay for form state sync changes. This will still post a 30 // message so updates will get coalesced, but as soon as we spin the message 31 // loop, it will generate an update. 32 SendContentStateImmediately(); 33 34 LoadHTML("<form method=\"POST\">" 35 " <input type=\"text\" id=\"firstname\"/>" 36 " <input type=\"text\" id=\"middlename\"/>" 37 " <input type=\"text\" id=\"lastname\" autoComplete=\"off\"/>" 38 " <input type=\"hidden\" id=\"email\"/>" 39 " <select id=\"state\"/>" 40 " <option>?</option>" 41 " <option>California</option>" 42 " <option>Texas</option>" 43 " </select>" 44 "</form>"); 45 46 // Verify that "FormsSeen" sends the expected number of fields. 47 const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching( 48 AutofillHostMsg_FormsSeen::ID); 49 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); 50 AutofillHostMsg_FormsSeen::Param params; 51 AutofillHostMsg_FormsSeen::Read(message, ¶ms); 52 const std::vector<FormData>& forms = params.a; 53 ASSERT_EQ(1UL, forms.size()); 54 ASSERT_EQ(4UL, forms[0].fields.size()); 55 56 FormFieldData expected; 57 58 expected.name = ASCIIToUTF16("firstname"); 59 expected.value = string16(); 60 expected.form_control_type = "text"; 61 expected.max_length = WebInputElement::defaultMaxLength(); 62 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[0]); 63 64 expected.name = ASCIIToUTF16("middlename"); 65 expected.value = string16(); 66 expected.form_control_type = "text"; 67 expected.max_length = WebInputElement::defaultMaxLength(); 68 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[1]); 69 70 expected.name = ASCIIToUTF16("lastname"); 71 expected.value = string16(); 72 expected.form_control_type = "text"; 73 expected.autocomplete_attribute = "off"; 74 expected.max_length = WebInputElement::defaultMaxLength(); 75 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[2]); 76 expected.autocomplete_attribute = std::string(); // reset 77 78 expected.name = ASCIIToUTF16("state"); 79 expected.value = ASCIIToUTF16("?"); 80 expected.form_control_type = "select-one"; 81 expected.max_length = 0; 82 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[3]); 83 84 // Verify that |didAcceptAutofillSuggestion()| sends the expected number of 85 // fields. 86 WebFrame* web_frame = GetMainFrame(); 87 WebDocument document = web_frame->document(); 88 WebInputElement firstname = 89 document.getElementById("firstname").to<WebInputElement>(); 90 91 // Make sure to query for Autofill suggestions before selecting one. 92 autofill_agent_->element_ = firstname; 93 autofill_agent_->QueryAutofillSuggestions(firstname, false); 94 95 // Fill the form with a suggestion that contained a label. Labeled items 96 // indicate Autofill as opposed to Autocomplete. We're testing this 97 // distinction below with the |AutofillHostMsg_FillAutofillFormData::ID| 98 // message. 99 autofill_agent_->FillAutofillFormData( 100 firstname, 101 1, 102 AutofillAgent::AUTOFILL_PREVIEW); 103 104 ProcessPendingMessages(); 105 const IPC::Message* message2 = 106 render_thread_->sink().GetUniqueMessageMatching( 107 AutofillHostMsg_FillAutofillFormData::ID); 108 ASSERT_NE(static_cast<IPC::Message*>(NULL), message2); 109 AutofillHostMsg_FillAutofillFormData::Param params2; 110 AutofillHostMsg_FillAutofillFormData::Read(message2, ¶ms2); 111 const FormData& form2 = params2.b; 112 ASSERT_EQ(3UL, form2.fields.size()); 113 114 expected.name = ASCIIToUTF16("firstname"); 115 expected.value = string16(); 116 expected.form_control_type = "text"; 117 expected.max_length = WebInputElement::defaultMaxLength(); 118 EXPECT_FORM_FIELD_DATA_EQUALS(expected, form2.fields[0]); 119 120 expected.name = ASCIIToUTF16("middlename"); 121 expected.value = string16(); 122 expected.form_control_type = "text"; 123 expected.max_length = WebInputElement::defaultMaxLength(); 124 EXPECT_FORM_FIELD_DATA_EQUALS(expected, form2.fields[1]); 125 126 expected.name = ASCIIToUTF16("state"); 127 expected.value = ASCIIToUTF16("?"); 128 expected.form_control_type = "select-one"; 129 expected.max_length = 0; 130 EXPECT_FORM_FIELD_DATA_EQUALS(expected, form2.fields[2]); 131 } 132 133 TEST_F(ChromeRenderViewTest, SendDynamicForms) { 134 // Don't want any delay for form state sync changes. This will still post a 135 // message so updates will get coalesced, but as soon as we spin the message 136 // loop, it will generate an update. 137 SendContentStateImmediately(); 138 139 LoadHTML("<form method=\"POST\" id=\"testform\">" 140 " <input type=\"text\" id=\"firstname\"/>" 141 " <input type=\"text\" id=\"middlename\"/>" 142 " <input type=\"text\" id=\"lastname\" autoComplete=\"off\"/>" 143 " <input type=\"hidden\" id=\"email\"/>" 144 " <select id=\"state\"/>" 145 " <option>?</option>" 146 " <option>California</option>" 147 " <option>Texas</option>" 148 " </select>" 149 "</form>"); 150 151 // Verify that "FormsSeen" sends the expected number of fields. 152 const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching( 153 AutofillHostMsg_FormsSeen::ID); 154 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); 155 AutofillHostMsg_FormsSeen::Param params; 156 AutofillHostMsg_FormsSeen::Read(message, ¶ms); 157 const std::vector<FormData>& forms = params.a; 158 ASSERT_EQ(1UL, forms.size()); 159 ASSERT_EQ(4UL, forms[0].fields.size()); 160 161 autofill_agent_->OnAutocheckoutSupported(); 162 render_thread_->sink().ClearMessages(); 163 ExecuteJavaScript("var newInput=document.createElement(\"input\");" 164 "newInput.setAttribute(\"type\",\"text\");" 165 "newInput.setAttribute(\"id\", \"telephone\");" 166 "document.getElementById(\"testform\")" 167 ".appendChild(newInput);"); 168 msg_loop_.RunUntilIdle(); 169 170 // Verify that FormsSeen is present with the new field. 171 const IPC::Message* message2 = render_thread_->sink().GetFirstMessageMatching( 172 AutofillHostMsg_FormsSeen::ID); 173 ASSERT_NE(static_cast<IPC::Message*>(NULL), message2); 174 AutofillHostMsg_FormsSeen::Read(message2, ¶ms); 175 const std::vector<FormData>& new_forms = params.a; 176 ASSERT_EQ(1UL, new_forms.size()); 177 ASSERT_EQ(5UL, new_forms[0].fields.size()); 178 179 FormFieldData expected; 180 181 expected.name = ASCIIToUTF16("telephone"); 182 expected.value = string16(); 183 expected.form_control_type = "text"; 184 expected.max_length = WebInputElement::defaultMaxLength(); 185 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[4]); 186 } 187 188 TEST_F(ChromeRenderViewTest, EnsureNoFormSeenIfTooFewFields) { 189 // Don't want any delay for form state sync changes. This will still post a 190 // message so updates will get coalesced, but as soon as we spin the message 191 // loop, it will generate an update. 192 SendContentStateImmediately(); 193 194 LoadHTML("<form method=\"POST\">" 195 " <input type=\"text\" id=\"firstname\"/>" 196 " <input type=\"text\" id=\"middlename\"/>" 197 "</form>"); 198 199 // Verify that "FormsSeen" isn't sent, as there are too few fields. 200 const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching( 201 AutofillHostMsg_FormsSeen::ID); 202 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); 203 AutofillHostMsg_FormsSeen::Param params; 204 AutofillHostMsg_FormsSeen::Read(message, ¶ms); 205 const std::vector<FormData>& forms = params.a; 206 ASSERT_EQ(0UL, forms.size()); 207 } 208 209 TEST_F(ChromeRenderViewTest, ShowAutofillWarning) { 210 // Don't want any delay for form state sync changes. This will still post a 211 // message so updates will get coalesced, but as soon as we spin the message 212 // loop, it will generate an update. 213 SendContentStateImmediately(); 214 215 LoadHTML("<form method=\"POST\" autocomplete=\"Off\">" 216 " <input id=\"firstname\" autocomplete=\"OFF\"/>" 217 " <input id=\"middlename\"/>" 218 " <input id=\"lastname\"/>" 219 "</form>"); 220 221 // Verify that "QueryFormFieldAutofill" isn't sent prior to a user 222 // interaction. 223 const IPC::Message* message0 = render_thread_->sink().GetFirstMessageMatching( 224 AutofillHostMsg_QueryFormFieldAutofill::ID); 225 EXPECT_EQ(static_cast<IPC::Message*>(NULL), message0); 226 227 WebFrame* web_frame = GetMainFrame(); 228 WebDocument document = web_frame->document(); 229 WebInputElement firstname = 230 document.getElementById("firstname").to<WebInputElement>(); 231 WebInputElement middlename = 232 document.getElementById("middlename").to<WebInputElement>(); 233 234 // Simulate attempting to Autofill the form from the first element, which 235 // specifies autocomplete="off". This should still trigger an IPC which 236 // shouldn't display warnings. 237 autofill_agent_->InputElementClicked(firstname, true, true); 238 const IPC::Message* message1 = render_thread_->sink().GetFirstMessageMatching( 239 AutofillHostMsg_QueryFormFieldAutofill::ID); 240 EXPECT_NE(static_cast<IPC::Message*>(NULL), message1); 241 242 AutofillQueryParam query_param; 243 AutofillHostMsg_QueryFormFieldAutofill::Read(message1, &query_param); 244 EXPECT_FALSE(query_param.e); 245 render_thread_->sink().ClearMessages(); 246 247 // Simulate attempting to Autofill the form from the second element, which 248 // does not specify autocomplete="off". This should trigger an IPC that will 249 // show warnings, as we *do* show warnings for elements that don't themselves 250 // set autocomplete="off", but for which the form does. 251 autofill_agent_->InputElementClicked(middlename, true, true); 252 const IPC::Message* message2 = render_thread_->sink().GetFirstMessageMatching( 253 AutofillHostMsg_QueryFormFieldAutofill::ID); 254 ASSERT_NE(static_cast<IPC::Message*>(NULL), message2); 255 256 AutofillHostMsg_QueryFormFieldAutofill::Read(message2, &query_param); 257 EXPECT_TRUE(query_param.e); 258 } 259 260 } // namespace autofill 261