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