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