autofill_dialog_controller_browsertest.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
1// Copyright (c) 2012 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/bind.h"
6#include "base/command_line.h"
7#include "base/memory/ref_counted.h"
8#include "base/memory/weak_ptr.h"
9#include "base/message_loop/message_loop.h"
10#include "base/prefs/pref_service.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/time/time.h"
13#include "chrome/browser/autofill/personal_data_manager_factory.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/ui/autofill/account_chooser_model.h"
16#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
17#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
18#include "chrome/browser/ui/autofill/data_model_wrapper.h"
19#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
20#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h"
21#include "chrome/browser/ui/autofill/testable_autofill_dialog_view.h"
22#include "chrome/browser/ui/browser.h"
23#include "chrome/browser/ui/tabs/tab_strip_model.h"
24#include "chrome/common/pref_names.h"
25#include "chrome/test/base/in_process_browser_test.h"
26#include "chrome/test/base/ui_test_utils.h"
27#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
28#include "components/autofill/content/browser/wallet/mock_wallet_client.h"
29#include "components/autofill/content/browser/wallet/wallet_test_util.h"
30#include "components/autofill/core/browser/autofill_common_test.h"
31#include "components/autofill/core/browser/autofill_metrics.h"
32#include "components/autofill/core/browser/test_personal_data_manager.h"
33#include "components/autofill/core/browser/validation.h"
34#include "components/autofill/core/common/autofill_switches.h"
35#include "components/autofill/core/common/form_data.h"
36#include "components/autofill/core/common/form_field_data.h"
37#include "content/public/browser/browser_thread.h"
38#include "content/public/browser/notification_service.h"
39#include "content/public/browser/web_contents.h"
40#include "content/public/browser/web_contents_delegate.h"
41#include "content/public/common/url_constants.h"
42#include "content/public/test/browser_test_utils.h"
43#include "content/public/test/test_utils.h"
44#include "testing/gmock/include/gmock/gmock.h"
45#include "testing/gtest/include/gtest/gtest.h"
46#include "third_party/WebKit/public/web/WebInputEvent.h"
47#include "url/gurl.h"
48
49namespace autofill {
50
51namespace {
52
53using testing::_;
54
55void MockCallback(const FormStructure*) {}
56
57class MockAutofillMetrics : public AutofillMetrics {
58 public:
59  MockAutofillMetrics()
60      : dialog_dismissal_action_(
61            static_cast<AutofillMetrics::DialogDismissalAction>(-1)) {}
62  virtual ~MockAutofillMetrics() {}
63
64  virtual void LogDialogUiDuration(
65      const base::TimeDelta& duration,
66      DialogDismissalAction dismissal_action) const OVERRIDE {
67    // Ignore constness for testing.
68    MockAutofillMetrics* mutable_this = const_cast<MockAutofillMetrics*>(this);
69    mutable_this->dialog_dismissal_action_ = dismissal_action;
70  }
71
72  AutofillMetrics::DialogDismissalAction dialog_dismissal_action() const {
73    return dialog_dismissal_action_;
74  }
75
76  MOCK_CONST_METHOD1(LogDialogDismissalState,
77                     void(DialogDismissalState state));
78
79 private:
80  AutofillMetrics::DialogDismissalAction dialog_dismissal_action_;
81
82  DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics);
83};
84
85class TestAutofillDialogController : public AutofillDialogControllerImpl {
86 public:
87  TestAutofillDialogController(
88      content::WebContents* contents,
89      const FormData& form_data,
90      const AutofillMetrics& metric_logger,
91      scoped_refptr<content::MessageLoopRunner> runner)
92      : AutofillDialogControllerImpl(contents,
93                                     form_data,
94                                     form_data.origin,
95                                     base::Bind(&MockCallback)),
96        metric_logger_(metric_logger),
97        mock_wallet_client_(
98            Profile::FromBrowserContext(contents->GetBrowserContext())->
99                GetRequestContext(), this, form_data.origin),
100        message_loop_runner_(runner),
101        use_validation_(false),
102        weak_ptr_factory_(this) {}
103
104  virtual ~TestAutofillDialogController() {}
105
106  virtual GURL SignInUrl() const OVERRIDE {
107    return GURL(content::kAboutBlankURL);
108  }
109
110  virtual void ViewClosed() OVERRIDE {
111    message_loop_runner_->Quit();
112    AutofillDialogControllerImpl::ViewClosed();
113  }
114
115  virtual string16 InputValidityMessage(
116      DialogSection section,
117      ServerFieldType type,
118      const string16& value) OVERRIDE {
119    if (!use_validation_)
120      return string16();
121    return AutofillDialogControllerImpl::InputValidityMessage(
122        section, type, value);
123  }
124
125  virtual ValidityMessages InputsAreValid(
126      DialogSection section,
127      const DetailOutputMap& inputs) OVERRIDE {
128    if (!use_validation_)
129      return ValidityMessages();
130    return AutofillDialogControllerImpl::InputsAreValid(section, inputs);
131  }
132
133  // Saving to Chrome is tested in AutofillDialogControllerImpl unit tests.
134  // TODO(estade): test that the view defaults to saving to Chrome.
135  virtual bool ShouldOfferToSaveInChrome() const OVERRIDE {
136    return false;
137  }
138
139  void ForceFinishSubmit() {
140    DoFinishSubmit();
141  }
142
143  // Increase visibility for testing.
144  using AutofillDialogControllerImpl::view;
145  using AutofillDialogControllerImpl::input_showing_popup;
146
147  MOCK_METHOD0(LoadRiskFingerprintData, void());
148
149  virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE {
150    return notifications_;
151  }
152
153  void set_notifications(const std::vector<DialogNotification>& notifications) {
154    notifications_ = notifications;
155  }
156
157  TestPersonalDataManager* GetTestingManager() {
158    return &test_manager_;
159  }
160
161  using AutofillDialogControllerImpl::IsEditingExistingData;
162  using AutofillDialogControllerImpl::IsManuallyEditingSection;
163  using AutofillDialogControllerImpl::IsSubmitPausedOn;
164  using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData;
165  using AutofillDialogControllerImpl::AccountChooserModelForTesting;
166
167  void set_use_validation(bool use_validation) {
168    use_validation_ = use_validation;
169  }
170
171  base::WeakPtr<TestAutofillDialogController> AsWeakPtr() {
172    return weak_ptr_factory_.GetWeakPtr();
173  }
174
175  wallet::MockWalletClient* GetTestingWalletClient() {
176    return &mock_wallet_client_;
177  }
178
179 protected:
180  virtual PersonalDataManager* GetManager() OVERRIDE {
181    return &test_manager_;
182  }
183
184  virtual wallet::WalletClient* GetWalletClient() OVERRIDE {
185    return &mock_wallet_client_;
186  }
187
188  virtual bool IsSignInContinueUrl(const GURL& url) const OVERRIDE {
189    return true;
190  }
191
192 private:
193  // To specify our own metric logger.
194  virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE {
195    return metric_logger_;
196  }
197
198  const AutofillMetrics& metric_logger_;
199  TestPersonalDataManager test_manager_;
200  testing::NiceMock<wallet::MockWalletClient> mock_wallet_client_;
201  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
202  bool use_validation_;
203
204  // A list of notifications to show in the notification area of the dialog.
205  // This is used to control what |CurrentNotifications()| returns for testing.
206  std::vector<DialogNotification> notifications_;
207
208  // Allows generation of WeakPtrs, so controller liveness can be tested.
209  base::WeakPtrFactory<TestAutofillDialogController> weak_ptr_factory_;
210
211  DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController);
212};
213
214}  // namespace
215
216class AutofillDialogControllerTest : public InProcessBrowserTest {
217 public:
218  AutofillDialogControllerTest() {}
219  virtual ~AutofillDialogControllerTest() {}
220
221  virtual void SetUpOnMainThread() OVERRIDE {
222    autofill::test::DisableSystemServices(browser()->profile());
223    InitializeController();
224  }
225
226  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
227#if defined(OS_MACOSX)
228    // OSX support for requestAutocomplete is still hidden behind a switch.
229    // Pending resolution of http://crbug.com/157274
230    CommandLine::ForCurrentProcess()->AppendSwitch(
231        switches::kEnableInteractiveAutocomplete);
232#endif
233  }
234
235  void InitializeController() {
236    FormData form;
237    form.name = ASCIIToUTF16("TestForm");
238    form.method = ASCIIToUTF16("POST");
239    form.origin = GURL("http://example.com/form.html");
240    form.action = GURL("http://example.com/submit.html");
241    form.user_submitted = true;
242
243    FormFieldData field;
244    field.autocomplete_attribute = "shipping tel";
245    form.fields.push_back(field);
246
247    test_generated_bubble_controller_ =
248        new testing::NiceMock<TestGeneratedCreditCardBubbleController>(
249            GetActiveWebContents());
250    ASSERT_TRUE(test_generated_bubble_controller_->IsInstalled());
251
252    message_loop_runner_ = new content::MessageLoopRunner;
253    controller_ = new TestAutofillDialogController(
254        GetActiveWebContents(),
255        form,
256        metric_logger_,
257        message_loop_runner_);
258    controller_->Show();
259  }
260
261  content::WebContents* GetActiveWebContents() {
262    return browser()->tab_strip_model()->GetActiveWebContents();
263  }
264
265  const MockAutofillMetrics& metric_logger() { return metric_logger_; }
266  TestAutofillDialogController* controller() { return controller_; }
267
268  void RunMessageLoop() {
269    message_loop_runner_->Run();
270  }
271
272  // Loads an HTML page in |GetActiveWebContents()| with markup as follows:
273  // <form>|form_inner_html|</form>. After loading, emulates a click event on
274  // the page as requestAutocomplete() must be in response to a user gesture.
275  // Returns the |AutofillDialogControllerImpl| created by this invocation.
276  AutofillDialogControllerImpl* SetUpHtmlAndInvoke(
277      const std::string& form_inner_html) {
278    content::WebContents* contents = GetActiveWebContents();
279    TabAutofillManagerDelegate* delegate =
280        TabAutofillManagerDelegate::FromWebContents(contents);
281    DCHECK(!delegate->GetDialogControllerForTesting());
282
283    ui_test_utils::NavigateToURL(
284        browser(), GURL(std::string("data:text/html,") +
285        "<!doctype html>"
286        "<html>"
287          "<body>"
288            "<form>" + form_inner_html + "</form>"
289            "<script>"
290              "function send(msg) {"
291                "domAutomationController.setAutomationId(0);"
292                "domAutomationController.send(msg);"
293              "}"
294              "document.forms[0].onautocompleteerror = function(e) {"
295                "send('error: ' + e.reason);"
296              "};"
297              "document.forms[0].onautocomplete = function() {"
298                "send('success');"
299              "};"
300              "window.onclick = function() {"
301                "document.forms[0].requestAutocomplete();"
302                "send('clicked');"
303              "};"
304              "function getValueForFieldOfType(type) {"
305              "  var fields = document.getElementsByTagName('input');"
306              "  for (var i = 0; i < fields.length; i++) {"
307              "    if (fields[i].autocomplete == type) {"
308              "      send(fields[i].value);"
309              "      return;"
310              "    }"
311              "  }"
312              "  send('');"
313              "};"
314            "</script>"
315          "</body>"
316        "</html>"));
317    content::WaitForLoadStop(contents);
318
319    dom_message_queue_.reset(new content::DOMMessageQueue);
320
321    // Triggers the onclick handler which invokes requestAutocomplete().
322    content::SimulateMouseClick(contents, 0, WebKit::WebMouseEvent::ButtonLeft);
323    ExpectDomMessage("clicked");
324
325    AutofillDialogControllerImpl* controller =
326        static_cast<AutofillDialogControllerImpl*>(
327            delegate->GetDialogControllerForTesting());
328    DCHECK(controller);
329    return controller;
330  }
331
332  // Wait for a message from the DOM automation controller (from JS in the
333  // page). Requires |SetUpHtmlAndInvoke()| be called first.
334  void ExpectDomMessage(const std::string& expected) {
335    std::string message;
336    ASSERT_TRUE(dom_message_queue_->WaitForMessage(&message));
337    dom_message_queue_->ClearQueue();
338    EXPECT_EQ("\"" + expected + "\"", message);
339  }
340
341  // Returns the value filled into the first field with autocomplete attribute
342  // equal to |autocomplete_type|, or an empty string if there is no such field.
343  std::string GetValueForHTMLFieldOfType(const std::string& autocomplete_type) {
344    content::RenderViewHost* render_view_host =
345        browser()->tab_strip_model()->GetActiveWebContents()->
346        GetRenderViewHost();
347    std::string script = "getValueForFieldOfType('" + autocomplete_type + "');";
348    std::string result;
349    EXPECT_TRUE(content::ExecuteScriptAndExtractString(render_view_host, script,
350                                                       &result));
351    return result;
352  }
353
354  void AddCreditcardToProfile(Profile* profile, const CreditCard& card) {
355    PersonalDataManagerFactory::GetForProfile(profile)->AddCreditCard(card);
356    WaitForWebDB();
357  }
358
359  void AddAutofillProfileToProfile(Profile* profile,
360                                   const AutofillProfile& autofill_profile) {
361    PersonalDataManagerFactory::GetForProfile(profile)->AddProfile(
362        autofill_profile);
363    WaitForWebDB();
364  }
365
366  TestGeneratedCreditCardBubbleController* test_generated_bubble_controller() {
367    return test_generated_bubble_controller_;
368  }
369
370 private:
371  void WaitForWebDB() {
372    content::RunAllPendingInMessageLoop(content::BrowserThread::DB);
373  }
374
375  testing::NiceMock<MockAutofillMetrics> metric_logger_;
376  TestAutofillDialogController* controller_;  // Weak reference.
377  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
378  scoped_ptr<content::DOMMessageQueue> dom_message_queue_;
379
380  // Weak; owned by the active web contents.
381  TestGeneratedCreditCardBubbleController* test_generated_bubble_controller_;
382
383  DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerTest);
384};
385
386#if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
387// Submit the form data.
388IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Submit) {
389  controller()->GetTestableView()->SubmitForTesting();
390
391  RunMessageLoop();
392
393  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
394            metric_logger().dialog_dismissal_action());
395}
396
397// Cancel out of the dialog.
398IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Cancel) {
399  controller()->GetTestableView()->CancelForTesting();
400
401  RunMessageLoop();
402
403  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
404            metric_logger().dialog_dismissal_action());
405}
406
407// Take some other action that dismisses the dialog.
408IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Hide) {
409  controller()->Hide();
410
411  RunMessageLoop();
412
413  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
414            metric_logger().dialog_dismissal_action());
415}
416
417// Ensure that Hide() will only destroy the controller object after the
418// message loop has run. Otherwise, there may be read-after-free issues
419// during some tests.
420IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, DeferredDestruction) {
421  base::WeakPtr<TestAutofillDialogController> weak_ptr =
422      controller()->AsWeakPtr();
423  EXPECT_TRUE(weak_ptr.get());
424
425  controller()->Hide();
426  EXPECT_TRUE(weak_ptr.get());
427
428  RunMessageLoop();
429  EXPECT_FALSE(weak_ptr.get());
430}
431
432// Ensure that the expected metric is logged when the dialog is closed during
433// signin.
434IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, CloseDuringSignin) {
435  controller()->SignInLinkClicked();
436
437  EXPECT_CALL(metric_logger(),
438              LogDialogDismissalState(
439                  AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN));
440  controller()->GetTestableView()->CancelForTesting();
441
442  RunMessageLoop();
443
444  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
445            metric_logger().dialog_dismissal_action());
446}
447
448IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, FillInputFromAutofill) {
449  AutofillProfile full_profile(test::GetFullProfile());
450  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
451
452  const DetailInputs& inputs =
453      controller()->RequestedFieldsForSection(SECTION_SHIPPING);
454  const DetailInput& triggering_input = inputs[0];
455  string16 value = full_profile.GetRawInfo(triggering_input.type);
456  TestableAutofillDialogView* view = controller()->GetTestableView();
457  view->SetTextContentsOfInput(triggering_input,
458                               value.substr(0, value.size() / 2));
459  view->ActivateInput(triggering_input);
460
461  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
462  controller()->DidAcceptSuggestion(string16(), 0);
463
464  // All inputs should be filled.
465  AutofillProfileWrapper wrapper(&full_profile);
466  for (size_t i = 0; i < inputs.size(); ++i) {
467    EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)),
468              view->GetTextContentsOfInput(inputs[i]));
469  }
470
471  // Now simulate some user edits and try again.
472  std::vector<string16> expectations;
473  for (size_t i = 0; i < inputs.size(); ++i) {
474    string16 users_input = i % 2 == 0 ? string16() : ASCIIToUTF16("dummy");
475    view->SetTextContentsOfInput(inputs[i], users_input);
476    // Empty inputs should be filled, others should be left alone.
477    string16 expectation =
478        &inputs[i] == &triggering_input || users_input.empty() ?
479        wrapper.GetInfo(AutofillType(inputs[i].type)) :
480        users_input;
481    expectations.push_back(expectation);
482  }
483
484  view->SetTextContentsOfInput(triggering_input,
485                               value.substr(0, value.size() / 2));
486  view->ActivateInput(triggering_input);
487  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
488  controller()->DidAcceptSuggestion(string16(), 0);
489
490  for (size_t i = 0; i < inputs.size(); ++i) {
491    EXPECT_EQ(expectations[i], view->GetTextContentsOfInput(inputs[i]));
492  }
493}
494
495// This test makes sure that picking a profile variant in the Autofill
496// popup works as expected.
497IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
498                       FillInputFromAutofillVariant) {
499  AutofillProfile full_profile(test::GetFullProfile());
500
501  // Set up some variant data.
502  std::vector<string16> names;
503  names.push_back(ASCIIToUTF16("John Doe"));
504  names.push_back(ASCIIToUTF16("Jane Doe"));
505  full_profile.SetRawMultiInfo(NAME_FULL, names);
506  std::vector<string16> emails;
507  emails.push_back(ASCIIToUTF16("user@example.com"));
508  emails.push_back(ASCIIToUTF16("admin@example.com"));
509  full_profile.SetRawMultiInfo(EMAIL_ADDRESS, emails);
510  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
511
512  const DetailInputs& inputs =
513      controller()->RequestedFieldsForSection(SECTION_BILLING);
514  const DetailInput& triggering_input = inputs[0];
515  EXPECT_EQ(NAME_BILLING_FULL, triggering_input.type);
516  TestableAutofillDialogView* view = controller()->GetTestableView();
517  view->ActivateInput(triggering_input);
518
519  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
520
521  // Choose the variant suggestion.
522  controller()->DidAcceptSuggestion(string16(), 1);
523
524  // All inputs should be filled.
525  AutofillProfileWrapper wrapper(
526      &full_profile, AutofillType(NAME_BILLING_FULL), 1);
527  for (size_t i = 0; i < inputs.size(); ++i) {
528    EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)),
529              view->GetTextContentsOfInput(inputs[i]));
530  }
531
532  // Make sure the wrapper applies the variant index to the right group.
533  EXPECT_EQ(names[1], wrapper.GetInfo(AutofillType(NAME_BILLING_FULL)));
534  // Make sure the wrapper doesn't apply the variant index to the wrong group.
535  EXPECT_EQ(emails[0], wrapper.GetInfo(AutofillType(EMAIL_ADDRESS)));
536}
537
538// Tests that changing the value of a CC expiration date combobox works as
539// expected when Autofill is used to fill text inputs.
540//
541// Flaky on Win7, WinXP, and Win Aura.  http://crbug.com/270314.
542#if defined(OS_WIN)
543#define MAYBE_FillComboboxFromAutofill DISABLED_FillComboboxFromAutofill
544#else
545#define MAYBE_FillComboboxFromAutofill FillComboboxFromAutofill
546#endif
547IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
548                       MAYBE_FillComboboxFromAutofill) {
549  CreditCard card1;
550  test::SetCreditCardInfo(&card1, "JJ Smith", "4111111111111111", "12", "2018");
551  controller()->GetTestingManager()->AddTestingCreditCard(&card1);
552  CreditCard card2;
553  test::SetCreditCardInfo(&card2, "B Bird", "3111111111111111", "11", "2017");
554  controller()->GetTestingManager()->AddTestingCreditCard(&card2);
555  AutofillProfile full_profile(test::GetFullProfile());
556  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
557
558  const DetailInputs& inputs =
559      controller()->RequestedFieldsForSection(SECTION_CC);
560  const DetailInput& triggering_input = inputs[0];
561  string16 value = card1.GetRawInfo(triggering_input.type);
562  TestableAutofillDialogView* view = controller()->GetTestableView();
563  view->SetTextContentsOfInput(triggering_input,
564                               value.substr(0, value.size() / 2));
565  view->ActivateInput(triggering_input);
566
567  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
568  controller()->DidAcceptSuggestion(string16(), 0);
569
570  // All inputs should be filled.
571  AutofillCreditCardWrapper wrapper1(&card1);
572  for (size_t i = 0; i < inputs.size(); ++i) {
573    EXPECT_EQ(wrapper1.GetInfo(AutofillType(inputs[i].type)),
574              view->GetTextContentsOfInput(inputs[i]));
575  }
576
577  // Try again with different data. Only expiration date and the triggering
578  // input should be overwritten.
579  value = card2.GetRawInfo(triggering_input.type);
580  view->SetTextContentsOfInput(triggering_input,
581                               value.substr(0, value.size() / 2));
582  view->ActivateInput(triggering_input);
583  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
584  controller()->DidAcceptSuggestion(string16(), 0);
585
586  AutofillCreditCardWrapper wrapper2(&card2);
587  for (size_t i = 0; i < inputs.size(); ++i) {
588    const DetailInput& input = inputs[i];
589    if (&input == &triggering_input ||
590        input.type == CREDIT_CARD_EXP_MONTH ||
591        input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
592      EXPECT_EQ(wrapper2.GetInfo(AutofillType(input.type)),
593                view->GetTextContentsOfInput(input));
594    } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) {
595      EXPECT_TRUE(view->GetTextContentsOfInput(input).empty());
596    } else {
597      EXPECT_EQ(wrapper1.GetInfo(AutofillType(input.type)),
598                view->GetTextContentsOfInput(input));
599    }
600  }
601
602  // Now fill from a profile. It should not overwrite any CC info.
603  const DetailInputs& billing_inputs =
604      controller()->RequestedFieldsForSection(SECTION_BILLING);
605  const DetailInput& billing_triggering_input = billing_inputs[0];
606  value = full_profile.GetRawInfo(triggering_input.type);
607  view->SetTextContentsOfInput(billing_triggering_input,
608                               value.substr(0, value.size() / 2));
609  view->ActivateInput(billing_triggering_input);
610
611  ASSERT_EQ(&billing_triggering_input, controller()->input_showing_popup());
612  controller()->DidAcceptSuggestion(string16(), 0);
613
614  for (size_t i = 0; i < inputs.size(); ++i) {
615    const DetailInput& input = inputs[i];
616    if (&input == &triggering_input ||
617        input.type == CREDIT_CARD_EXP_MONTH ||
618        input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
619      EXPECT_EQ(wrapper2.GetInfo(AutofillType(input.type)),
620                view->GetTextContentsOfInput(input));
621    } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) {
622      EXPECT_TRUE(view->GetTextContentsOfInput(input).empty());
623    } else {
624      EXPECT_EQ(wrapper1.GetInfo(AutofillType(input.type)),
625                view->GetTextContentsOfInput(input));
626    }
627  }
628}
629
630IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ShouldShowErrorBubble) {
631  EXPECT_TRUE(controller()->ShouldShowErrorBubble());
632
633  CreditCard card(test::GetCreditCard());
634  ASSERT_FALSE(card.IsVerified());
635  controller()->GetTestingManager()->AddTestingCreditCard(&card);
636
637  const DetailInputs& cc_inputs =
638      controller()->RequestedFieldsForSection(SECTION_CC);
639  const DetailInput& cc_number_input = cc_inputs[0];
640  ASSERT_EQ(CREDIT_CARD_NUMBER, cc_number_input.type);
641
642  TestableAutofillDialogView* view = controller()->GetTestableView();
643  view->SetTextContentsOfInput(
644      cc_number_input,
645      card.GetRawInfo(CREDIT_CARD_NUMBER).substr(0, 1));
646
647  view->ActivateInput(cc_number_input);
648  EXPECT_FALSE(controller()->ShouldShowErrorBubble());
649
650  controller()->FocusMoved();
651  EXPECT_TRUE(controller()->ShouldShowErrorBubble());
652}
653
654// Ensure that expired cards trigger invalid suggestions.
655IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ExpiredCard) {
656  CreditCard verified_card(test::GetCreditCard());
657  verified_card.set_origin("Chrome settings");
658  ASSERT_TRUE(verified_card.IsVerified());
659  controller()->GetTestingManager()->AddTestingCreditCard(&verified_card);
660
661  CreditCard expired_card(test::GetCreditCard());
662  expired_card.set_origin("Chrome settings");
663  expired_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2007"));
664  ASSERT_TRUE(expired_card.IsVerified());
665  ASSERT_FALSE(
666      autofill::IsValidCreditCardExpirationDate(
667          expired_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR),
668          expired_card.GetRawInfo(CREDIT_CARD_EXP_MONTH),
669          base::Time::Now()));
670  controller()->GetTestingManager()->AddTestingCreditCard(&expired_card);
671
672  ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC);
673  ASSERT_EQ(4, model->GetItemCount());
674
675  ASSERT_TRUE(model->IsItemCheckedAt(0));
676  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));
677
678  model->ActivatedAt(1);
679  ASSERT_TRUE(model->IsItemCheckedAt(1));
680  EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC));
681}
682
683// Notifications with long message text should not make the dialog bigger.
684IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, LongNotifications) {
685  const gfx::Size no_notification_size =
686      controller()->GetTestableView()->GetSize();
687  ASSERT_GT(no_notification_size.width(), 0);
688
689  std::vector<DialogNotification> notifications;
690  notifications.push_back(
691      DialogNotification(DialogNotification::DEVELOPER_WARNING, ASCIIToUTF16(
692          "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
693          "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim "
694          "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut "
695          "aliquip ex ea commodo consequat. Duis aute irure dolor in "
696          "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
697          "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
698          "culpa qui officia deserunt mollit anim id est laborum.")));
699  controller()->set_notifications(notifications);
700  controller()->view()->UpdateNotificationArea();
701
702  EXPECT_EQ(no_notification_size.width(),
703            controller()->GetTestableView()->GetSize().width());
704}
705
706IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocompleteEvent) {
707  AutofillDialogControllerImpl* controller =
708      SetUpHtmlAndInvoke("<input autocomplete='cc-name'>");
709
710  AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard());
711  AddAutofillProfileToProfile(controller->profile(),
712                              test::GetVerifiedProfile());
713
714  TestableAutofillDialogView* view = controller->GetTestableView();
715  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
716  view->SubmitForTesting();
717  ExpectDomMessage("success");
718}
719
720IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
721                       AutocompleteErrorEventReasonInvalid) {
722  AutofillDialogControllerImpl* controller =
723      SetUpHtmlAndInvoke("<input autocomplete='cc-name' pattern='.*zebra.*'>");
724
725  const CreditCard& credit_card = test::GetVerifiedCreditCard();
726  ASSERT_TRUE(
727    credit_card.GetRawInfo(CREDIT_CARD_NAME).find(ASCIIToUTF16("zebra")) ==
728        base::string16::npos);
729  AddCreditcardToProfile(controller->profile(), credit_card);
730  AddAutofillProfileToProfile(controller->profile(),
731                              test::GetVerifiedProfile());
732
733  TestableAutofillDialogView* view = controller->GetTestableView();
734  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
735  view->SubmitForTesting();
736  ExpectDomMessage("error: invalid");
737}
738
739IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
740                       AutocompleteErrorEventReasonCancel) {
741  SetUpHtmlAndInvoke("<input autocomplete='cc-name'>")->GetTestableView()->
742      CancelForTesting();
743  ExpectDomMessage("error: cancel");
744}
745
746IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, NoCvcSegfault) {
747  controller()->set_use_validation(true);
748
749  CreditCard credit_card(test::GetVerifiedCreditCard());
750  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
751  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));
752
753  ASSERT_NO_FATAL_FAILURE(
754      controller()->GetTestableView()->SubmitForTesting());
755}
756
757// Flaky on Win7, WinXP, and Win Aura.  http://crbug.com/270314.
758#if defined(OS_WIN)
759#define MAYBE_PreservedSections DISABLED_PreservedSections
760#else
761#define MAYBE_PreservedSections PreservedSections
762#endif
763IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_PreservedSections) {
764  controller()->set_use_validation(true);
765
766  // Set up some Autofill state.
767  CreditCard credit_card(test::GetVerifiedCreditCard());
768  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
769
770  AutofillProfile profile(test::GetVerifiedProfile());
771  controller()->GetTestingManager()->AddTestingProfile(&profile);
772
773  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC));
774  EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING));
775  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING));
776  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
777
778  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC));
779  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
780  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
781
782  // Set up some Wallet state.
783  std::vector<std::string> usernames;
784  usernames.push_back("user@example.com");
785  controller()->OnUserNameFetchSuccess(usernames);
786  controller()->OnDidFetchWalletCookieValue(std::string());
787  controller()->OnDidGetWalletItems(
788      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
789
790  ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser();
791  ASSERT_TRUE(account_chooser->IsItemCheckedAt(0));
792
793  // Check that the view's in the state we expect before starting to simulate
794  // user input.
795  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC));
796  EXPECT_FALSE(controller()->SectionIsActive(SECTION_BILLING));
797  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
798  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
799
800  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC_BILLING));
801
802  // Create some valid inputted billing data.
803  const DetailInput& cc_number =
804      controller()->RequestedFieldsForSection(SECTION_CC_BILLING)[0];
805  EXPECT_EQ(CREDIT_CARD_NUMBER, cc_number.type);
806  TestableAutofillDialogView* view = controller()->GetTestableView();
807  view->SetTextContentsOfInput(cc_number, ASCIIToUTF16("4111111111111111"));
808
809  // Select "Add new shipping info..." from suggestions menu.
810  ui::MenuModel* shipping_model =
811      controller()->MenuModelForSection(SECTION_SHIPPING);
812  shipping_model->ActivatedAt(shipping_model->GetItemCount() - 2);
813
814  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
815
816  // Create some invalid, manually inputted shipping data.
817  const DetailInput& shipping_zip =
818      controller()->RequestedFieldsForSection(SECTION_SHIPPING)[5];
819  ASSERT_EQ(ADDRESS_HOME_ZIP, shipping_zip.type);
820  view->SetTextContentsOfInput(shipping_zip, ASCIIToUTF16("shipping zip"));
821
822  // Switch to using Autofill.
823  account_chooser->ActivatedAt(1);
824
825  // Check that appropriate sections are preserved and in manually editing mode
826  // (or disabled, in the case of the combined cc + billing section).
827  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC));
828  EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING));
829  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING));
830  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
831
832  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC));
833  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
834  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
835
836  const DetailInput& new_cc_number =
837      controller()->RequestedFieldsForSection(SECTION_CC).front();
838  EXPECT_EQ(cc_number.type, new_cc_number.type);
839  EXPECT_EQ(ASCIIToUTF16("4111111111111111"),
840            view->GetTextContentsOfInput(new_cc_number));
841
842  EXPECT_NE(ASCIIToUTF16("shipping name"),
843            view->GetTextContentsOfInput(shipping_zip));
844}
845#endif  // defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
846
847IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
848                       GeneratedCardLastFourAfterVerifyCvv) {
849  std::vector<std::string> usernames(1, "user@example.com");
850  controller()->OnUserNameFetchSuccess(usernames);
851  controller()->OnDidFetchWalletCookieValue(std::string());
852
853  scoped_ptr<wallet::WalletItems> wallet_items =
854      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
855  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
856  wallet_items->AddAddress(wallet::GetTestShippingAddress());
857
858  base::string16 last_four =
859      wallet_items->instruments()[0]->TypeAndLastFourDigits();
860  controller()->OnDidGetWalletItems(wallet_items.Pass());
861
862  TestableAutofillDialogView* test_view = controller()->GetTestableView();
863  EXPECT_FALSE(test_view->IsShowingOverlay());
864  EXPECT_CALL(*controller(), LoadRiskFingerprintData());
865  controller()->OnAccept();
866  EXPECT_TRUE(test_view->IsShowingOverlay());
867
868  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
869  scoped_ptr<risk::Fingerprint> fingerprint(new risk::Fingerprint());
870  fingerprint->mutable_machine_characteristics()->mutable_screen_size()->
871      set_width(1024);
872  controller()->OnDidLoadRiskFingerprintData(fingerprint.Pass());
873
874  controller()->OnDidGetFullWallet(
875      wallet::GetTestFullWalletWithRequiredActions(
876          std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV)));
877
878  ASSERT_TRUE(controller()->IsSubmitPausedOn(wallet::VERIFY_CVV));
879
880  std::string fake_cvc("123");
881  test_view->SetTextContentsOfSuggestionInput(SECTION_CC_BILLING,
882                                              ASCIIToUTF16(fake_cvc));
883
884  EXPECT_FALSE(test_view->IsShowingOverlay());
885  EXPECT_CALL(*controller()->GetTestingWalletClient(),
886              AuthenticateInstrument(_, fake_cvc));
887  controller()->OnAccept();
888  EXPECT_TRUE(test_view->IsShowingOverlay());
889
890  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
891  controller()->OnDidAuthenticateInstrument(true);
892  controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
893  controller()->ForceFinishSubmit();
894
895  RunMessageLoop();
896
897  EXPECT_EQ(1, test_generated_bubble_controller()->bubbles_shown());
898  EXPECT_EQ(last_four, test_generated_bubble_controller()->backing_card_name());
899}
900
901// See http://crbug.com/314627
902#if defined(OS_WIN)
903#define MAYBE_SignInNoCrash DISABLED_SignInNoCrash
904#else
905#define MAYBE_SignInNoCrash SignInNoCrash
906#endif
907
908// Simulates the user successfully signing in to the dialog for the first time.
909// The controller listens for nav entry commits and should not destroy the web
910// contents before its post load code runs (which would cause a crash).
911IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_SignInNoCrash) {
912  browser()->profile()->GetPrefs()->SetBoolean(
913      ::prefs::kAutofillDialogPayWithoutWallet,
914      true);
915
916  InitializeController();
917
918  const AccountChooserModel& account_chooser_model =
919      controller()->AccountChooserModelForTesting();
920  EXPECT_FALSE(account_chooser_model.WalletIsSelected());
921
922  ui_test_utils::UrlLoadObserver observer(
923      controller()->SignInUrl(),
924      content::NotificationService::AllSources());
925
926  controller()->SignInLinkClicked();
927  std::vector<std::string> usernames(1, "user@example.com");
928  controller()->OnUserNameFetchSuccess(usernames);
929  controller()->OnDidFetchWalletCookieValue(std::string());
930  controller()->OnDidGetWalletItems(
931      wallet::GetTestWalletItemsWithRequiredAction(wallet::GAIA_AUTH));
932
933  TestableAutofillDialogView* view = controller()->GetTestableView();
934  EXPECT_TRUE(view->GetSignInWebContents());
935  EXPECT_TRUE(controller()->ShouldShowSignInWebView());
936  observer.Wait();
937
938  // Wallet should now be selected and Chrome shouldn't have crashed.
939  EXPECT_TRUE(account_chooser_model.WalletIsSelected());
940}
941
942// Verify that filling a form works correctly, including filling the CVC when
943// that is requested separately.
944IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, FillFormIncludesCVC) {
945  AutofillDialogControllerImpl* controller =
946      SetUpHtmlAndInvoke("<input autocomplete='cc-csc'>");
947
948  AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard());
949  AddAutofillProfileToProfile(controller->profile(),
950                              test::GetVerifiedProfile());
951
952  TestableAutofillDialogView* view = controller->GetTestableView();
953  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
954  view->SubmitForTesting();
955  ExpectDomMessage("success");
956  EXPECT_EQ("123", GetValueForHTMLFieldOfType("cc-csc"));
957}
958
959}  // namespace autofill
960