autofill_interactive_uitest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright (c) 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 "base/memory/ref_counted.h" 6#include "base/memory/scoped_ptr.h" 7#include "chrome/browser/autofill/personal_data_manager_factory.h" 8#include "chrome/browser/chrome_notification_types.h" 9#include "chrome/browser/infobars/confirm_infobar_delegate.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/ui/browser.h" 12#include "chrome/browser/ui/tabs/tab_strip_model.h" 13#include "chrome/test/base/in_process_browser_test.h" 14#include "chrome/test/base/ui_test_utils.h" 15#include "components/autofill/content/browser/autofill_driver_impl.h" 16#include "components/autofill/core/browser/autofill_common_test.h" 17#include "components/autofill/core/browser/autofill_external_delegate.h" 18#include "components/autofill/core/browser/autofill_manager.h" 19#include "components/autofill/core/browser/autofill_manager_test_delegate.h" 20#include "components/autofill/core/browser/autofill_profile.h" 21#include "components/autofill/core/browser/personal_data_manager.h" 22#include "components/autofill/core/browser/personal_data_manager_observer.h" 23#include "content/public/browser/notification_observer.h" 24#include "content/public/browser/notification_registrar.h" 25#include "content/public/browser/notification_service.h" 26#include "content/public/browser/render_view_host.h" 27#include "content/public/browser/web_contents.h" 28#include "content/public/test/browser_test_utils.h" 29#include "content/public/test/test_utils.h" 30#include "ui/base/keycodes/keyboard_codes.h" 31 32using content::RenderViewHost; 33 34// TODO(csharp): Most of this file was just copied from autofill_browsertests.cc 35// The repeated code should be moved into a helper file, instead of being 36// repeated. 37 38namespace autofill { 39 40static const char* kDataURIPrefix = "data:text/html;charset=utf-8,"; 41static const char* kTestFormString = 42 "<form action=\"http://www.example.com/\" method=\"POST\">" 43 "<label for=\"firstname\">First name:</label>" 44 " <input type=\"text\" id=\"firstname\"" 45 " onFocus=\"domAutomationController.send(true)\"><br>" 46 "<label for=\"lastname\">Last name:</label>" 47 " <input type=\"text\" id=\"lastname\"><br>" 48 "<label for=\"address1\">Address line 1:</label>" 49 " <input type=\"text\" id=\"address1\"><br>" 50 "<label for=\"address2\">Address line 2:</label>" 51 " <input type=\"text\" id=\"address2\"><br>" 52 "<label for=\"city\">City:</label>" 53 " <input type=\"text\" id=\"city\"><br>" 54 "<label for=\"state\">State:</label>" 55 " <select id=\"state\">" 56 " <option value=\"\" selected=\"yes\">--</option>" 57 " <option value=\"CA\">California</option>" 58 " <option value=\"TX\">Texas</option>" 59 " </select><br>" 60 "<label for=\"zip\">ZIP code:</label>" 61 " <input type=\"text\" id=\"zip\"><br>" 62 "<label for=\"country\">Country:</label>" 63 " <select id=\"country\">" 64 " <option value=\"\" selected=\"yes\">--</option>" 65 " <option value=\"CA\">Canada</option>" 66 " <option value=\"US\">United States</option>" 67 " </select><br>" 68 "<label for=\"phone\">Phone number:</label>" 69 " <input type=\"text\" id=\"phone\"><br>" 70 "</form>"; 71 72class AutofillManagerTestDelegateImpl 73 : public autofill::AutofillManagerTestDelegate { 74 public: 75 AutofillManagerTestDelegateImpl() {} 76 77 virtual void DidPreviewFormData() OVERRIDE { 78 loop_runner_->Quit(); 79 } 80 81 virtual void DidFillFormData() OVERRIDE { 82 loop_runner_->Quit(); 83 } 84 85 virtual void DidShowSuggestions() OVERRIDE { 86 loop_runner_->Quit(); 87 } 88 89 void Reset() { 90 loop_runner_ = new content::MessageLoopRunner(); 91 } 92 93 void Wait() { 94 loop_runner_->Run(); 95 } 96 97 private: 98 scoped_refptr<content::MessageLoopRunner> loop_runner_; 99 100 DISALLOW_COPY_AND_ASSIGN(AutofillManagerTestDelegateImpl); 101}; 102 103class WindowedPersonalDataManagerObserver 104 : public PersonalDataManagerObserver, 105 public content::NotificationObserver { 106 public: 107 explicit WindowedPersonalDataManagerObserver(Browser* browser) 108 : alerted_(false), 109 has_run_message_loop_(false), 110 browser_(browser), 111 infobar_service_(NULL) { 112 PersonalDataManagerFactory::GetForProfile(browser_->profile())-> 113 AddObserver(this); 114 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, 115 content::NotificationService::AllSources()); 116 } 117 118 virtual ~WindowedPersonalDataManagerObserver() { 119 if (infobar_service_ && infobar_service_->infobar_count() > 0) 120 infobar_service_->RemoveInfoBar(infobar_service_->infobar_at(0)); 121 } 122 123 void Wait() { 124 if (!alerted_) { 125 has_run_message_loop_ = true; 126 content::RunMessageLoop(); 127 } 128 PersonalDataManagerFactory::GetForProfile(browser_->profile())-> 129 RemoveObserver(this); 130 } 131 132 // PersonalDataManagerObserver: 133 virtual void OnPersonalDataChanged() OVERRIDE { 134 if (has_run_message_loop_) { 135 base::MessageLoopForUI::current()->Quit(); 136 has_run_message_loop_ = false; 137 } 138 alerted_ = true; 139 } 140 141 virtual void OnInsufficientFormData() OVERRIDE { 142 OnPersonalDataChanged(); 143 } 144 145 // content::NotificationObserver: 146 virtual void Observe(int type, 147 const content::NotificationSource& source, 148 const content::NotificationDetails& details) OVERRIDE { 149 // Accept in the infobar. 150 infobar_service_ = InfoBarService::FromWebContents( 151 browser_->tab_strip_model()->GetActiveWebContents()); 152 InfoBarDelegate* infobar = infobar_service_->infobar_at(0); 153 154 ConfirmInfoBarDelegate* confirm_infobar = 155 infobar->AsConfirmInfoBarDelegate(); 156 confirm_infobar->Accept(); 157 } 158 159 private: 160 bool alerted_; 161 bool has_run_message_loop_; 162 Browser* browser_; 163 content::NotificationRegistrar registrar_; 164 InfoBarService* infobar_service_; 165}; 166 167class TestAutofillExternalDelegate : public AutofillExternalDelegate { 168 public: 169 TestAutofillExternalDelegate(content::WebContents* web_contents, 170 AutofillManager* autofill_manager, 171 AutofillDriver* autofill_driver) 172 : AutofillExternalDelegate(web_contents, autofill_manager, 173 autofill_driver), 174 keyboard_listener_(NULL) { 175 } 176 virtual ~TestAutofillExternalDelegate() {} 177 178 virtual void OnPopupShown(content::KeyboardListener* listener) OVERRIDE { 179 AutofillExternalDelegate::OnPopupShown(listener); 180 keyboard_listener_ = listener; 181 } 182 183 virtual void OnPopupHidden(content::KeyboardListener* listener) OVERRIDE { 184 keyboard_listener_ = NULL; 185 AutofillExternalDelegate::OnPopupHidden(listener); 186 } 187 188 content::KeyboardListener* keyboard_listener() { 189 return keyboard_listener_; 190 } 191 192 private: 193 // The popup that is currently registered as a keyboard listener, or NULL if 194 // there is none. 195 content::KeyboardListener* keyboard_listener_; 196 197 DISALLOW_COPY_AND_ASSIGN(TestAutofillExternalDelegate); 198}; 199 200class AutofillInteractiveTest : public InProcessBrowserTest { 201 protected: 202 AutofillInteractiveTest() {} 203 204 virtual void SetUpOnMainThread() OVERRIDE { 205 // Don't want Keychain coming up on Mac. 206 test::DisableSystemServices(browser()->profile()); 207 208 // When testing the native UI, hook up a test external delegate, which 209 // allows us to forward keyboard events to the popup directly. 210 content::WebContents* web_contents = 211 browser()->tab_strip_model()->GetActiveWebContents(); 212 AutofillDriverImpl* autofill_driver = 213 AutofillDriverImpl::FromWebContents(web_contents); 214 AutofillManager* autofill_manager = autofill_driver->autofill_manager(); 215 scoped_ptr<AutofillExternalDelegate> external_delegate( 216 new TestAutofillExternalDelegate(web_contents, autofill_manager, 217 autofill_driver)); 218 autofill_driver->SetAutofillExternalDelegate(external_delegate.Pass()); 219 autofill_manager->SetTestDelegate(&test_delegate_); 220 } 221 222 virtual void CleanUpOnMainThread() OVERRIDE { 223 // Make sure to close any showing popups prior to tearing down the UI. 224 content::WebContents* web_contents = 225 browser()->tab_strip_model()->GetActiveWebContents(); 226 AutofillManager* autofill_manager = 227 AutofillDriverImpl::FromWebContents(web_contents)->autofill_manager(); 228 autofill_manager->delegate()->HideAutofillPopup(); 229 } 230 231 PersonalDataManager* personal_data_manager() { 232 return PersonalDataManagerFactory::GetForProfile(browser()->profile()); 233 } 234 235 void CreateTestProfile() { 236 AutofillProfile profile; 237 test::SetProfileInfo( 238 &profile, "Milton", "C.", "Waddams", 239 "red.swingline@initech.com", "Initech", "4120 Freidrich Lane", 240 "Basement", "Austin", "Texas", "78744", "US", "5125551234"); 241 242 WindowedPersonalDataManagerObserver observer(browser()); 243 personal_data_manager()->AddProfile(profile); 244 245 // AddProfile is asynchronous. Wait for it to finish before continuing the 246 // tests. 247 observer.Wait(); 248 } 249 250 void ExpectFieldValue(const std::string& field_name, 251 const std::string& expected_value) { 252 std::string value; 253 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 254 browser()->tab_strip_model()->GetActiveWebContents(), 255 "window.domAutomationController.send(" 256 " document.getElementById('" + field_name + "').value);", 257 &value)); 258 EXPECT_EQ(expected_value, value); 259 } 260 261 RenderViewHost* render_view_host() { 262 return browser()->tab_strip_model()->GetActiveWebContents()-> 263 GetRenderViewHost(); 264 } 265 266 void FocusFirstNameField() { 267 LOG(WARNING) << "Clicking on the tab."; 268 content::SimulateMouseClick( 269 browser()->tab_strip_model()->GetActiveWebContents(), 270 0, 271 WebKit::WebMouseEvent::ButtonLeft); 272 273 LOG(WARNING) << "Focusing the first name field."; 274 bool result = false; 275 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 276 render_view_host(), 277 "if (document.readyState === 'complete')" 278 " document.getElementById('firstname').focus();" 279 "else" 280 " domAutomationController.send(false);", 281 &result)); 282 ASSERT_TRUE(result); 283 } 284 285 void ExpectFilledTestForm() { 286 ExpectFieldValue("firstname", "Milton"); 287 ExpectFieldValue("lastname", "Waddams"); 288 ExpectFieldValue("address1", "4120 Freidrich Lane"); 289 ExpectFieldValue("address2", "Basement"); 290 ExpectFieldValue("city", "Austin"); 291 ExpectFieldValue("state", "TX"); 292 ExpectFieldValue("zip", "78744"); 293 ExpectFieldValue("country", "US"); 294 ExpectFieldValue("phone", "5125551234"); 295 } 296 297 void SendKeyToPageAndWait(ui::KeyboardCode key) { 298 test_delegate_.Reset(); 299 content::SimulateKeyPress( 300 browser()->tab_strip_model()->GetActiveWebContents(), 301 key, false, false, false, false); 302 test_delegate_.Wait(); 303 } 304 305 void SendKeyToPopupAndWait(ui::KeyboardCode key) { 306 // TODO(isherman): Remove this condition once the WebKit popup UI code is 307 // removed. 308 if (!external_delegate()) { 309 // When testing the WebKit-based UI, route all keys to the page. 310 SendKeyToPageAndWait(key); 311 return; 312 } 313 314 // When testing the native UI, route popup-targeted key presses via the 315 // external delegate. 316 content::NativeWebKeyboardEvent event; 317 event.windowsKeyCode = key; 318 test_delegate_.Reset(); 319 external_delegate()->keyboard_listener()->HandleKeyPressEvent(event); 320 test_delegate_.Wait(); 321 } 322 323 TestAutofillExternalDelegate* external_delegate() { 324 content::WebContents* web_contents = 325 browser()->tab_strip_model()->GetActiveWebContents(); 326 AutofillDriverImpl* autofill_driver = 327 AutofillDriverImpl::FromWebContents(web_contents); 328 return static_cast<TestAutofillExternalDelegate*>( 329 autofill_driver->autofill_external_delegate()); 330 } 331 332 AutofillManagerTestDelegateImpl test_delegate_; 333}; 334 335IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, DISABLED_AutofillSelectViaTab) { 336 CreateTestProfile(); 337 338 // Load the test page. 339 ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), 340 GURL(std::string(kDataURIPrefix) + kTestFormString))); 341 342 // Focus a fillable field. 343 FocusFirstNameField(); 344 345 // Press the down arrow to initiate Autofill and wait for the popup to be 346 // shown. 347 SendKeyToPageAndWait(ui::VKEY_DOWN); 348 349 // Press the down arrow to select the suggestion and preview the autofilled 350 // form. 351 SendKeyToPopupAndWait(ui::VKEY_DOWN); 352 353 // Press tab to accept the autofill suggestions. 354 SendKeyToPopupAndWait(ui::VKEY_TAB); 355 356 // The form should be filled. 357 ExpectFilledTestForm(); 358} 359 360} // namespace autofill 361