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