autofill_renderer_browsertest.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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/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" 22 23using base::ASCIIToUTF16; 24using blink::WebDocument; 25using blink::WebElement; 26using blink::WebFormElement; 27using blink::WebFrame; 28using blink::WebLocalFrame; 29using blink::WebInputElement; 30using blink::WebString; 31using blink::WebURLRequest; 32using blink::WebVector; 33 34namespace autofill { 35 36typedef Tuple5<int, 37 autofill::FormData, 38 autofill::FormFieldData, 39 gfx::RectF, 40 bool> AutofillQueryParam; 41 42class AutofillRendererTest : public ChromeRenderViewTest { 43 public: 44 AutofillRendererTest() {} 45 virtual ~AutofillRendererTest() {} 46 47 protected: 48 virtual void SetUp() OVERRIDE { 49 ChromeRenderViewTest::SetUp(); 50 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(); 55 } 56 57 private: 58 DISALLOW_COPY_AND_ASSIGN(AutofillRendererTest); 59}; 60 61TEST_F(AutofillRendererTest, SendForms) { 62 LoadHTML("<form method='POST'>" 63 " <input type='text' id='firstname'/>" 64 " <input type='text' id='middlename'/>" 65 " <input type='text' id='lastname' autoComplete='off'/>" 66 " <input type='hidden' id='email'/>" 67 " <select id='state'/>" 68 " <option>?</option>" 69 " <option>California</option>" 70 " <option>Texas</option>" 71 " </select>" 72 "</form>"); 73 74 // Verify that "FormsSeen" sends the expected number of fields. 75 const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching( 76 AutofillHostMsg_FormsSeen::ID); 77 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); 78 AutofillHostMsg_FormsSeen::Param params; 79 AutofillHostMsg_FormsSeen::Read(message, ¶ms); 80 std::vector<FormData> forms = params.a; 81 ASSERT_EQ(1UL, forms.size()); 82 ASSERT_EQ(4UL, forms[0].fields.size()); 83 84 FormFieldData expected; 85 86 expected.name = ASCIIToUTF16("firstname"); 87 expected.value = base::string16(); 88 expected.form_control_type = "text"; 89 expected.max_length = WebInputElement::defaultMaxLength(); 90 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[0]); 91 92 expected.name = ASCIIToUTF16("middlename"); 93 expected.value = base::string16(); 94 expected.form_control_type = "text"; 95 expected.max_length = WebInputElement::defaultMaxLength(); 96 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[1]); 97 98 expected.name = ASCIIToUTF16("lastname"); 99 expected.value = base::string16(); 100 expected.form_control_type = "text"; 101 expected.autocomplete_attribute = "off"; 102 expected.max_length = WebInputElement::defaultMaxLength(); 103 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[2]); 104 expected.autocomplete_attribute = std::string(); // reset 105 106 expected.name = ASCIIToUTF16("state"); 107 expected.value = ASCIIToUTF16("?"); 108 expected.form_control_type = "select-one"; 109 expected.max_length = 0; 110 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[3]); 111 112 render_thread_->sink().ClearMessages(); 113 114 // Dynamically create a new form. A new message should be sent for it, but 115 // not for the previous form. 116 ExecuteJavaScript( 117 "var newForm=document.createElement('form');" 118 "newForm.id='new_testform';" 119 "newForm.action='http://google.com';" 120 "newForm.method='post';" 121 "var newFirstname=document.createElement('input');" 122 "newFirstname.setAttribute('type', 'text');" 123 "newFirstname.setAttribute('id', 'second_firstname');" 124 "newFirstname.value = 'Bob';" 125 "var newLastname=document.createElement('input');" 126 "newLastname.setAttribute('type', 'text');" 127 "newLastname.setAttribute('id', 'second_lastname');" 128 "newLastname.value = 'Hope';" 129 "var newEmail=document.createElement('input');" 130 "newEmail.setAttribute('type', 'text');" 131 "newEmail.setAttribute('id', 'second_email');" 132 "newEmail.value = 'bobhope@example.com';" 133 "newForm.appendChild(newFirstname);" 134 "newForm.appendChild(newLastname);" 135 "newForm.appendChild(newEmail);" 136 "document.body.appendChild(newForm);"); 137 msg_loop_.RunUntilIdle(); 138 139 message = render_thread_->sink().GetFirstMessageMatching( 140 AutofillHostMsg_FormsSeen::ID); 141 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); 142 AutofillHostMsg_FormsSeen::Read(message, ¶ms); 143 forms = params.a; 144 ASSERT_EQ(1UL, forms.size()); 145 ASSERT_EQ(3UL, forms[0].fields.size()); 146 147 expected.form_control_type = "text"; 148 expected.max_length = WebInputElement::defaultMaxLength(); 149 150 expected.name = ASCIIToUTF16("second_firstname"); 151 expected.value = ASCIIToUTF16("Bob"); 152 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[0]); 153 154 expected.name = ASCIIToUTF16("second_lastname"); 155 expected.value = ASCIIToUTF16("Hope"); 156 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[1]); 157 158 expected.name = ASCIIToUTF16("second_email"); 159 expected.value = ASCIIToUTF16("bobhope@example.com"); 160 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[2]); 161} 162 163TEST_F(AutofillRendererTest, EnsureNoFormSeenIfTooFewFields) { 164 LoadHTML("<form method='POST'>" 165 " <input type='text' id='firstname'/>" 166 " <input type='text' id='middlename'/>" 167 "</form>"); 168 169 // Verify that "FormsSeen" isn't sent, as there are too few fields. 170 const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching( 171 AutofillHostMsg_FormsSeen::ID); 172 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); 173 AutofillHostMsg_FormsSeen::Param params; 174 AutofillHostMsg_FormsSeen::Read(message, ¶ms); 175 const std::vector<FormData>& forms = params.a; 176 ASSERT_EQ(0UL, forms.size()); 177} 178 179TEST_F(AutofillRendererTest, ShowAutofillWarning) { 180 LoadHTML("<form method='POST' autocomplete='Off'>" 181 " <input id='firstname' autocomplete='OFF'/>" 182 " <input id='middlename'/>" 183 " <input id='lastname'/>" 184 "</form>"); 185 186 // Verify that "QueryFormFieldAutofill" isn't sent prior to a user 187 // interaction. 188 const IPC::Message* message0 = render_thread_->sink().GetFirstMessageMatching( 189 AutofillHostMsg_QueryFormFieldAutofill::ID); 190 EXPECT_EQ(static_cast<IPC::Message*>(NULL), message0); 191 192 WebFrame* web_frame = GetMainFrame(); 193 WebDocument document = web_frame->document(); 194 WebInputElement firstname = 195 document.getElementById("firstname").to<WebInputElement>(); 196 WebInputElement middlename = 197 document.getElementById("middlename").to<WebInputElement>(); 198 199 // Simulate attempting to Autofill the form from the first element, which 200 // specifies autocomplete="off". This should still trigger an IPC which 201 // shouldn't display warnings. 202 autofill_agent_->FormControlElementClicked(firstname, true); 203 const IPC::Message* message1 = render_thread_->sink().GetFirstMessageMatching( 204 AutofillHostMsg_QueryFormFieldAutofill::ID); 205 EXPECT_NE(static_cast<IPC::Message*>(NULL), message1); 206 207 AutofillQueryParam query_param; 208 AutofillHostMsg_QueryFormFieldAutofill::Read(message1, &query_param); 209 EXPECT_FALSE(query_param.e); 210 render_thread_->sink().ClearMessages(); 211 212 // Simulate attempting to Autofill the form from the second element, which 213 // does not specify autocomplete="off". This should trigger an IPC that will 214 // show warnings, as we *do* show warnings for elements that don't themselves 215 // set autocomplete="off", but for which the form does. 216 autofill_agent_->FormControlElementClicked(middlename, true); 217 const IPC::Message* message2 = render_thread_->sink().GetFirstMessageMatching( 218 AutofillHostMsg_QueryFormFieldAutofill::ID); 219 ASSERT_NE(static_cast<IPC::Message*>(NULL), message2); 220 221 AutofillHostMsg_QueryFormFieldAutofill::Read(message2, &query_param); 222 EXPECT_TRUE(query_param.e); 223} 224 225// Regression test for [ http://crbug.com/346010 ]. 226TEST_F(AutofillRendererTest, DontCrashWhileAssociatingForms) { 227 LoadHTML("<form id='form'>" 228 "<foo id='foo'>" 229 "<script id='script'>" 230 "document.documentElement.appendChild(foo);" 231 "newDoc = document.implementation.createDocument(" 232 " 'http://www.w3.org/1999/xhtml', 'html');" 233 "foo.insertBefore(form, script);" 234 "newDoc.adoptNode(foo);" 235 "</script>"); 236 237 // Shouldn't crash. 238} 239 240class RequestAutocompleteRendererTest : public AutofillRendererTest { 241 public: 242 RequestAutocompleteRendererTest() 243 : invoking_frame_(NULL), sibling_frame_(NULL) {} 244 virtual ~RequestAutocompleteRendererTest() {} 245 246 protected: 247 virtual void SetUp() OVERRIDE { 248 AutofillRendererTest::SetUp(); 249 250 // Bypass the HTTPS-only restriction to show requestAutocomplete. 251 CommandLine* command_line = CommandLine::ForCurrentProcess(); 252 command_line->AppendSwitch(::switches::kReduceSecurityForTesting); 253 254 GURL url("data:text/html;charset=utf-8," 255 "<form><input autocomplete=cc-number></form>"); 256 const char kDoubleIframeHtml[] = "<iframe id=subframe src='%s'></iframe>" 257 "<iframe id=sibling></iframe>"; 258 LoadHTML(base::StringPrintf(kDoubleIframeHtml, url.spec().c_str()).c_str()); 259 260 WebElement subframe = GetMainFrame()->document().getElementById("subframe"); 261 ASSERT_FALSE(subframe.isNull()); 262 invoking_frame_ = WebLocalFrame::fromFrameOwnerElement(subframe); 263 ASSERT_TRUE(invoking_frame()); 264 ASSERT_EQ(GetMainFrame(), invoking_frame()->parent()); 265 266 WebElement sibling = GetMainFrame()->document().getElementById("sibling"); 267 ASSERT_FALSE(sibling.isNull()); 268 sibling_frame_ = WebLocalFrame::fromFrameOwnerElement(sibling); 269 ASSERT_TRUE(sibling_frame()); 270 271 WebVector<WebFormElement> forms; 272 invoking_frame()->document().forms(forms); 273 ASSERT_EQ(1U, forms.size()); 274 invoking_form_ = forms[0]; 275 ASSERT_FALSE(invoking_form().isNull()); 276 277 render_thread_->sink().ClearMessages(); 278 279 // Invoke requestAutocomplete to show the dialog. 280 autofill_agent_->didRequestAutocomplete(invoking_form()); 281 ASSERT_TRUE(render_thread_->sink().GetFirstMessageMatching( 282 AutofillHostMsg_RequestAutocomplete::ID)); 283 284 render_thread_->sink().ClearMessages(); 285 } 286 287 virtual void TearDown() OVERRIDE { 288 invoking_form_.reset(); 289 AutofillRendererTest::TearDown(); 290 } 291 292 void NavigateFrame(WebFrame* frame) { 293 frame->loadRequest(WebURLRequest(GURL("about:blank"))); 294 ProcessPendingMessages(); 295 } 296 297 const WebFormElement& invoking_form() const { return invoking_form_; } 298 WebLocalFrame* invoking_frame() { return invoking_frame_; } 299 WebFrame* sibling_frame() { return sibling_frame_; } 300 301 private: 302 WebFormElement invoking_form_; 303 WebLocalFrame* invoking_frame_; 304 WebFrame* sibling_frame_; 305 306 DISALLOW_COPY_AND_ASSIGN(RequestAutocompleteRendererTest); 307}; 308 309TEST_F(RequestAutocompleteRendererTest, SiblingNavigateIgnored) { 310 // Pretend that a sibling frame navigated. No cancel should be sent. 311 NavigateFrame(sibling_frame()); 312 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 313 AutofillHostMsg_CancelRequestAutocomplete::ID)); 314} 315 316TEST_F(RequestAutocompleteRendererTest, SubframeNavigateCancels) { 317 // Pretend that the invoking frame navigated. A cancel should be sent. 318 NavigateFrame(invoking_frame()); 319 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching( 320 AutofillHostMsg_CancelRequestAutocomplete::ID)); 321} 322 323TEST_F(RequestAutocompleteRendererTest, MainFrameNavigateCancels) { 324 // Pretend that the top-level frame navigated. A cancel should be sent. 325 NavigateFrame(GetMainFrame()); 326 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching( 327 AutofillHostMsg_CancelRequestAutocomplete::ID)); 328} 329 330TEST_F(RequestAutocompleteRendererTest, NoCancelOnSubframeNavigateAfterDone) { 331 // Pretend that the dialog was cancelled. 332 autofill_agent_->OnRequestAutocompleteResult( 333 WebFormElement::AutocompleteResultErrorCancel, 334 base::ASCIIToUTF16("Print me to the console"), 335 FormData()); 336 337 // Additional navigations should not crash nor send cancels. 338 NavigateFrame(invoking_frame()); 339 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 340 AutofillHostMsg_CancelRequestAutocomplete::ID)); 341} 342 343TEST_F(RequestAutocompleteRendererTest, NoCancelOnMainFrameNavigateAfterDone) { 344 // Pretend that the dialog was cancelled. 345 autofill_agent_->OnRequestAutocompleteResult( 346 WebFormElement::AutocompleteResultErrorCancel, 347 base::ASCIIToUTF16("Print me to the console"), 348 FormData()); 349 350 // Additional navigations should not crash nor send cancels. 351 NavigateFrame(GetMainFrame()); 352 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 353 AutofillHostMsg_CancelRequestAutocomplete::ID)); 354} 355 356TEST_F(RequestAutocompleteRendererTest, InvokingTwiceOnlyShowsOnce) { 357 // Attempting to show the requestAutocomplete dialog again should be ignored. 358 autofill_agent_->didRequestAutocomplete(invoking_form()); 359 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 360 AutofillHostMsg_RequestAutocomplete::ID)); 361} 362 363} // namespace autofill 364