Home | History | Annotate | Download | only in autofill
      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, &params);
     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, &params2);
    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, &params);
    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, &params);
    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, &params);
    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