Home | History | Annotate | Download | only in autofill
      1 // Copyright 2013 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 <string.h>
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "chrome/test/base/chrome_render_view_test.h"
     10 #include "components/autofill/content/common/autofill_messages.h"
     11 #include "components/autofill/content/renderer/autofill_agent.h"
     12 #include "components/autofill/content/renderer/test_password_generation_agent.h"
     13 #include "components/autofill/core/common/form_data.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "third_party/WebKit/public/platform/WebString.h"
     16 #include "third_party/WebKit/public/web/WebDocument.h"
     17 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     18 #include "third_party/WebKit/public/web/WebWidget.h"
     19 
     20 using blink::WebDocument;
     21 using blink::WebElement;
     22 using blink::WebInputElement;
     23 using blink::WebNode;
     24 using blink::WebString;
     25 
     26 namespace autofill {
     27 
     28 class PasswordGenerationAgentTest : public ChromeRenderViewTest {
     29  public:
     30   PasswordGenerationAgentTest() {}
     31 
     32   virtual void TearDown() {
     33     LoadHTML("");
     34     ChromeRenderViewTest::TearDown();
     35   }
     36 
     37   void SetNotBlacklistedMessage(const char* form_str) {
     38     autofill::PasswordForm form;
     39     form.origin =
     40         GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str));
     41     AutofillMsg_FormNotBlacklisted msg(0, form);
     42     password_generation_->OnMessageReceived(msg);
     43   }
     44 
     45   void SetAccountCreationFormsDetectedMessage(const char* form_str) {
     46     autofill::FormData form;
     47     form.origin =
     48         GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str));
     49     std::vector<autofill::FormData> forms;
     50     forms.push_back(form);
     51     AutofillMsg_AccountCreationFormsDetected msg(0, forms);
     52     password_generation_->OnMessageReceived(msg);
     53   }
     54 
     55   void ExpectPasswordGenerationAvailable(const char* element_id,
     56                                          bool available) {
     57     WebDocument document = GetMainFrame()->document();
     58     WebElement element =
     59         document.getElementById(WebString::fromUTF8(element_id));
     60     ASSERT_FALSE(element.isNull());
     61     WebInputElement target_element = element.to<WebInputElement>();
     62     ExecuteJavaScript(
     63         base::StringPrintf("document.getElementById('%s').focus();",
     64                            element_id).c_str());
     65     if (available) {
     66       ASSERT_EQ(1u, password_generation_->messages().size());
     67       EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
     68                 password_generation_->messages()[0]->type());
     69     } else {
     70       EXPECT_EQ(0u, password_generation_->messages().size());
     71     }
     72     password_generation_->clear_messages();
     73   }
     74 
     75  private:
     76   DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgentTest);
     77 };
     78 
     79 const char kSigninFormHTML[] =
     80     "<FORM name = 'blah' action = 'http://www.random.com/'> "
     81     "  <INPUT type = 'text' id = 'username'/> "
     82     "  <INPUT type = 'password' id = 'password'/> "
     83     "  <INPUT type = 'submit' value = 'LOGIN' />"
     84     "</FORM>";
     85 
     86 const char kAccountCreationFormHTML[] =
     87     "<FORM name = 'blah' action = 'http://www.random.com/'> "
     88     "  <INPUT type = 'text' id = 'username'/> "
     89     "  <INPUT type = 'password' id = 'first_password' "
     90     "         autocomplete = 'off' size = 5/>"
     91     "  <INPUT type = 'password' id = 'second_password' size = 5/> "
     92     "  <INPUT type = 'text' id = 'address'/> "
     93     "  <INPUT type = 'submit' value = 'LOGIN' />"
     94     "</FORM>";
     95 
     96 const char kHiddenPasswordAccountCreationFormHTML[] =
     97     "<FORM name = 'blah' action = 'http://www.random.com/'> "
     98     "  <INPUT type = 'text' id = 'username'/> "
     99     "  <INPUT type = 'password' id = 'first_password'/> "
    100     "  <INPUT type = 'password' id = 'second_password' style='display:none'/> "
    101     "  <INPUT type = 'submit' value = 'LOGIN' />"
    102     "</FORM>";
    103 
    104 const char kInvalidActionAccountCreationFormHTML[] =
    105     "<FORM name = 'blah' action = 'invalid'> "
    106     "  <INPUT type = 'text' id = 'username'/> "
    107     "  <INPUT type = 'password' id = 'first_password'/> "
    108     "  <INPUT type = 'password' id = 'second_password'/> "
    109     "  <INPUT type = 'submit' value = 'LOGIN' />"
    110     "</FORM>";
    111 
    112 TEST_F(PasswordGenerationAgentTest, DetectionTest) {
    113   // Don't shown the icon for non account creation forms.
    114   LoadHTML(kSigninFormHTML);
    115   ExpectPasswordGenerationAvailable("password", false);
    116 
    117   // We don't show the decoration yet because the feature isn't enabled.
    118   LoadHTML(kAccountCreationFormHTML);
    119   ExpectPasswordGenerationAvailable("first_password", false);
    120 
    121   // Pretend like We have received message indicating site is not blacklisted,
    122   // and we have received message indicating the form is classified as
    123   // ACCOUNT_CREATION_FORM form Autofill server. We should show the icon.
    124   LoadHTML(kAccountCreationFormHTML);
    125   SetNotBlacklistedMessage(kAccountCreationFormHTML);
    126   SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
    127   ExpectPasswordGenerationAvailable("first_password", true);
    128 
    129   // This doesn't trigger because hidden password fields are ignored.
    130   LoadHTML(kHiddenPasswordAccountCreationFormHTML);
    131   SetNotBlacklistedMessage(kHiddenPasswordAccountCreationFormHTML);
    132   SetAccountCreationFormsDetectedMessage(
    133       kHiddenPasswordAccountCreationFormHTML);
    134   ExpectPasswordGenerationAvailable("first_password", false);
    135 
    136   // This doesn't trigger because the form action is invalid.
    137   LoadHTML(kInvalidActionAccountCreationFormHTML);
    138   SetNotBlacklistedMessage(kInvalidActionAccountCreationFormHTML);
    139   SetAccountCreationFormsDetectedMessage(kInvalidActionAccountCreationFormHTML);
    140   ExpectPasswordGenerationAvailable("first_password", false);
    141 }
    142 
    143 TEST_F(PasswordGenerationAgentTest, FillTest) {
    144   // Make sure that we are enabled before loading HTML.
    145   LoadHTML(kAccountCreationFormHTML);
    146 
    147   WebDocument document = GetMainFrame()->document();
    148   WebElement element =
    149       document.getElementById(WebString::fromUTF8("first_password"));
    150   ASSERT_FALSE(element.isNull());
    151   WebInputElement first_password_element = element.to<WebInputElement>();
    152   element = document.getElementById(WebString::fromUTF8("second_password"));
    153   ASSERT_FALSE(element.isNull());
    154   WebInputElement second_password_element = element.to<WebInputElement>();
    155 
    156   // Both password fields should be empty.
    157   EXPECT_TRUE(first_password_element.value().isNull());
    158   EXPECT_TRUE(second_password_element.value().isNull());
    159 
    160   base::string16 password = base::ASCIIToUTF16("random_password");
    161   AutofillMsg_GeneratedPasswordAccepted msg(0, password);
    162   password_generation_->OnMessageReceived(msg);
    163 
    164   // Password fields are filled out and set as being autofilled.
    165   EXPECT_EQ(password, first_password_element.value());
    166   EXPECT_EQ(password, second_password_element.value());
    167   EXPECT_TRUE(first_password_element.isAutofilled());
    168   EXPECT_TRUE(second_password_element.isAutofilled());
    169 
    170   // Focus moved to the next input field.
    171   // TODO(zysxqn): Change this back to the address element once Bug 90224
    172   // https://bugs.webkit.org/show_bug.cgi?id=90224 has been fixed.
    173   element = document.getElementById(WebString::fromUTF8("first_password"));
    174   ASSERT_FALSE(element.isNull());
    175   EXPECT_EQ(element, document.focusedElement());
    176 }
    177 
    178 TEST_F(PasswordGenerationAgentTest, EditingTest) {
    179   LoadHTML(kAccountCreationFormHTML);
    180   SetNotBlacklistedMessage(kAccountCreationFormHTML);
    181   SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
    182 
    183   WebDocument document = GetMainFrame()->document();
    184   WebElement element =
    185       document.getElementById(WebString::fromUTF8("first_password"));
    186   ASSERT_FALSE(element.isNull());
    187   WebInputElement first_password_element = element.to<WebInputElement>();
    188   element = document.getElementById(WebString::fromUTF8("second_password"));
    189   ASSERT_FALSE(element.isNull());
    190   WebInputElement second_password_element = element.to<WebInputElement>();
    191 
    192   base::string16 password = base::ASCIIToUTF16("random_password");
    193   AutofillMsg_GeneratedPasswordAccepted msg(0, password);
    194   password_generation_->OnMessageReceived(msg);
    195 
    196   // Passwords start out the same.
    197   EXPECT_EQ(password, first_password_element.value());
    198   EXPECT_EQ(password, second_password_element.value());
    199 
    200   // After editing the first field they are still the same.
    201   base::string16 edited_password = base::ASCIIToUTF16("edited_password");
    202   first_password_element.setValue(edited_password);
    203   // Cast to WebAutofillClient where textFieldDidChange() is public.
    204   static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange(
    205       first_password_element);
    206   // textFieldDidChange posts a task, so we need to wait until it's been
    207   // processed.
    208   base::MessageLoop::current()->RunUntilIdle();
    209 
    210   EXPECT_EQ(edited_password, first_password_element.value());
    211   EXPECT_EQ(edited_password, second_password_element.value());
    212 }
    213 
    214 TEST_F(PasswordGenerationAgentTest, BlacklistedTest) {
    215   // Did not receive not blacklisted message. Don't show password generation
    216   // icon.
    217   LoadHTML(kAccountCreationFormHTML);
    218   SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
    219   ExpectPasswordGenerationAvailable("first_password", false);
    220 
    221   // Receive one not blacklisted message for non account creation form. Don't
    222   // show password generation icon.
    223   LoadHTML(kAccountCreationFormHTML);
    224   SetNotBlacklistedMessage(kSigninFormHTML);
    225   SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
    226   ExpectPasswordGenerationAvailable("first_password", false);
    227 
    228   // Receive one not blackliste message for account creation form. Show password
    229   // generation icon.
    230   LoadHTML(kAccountCreationFormHTML);
    231   SetNotBlacklistedMessage(kAccountCreationFormHTML);
    232   SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
    233   ExpectPasswordGenerationAvailable("first_password", true);
    234 
    235   // Receive two not blacklisted messages, one is for account creation form and
    236   // the other is not. Show password generation icon.
    237   LoadHTML(kAccountCreationFormHTML);
    238   SetNotBlacklistedMessage(kAccountCreationFormHTML);
    239   SetNotBlacklistedMessage(kSigninFormHTML);
    240   SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
    241   ExpectPasswordGenerationAvailable("first_password", true);
    242 }
    243 
    244 TEST_F(PasswordGenerationAgentTest, AccountCreationFormsDetectedTest) {
    245   // Did not receive account creation forms detected messege. Don't show
    246   // password generation icon.
    247   LoadHTML(kAccountCreationFormHTML);
    248   SetNotBlacklistedMessage(kAccountCreationFormHTML);
    249   ExpectPasswordGenerationAvailable("first_password", false);
    250 
    251   // Receive the account creation forms detected message. Show password
    252   // generation icon.
    253   LoadHTML(kAccountCreationFormHTML);
    254   SetNotBlacklistedMessage(kAccountCreationFormHTML);
    255   SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
    256   ExpectPasswordGenerationAvailable("first_password", true);
    257 }
    258 
    259 }  // namespace autofill
    260