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