autofill_dialog_controller_unittest.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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/guid.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/message_loop.h"
8#include "base/prefs/pref_service.h"
9#include "base/utf_string_conversions.h"
10#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
11#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
12#include "chrome/common/pref_names.h"
13#include "chrome/test/base/testing_profile.h"
14#include "components/autofill/browser/autofill_common_test.h"
15#include "components/autofill/browser/autofill_metrics.h"
16#include "components/autofill/browser/test_personal_data_manager.h"
17#include "components/autofill/browser/wallet/full_wallet.h"
18#include "components/autofill/browser/wallet/instrument.h"
19#include "components/autofill/browser/wallet/wallet_address.h"
20#include "components/autofill/browser/wallet/wallet_client.h"
21#include "components/autofill/browser/wallet/wallet_test_util.h"
22#include "components/autofill/common/form_data.h"
23#include "content/public/browser/web_contents.h"
24#include "content/public/test/test_browser_thread.h"
25#include "content/public/test/web_contents_tester.h"
26#include "testing/gmock/include/gmock/gmock.h"
27#include "testing/gtest/include/gtest/gtest.h"
28
29#if defined(OS_WIN)
30#include "ui/base/win/scoped_ole_initializer.h"
31#endif
32
33using testing::_;
34
35namespace autofill {
36
37namespace {
38
39const char kFakeEmail[] = "user@example.com";
40const char* kFieldsFromPage[] = { "email", "cc-number", "billing region",
41  "shipping region" };
42const char kSettingsOrigin[] = "Chrome settings";
43
44using content::BrowserThread;
45
46class TestAutofillDialogView : public AutofillDialogView {
47 public:
48  TestAutofillDialogView() {}
49  virtual ~TestAutofillDialogView() {}
50
51  virtual void Show() OVERRIDE {}
52  virtual void Hide() OVERRIDE {}
53  virtual void UpdateNotificationArea() OVERRIDE {}
54  virtual void UpdateAccountChooser() OVERRIDE {}
55  virtual void UpdateButtonStrip() OVERRIDE {}
56  virtual void UpdateDetailArea() OVERRIDE {}
57  virtual void UpdateSection(DialogSection section) OVERRIDE {}
58  virtual void FillSection(DialogSection section,
59                           const DetailInput& originating_input) OVERRIDE {};
60  virtual void GetUserInput(DialogSection section, DetailOutputMap* output)
61      OVERRIDE {
62    *output = outputs_[section];
63  }
64
65  virtual string16 GetCvc() OVERRIDE { return string16(); }
66  virtual bool SaveDetailsLocally() OVERRIDE { return true; }
67  virtual const content::NavigationController* ShowSignIn() OVERRIDE {
68    return NULL;
69  }
70  virtual void HideSignIn() OVERRIDE {}
71  virtual void UpdateProgressBar(double value) OVERRIDE {}
72
73  MOCK_METHOD0(ModelChanged, void());
74
75  void SetUserInput(DialogSection section, const DetailOutputMap& map) {
76    outputs_[section] = map;
77  }
78
79 private:
80  std::map<DialogSection, DetailOutputMap> outputs_;
81
82  DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogView);
83};
84
85class TestWalletClient : public wallet::WalletClient {
86 public:
87  TestWalletClient(net::URLRequestContextGetter* context,
88                   wallet::WalletClientDelegate* delegate)
89      : wallet::WalletClient(context, delegate) {}
90  virtual ~TestWalletClient() {}
91
92  MOCK_METHOD3(AcceptLegalDocuments,
93      void(const std::vector<wallet::WalletItems::LegalDocument*>& documents,
94           const std::string& google_transaction_id,
95           const GURL& source_url));
96
97  MOCK_METHOD3(AuthenticateInstrument,
98      void(const std::string& instrument_id,
99           const std::string& card_verification_number,
100           const std::string& obfuscated_gaia_id));
101
102  MOCK_METHOD1(GetFullWallet,
103      void(const wallet::WalletClient::FullWalletRequest& request));
104
105  MOCK_METHOD2(SaveAddress,
106      void(const wallet::Address& address, const GURL& source_url));
107
108  MOCK_METHOD3(SaveInstrument,
109      void(const wallet::Instrument& instrument,
110           const std::string& obfuscated_gaia_id,
111           const GURL& source_url));
112
113  MOCK_METHOD4(SaveInstrumentAndAddress,
114      void(const wallet::Instrument& instrument,
115           const wallet::Address& address,
116           const std::string& obfuscated_gaia_id,
117           const GURL& source_url));
118
119 private:
120  DISALLOW_COPY_AND_ASSIGN(TestWalletClient);
121};
122
123// Bring over command-ids from AccountChooserModel.
124class TestAccountChooserModel : public AccountChooserModel {
125 public:
126  TestAccountChooserModel(AccountChooserModelDelegate* delegate,
127                          PrefService* prefs,
128                          const AutofillMetrics& metric_logger)
129      : AccountChooserModel(delegate, prefs, metric_logger,
130                            DIALOG_TYPE_REQUEST_AUTOCOMPLETE) {}
131  virtual ~TestAccountChooserModel() {}
132
133  using AccountChooserModel::kActiveWalletItemId;
134  using AccountChooserModel::kAutofillItemId;
135
136 private:
137  DISALLOW_COPY_AND_ASSIGN(TestAccountChooserModel);
138};
139
140class TestAutofillDialogController
141    : public AutofillDialogControllerImpl,
142      public base::SupportsWeakPtr<TestAutofillDialogController> {
143 public:
144  TestAutofillDialogController(
145      content::WebContents* contents,
146      const FormData& form_structure,
147      const GURL& source_url,
148      const AutofillMetrics& metric_logger,
149      const DialogType dialog_type,
150      const base::Callback<void(const FormStructure*,
151                                const std::string&)>& callback)
152      : AutofillDialogControllerImpl(contents,
153                                     form_structure,
154                                     source_url,
155                                     dialog_type,
156                                     callback),
157        metric_logger_(metric_logger),
158        test_wallet_client_(
159            Profile::FromBrowserContext(contents->GetBrowserContext())->
160                GetRequestContext(), this),
161        is_first_run_(true) {}
162  virtual ~TestAutofillDialogController() {}
163
164  virtual AutofillDialogView* CreateView() OVERRIDE {
165    return new testing::NiceMock<TestAutofillDialogView>();
166  }
167
168  void Init(content::BrowserContext* browser_context) {
169    test_manager_.Init(browser_context);
170  }
171
172  TestAutofillDialogView* GetView() {
173    return static_cast<TestAutofillDialogView*>(view());
174  }
175
176  TestPersonalDataManager* GetTestingManager() {
177    return &test_manager_;
178  }
179
180  TestWalletClient* GetTestingWalletClient() {
181    return &test_wallet_client_;
182  }
183
184  void set_is_first_run(bool is_first_run) { is_first_run_ = is_first_run; }
185
186  const GURL& open_tab_url() { return open_tab_url_; }
187
188 protected:
189  virtual PersonalDataManager* GetManager() OVERRIDE {
190    return &test_manager_;
191  }
192
193  virtual wallet::WalletClient* GetWalletClient() OVERRIDE {
194    return &test_wallet_client_;
195  }
196
197  virtual bool IsFirstRun() const OVERRIDE {
198    return is_first_run_;
199  }
200
201  virtual void OpenTabWithUrl(const GURL& url) OVERRIDE {
202    open_tab_url_ = url;
203  }
204
205 private:
206  // To specify our own metric logger.
207  virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE {
208    return metric_logger_;
209  }
210
211  const AutofillMetrics& metric_logger_;
212  TestPersonalDataManager test_manager_;
213  testing::NiceMock<TestWalletClient> test_wallet_client_;
214  bool is_first_run_;
215  GURL open_tab_url_;
216
217  DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController);
218};
219
220class AutofillDialogControllerTest : public testing::Test {
221 public:
222  AutofillDialogControllerTest()
223    : ui_thread_(BrowserThread::UI, &loop_),
224      file_thread_(BrowserThread::FILE),
225      file_blocking_thread_(BrowserThread::FILE_USER_BLOCKING),
226      io_thread_(BrowserThread::IO) {
227    file_thread_.Start();
228    file_blocking_thread_.Start();
229    io_thread_.StartIOThread();
230  }
231
232  virtual ~AutofillDialogControllerTest() {}
233
234  // testing::Test implementation:
235  virtual void SetUp() OVERRIDE {
236    FormData form_data;
237    for (size_t i = 0; i < arraysize(kFieldsFromPage); ++i) {
238      FormFieldData field;
239      field.autocomplete_attribute = kFieldsFromPage[i];
240      form_data.fields.push_back(field);
241    }
242
243    profile()->CreateRequestContext();
244    test_web_contents_.reset(
245        content::WebContentsTester::CreateTestWebContents(profile(), NULL));
246
247    base::Callback<void(const FormStructure*, const std::string&)> callback =
248        base::Bind(&AutofillDialogControllerTest::FinishedCallback,
249                   base::Unretained(this));
250    controller_ = (new TestAutofillDialogController(
251        test_web_contents_.get(),
252        form_data,
253        GURL(),
254        metric_logger_,
255        DIALOG_TYPE_REQUEST_AUTOCOMPLETE,
256        callback))->AsWeakPtr();
257    controller_->Init(profile());
258    controller_->Show();
259    controller_->OnUserNameFetchSuccess(kFakeEmail);
260  }
261
262  virtual void TearDown() OVERRIDE {
263    if (controller_)
264      controller_->ViewClosed();
265  }
266
267 protected:
268  static scoped_ptr<wallet::FullWallet> CreateFullWalletWithVerifyCvv() {
269    base::DictionaryValue dict;
270    scoped_ptr<base::ListValue> list(new base::ListValue());
271    list->AppendString("verify_cvv");
272    dict.Set("required_action", list.release());
273    return wallet::FullWallet::CreateFullWallet(dict);
274  }
275
276  void FillCreditCardInputs() {
277    DetailOutputMap cc_outputs;
278    const DetailInputs& cc_inputs =
279        controller()->RequestedFieldsForSection(SECTION_CC);
280    for (size_t i = 0; i < cc_inputs.size(); ++i) {
281      cc_outputs[&cc_inputs[i]] = ASCIIToUTF16("11");
282    }
283    controller()->GetView()->SetUserInput(SECTION_CC, cc_outputs);
284  }
285
286  std::vector<DialogNotification> NotificationsOfType(
287      DialogNotification::Type type) {
288    std::vector<DialogNotification> right_type;
289    const std::vector<DialogNotification>& notifications =
290        controller()->CurrentNotifications();
291    for (size_t i = 0; i < notifications.size(); ++i) {
292      if (notifications[i].type() == type)
293        right_type.push_back(notifications[i]);
294    }
295    return right_type;
296  }
297
298  void SwitchToAutofill() {
299    controller_->MenuModelForAccountChooser()->ActivatedAt(
300        TestAccountChooserModel::kAutofillItemId);
301  }
302
303  void SwitchToWallet() {
304    controller_->MenuModelForAccountChooser()->ActivatedAt(
305        TestAccountChooserModel::kActiveWalletItemId);
306  }
307
308  TestAutofillDialogController* controller() { return controller_; }
309
310  TestingProfile* profile() { return &profile_; }
311
312  const FormStructure* form_structure() { return form_structure_; }
313
314 private:
315  void FinishedCallback(const FormStructure* form_structure,
316                        const std::string& google_transaction_id) {
317    form_structure_ = form_structure;
318  }
319
320#if defined(OS_WIN)
321   // http://crbug.com/227221
322   ui::ScopedOleInitializer ole_initializer_;
323#endif
324
325  // A bunch of threads are necessary for classes like TestWebContents and
326  // URLRequestContextGetter not to fall over.
327  base::MessageLoopForUI loop_;
328  content::TestBrowserThread ui_thread_;
329  content::TestBrowserThread file_thread_;
330  content::TestBrowserThread file_blocking_thread_;
331  content::TestBrowserThread io_thread_;
332  TestingProfile profile_;
333
334  // The controller owns itself.
335  base::WeakPtr<TestAutofillDialogController> controller_;
336
337  scoped_ptr<content::WebContents> test_web_contents_;
338
339  // Must outlive the controller.
340  AutofillMetrics metric_logger_;
341
342  // Returned when the dialog closes successfully.
343  const FormStructure* form_structure_;
344
345  DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerTest);
346};
347
348}  // namespace
349
350// This test makes sure nothing falls over when fields are being validity-
351// checked.
352TEST_F(AutofillDialogControllerTest, ValidityCheck) {
353  const DialogSection sections[] = {
354    SECTION_EMAIL,
355    SECTION_CC,
356    SECTION_BILLING,
357    SECTION_CC_BILLING,
358    SECTION_SHIPPING
359  };
360
361  for (size_t i = 0; i < arraysize(sections); ++i) {
362    DialogSection section = sections[i];
363    const DetailInputs& shipping_inputs =
364        controller()->RequestedFieldsForSection(section);
365    for (DetailInputs::const_iterator iter = shipping_inputs.begin();
366         iter != shipping_inputs.end(); ++iter) {
367      controller()->InputIsValid(iter->type, string16());
368    }
369  }
370}
371
372TEST_F(AutofillDialogControllerTest, AutofillProfiles) {
373  ui::MenuModel* shipping_model =
374      controller()->MenuModelForSection(SECTION_SHIPPING);
375  // Since the PersonalDataManager is empty, this should only have the
376  // "use billing", "add new" and "manage" menu items.
377  EXPECT_EQ(3, shipping_model->GetItemCount());
378  // On the other hand, the other models should be NULL when there's no
379  // suggestion.
380  EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC));
381  EXPECT_FALSE(controller()->MenuModelForSection(SECTION_BILLING));
382  EXPECT_FALSE(controller()->MenuModelForSection(SECTION_EMAIL));
383
384  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(2);
385
386  // Empty profiles are ignored.
387  AutofillProfile empty_profile(base::GenerateGUID(), kSettingsOrigin);
388  empty_profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John Doe"));
389  controller()->GetTestingManager()->AddTestingProfile(&empty_profile);
390  shipping_model = controller()->MenuModelForSection(SECTION_SHIPPING);
391  EXPECT_EQ(3, shipping_model->GetItemCount());
392  EXPECT_FALSE(controller()->MenuModelForSection(SECTION_EMAIL));
393
394  // A full profile should be picked up.
395  AutofillProfile full_profile(test::GetFullProfile());
396  full_profile.set_origin(kSettingsOrigin);
397  full_profile.SetRawInfo(ADDRESS_HOME_LINE2, string16());
398  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
399  shipping_model = controller()->MenuModelForSection(SECTION_SHIPPING);
400  EXPECT_EQ(4, shipping_model->GetItemCount());
401  EXPECT_TRUE(!!controller()->MenuModelForSection(SECTION_EMAIL));
402}
403
404TEST_F(AutofillDialogControllerTest, AutofillProfileVariants) {
405  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
406  ui::MenuModel* email_model =
407      controller()->MenuModelForSection(SECTION_EMAIL);
408  EXPECT_FALSE(email_model);
409
410  // Set up some variant data.
411  AutofillProfile full_profile(test::GetFullProfile());
412  std::vector<string16> names;
413  names.push_back(ASCIIToUTF16("John Doe"));
414  names.push_back(ASCIIToUTF16("Jane Doe"));
415  full_profile.SetRawMultiInfo(EMAIL_ADDRESS, names);
416  const string16 kEmail1 = ASCIIToUTF16(kFakeEmail);
417  const string16 kEmail2 = ASCIIToUTF16("admin@example.com");
418  std::vector<string16> emails;
419  emails.push_back(kEmail1);
420  emails.push_back(kEmail2);
421  full_profile.SetRawMultiInfo(EMAIL_ADDRESS, emails);
422
423  // Respect variants for the email address field only.
424  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
425  ui::MenuModel* shipping_model =
426      controller()->MenuModelForSection(SECTION_SHIPPING);
427  EXPECT_EQ(4, shipping_model->GetItemCount());
428  email_model = controller()->MenuModelForSection(SECTION_EMAIL);
429  ASSERT_TRUE(!!email_model);
430  EXPECT_EQ(4, email_model->GetItemCount());
431
432  email_model->ActivatedAt(0);
433  EXPECT_EQ(kEmail1,
434            controller()->SuggestionStateForSection(SECTION_EMAIL).text);
435  email_model->ActivatedAt(1);
436  EXPECT_EQ(kEmail2,
437            controller()->SuggestionStateForSection(SECTION_EMAIL).text);
438
439  controller()->EditClickedForSection(SECTION_EMAIL);
440  const DetailInputs& inputs =
441      controller()->RequestedFieldsForSection(SECTION_EMAIL);
442  EXPECT_EQ(kEmail2, inputs[0].initial_value);
443}
444
445// Test selecting a shipping address different from billing as address.
446TEST_F(AutofillDialogControllerTest, DontUseBillingAsShipping) {
447  AutofillProfile full_profile(test::GetFullProfile());
448  AutofillProfile full_profile2(test::GetFullProfile2());
449  CreditCard credit_card;
450  test::SetCreditCardInfo(&credit_card, "Test User",
451                          "4234567890654321", // Visa
452                          "11", "2100");
453  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
454  controller()->GetTestingManager()->AddTestingProfile(&full_profile2);
455  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
456  ui::MenuModel* shipping_model =
457      controller()->MenuModelForSection(SECTION_SHIPPING);
458  shipping_model->ActivatedAt(2);
459
460  controller()->OnAccept();
461  ASSERT_EQ(4U, form_structure()->field_count());
462  EXPECT_EQ("CA", UTF16ToUTF8(form_structure()->field(2)->value));
463  EXPECT_EQ("MI", UTF16ToUTF8(form_structure()->field(3)->value));
464  EXPECT_EQ(ADDRESS_BILLING_STATE, form_structure()->field(2)->type());
465  EXPECT_EQ(ADDRESS_HOME_STATE, form_structure()->field(3)->type());
466}
467
468// Test selecting UseBillingForShipping.
469TEST_F(AutofillDialogControllerTest, UseBillingAsShipping) {
470  AutofillProfile full_profile(test::GetFullProfile());
471  AutofillProfile full_profile2(test::GetFullProfile2());
472  CreditCard credit_card;
473  test::SetCreditCardInfo(&credit_card, "Test User",
474                          "4234567890654321", // Visa
475                          "11", "2100");
476  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
477  controller()->GetTestingManager()->AddTestingProfile(&full_profile2);
478  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
479  ui::MenuModel* shipping_model =
480      controller()->MenuModelForSection(SECTION_SHIPPING);
481
482  // Test after setting use billing for shipping.
483  shipping_model->ActivatedAt(0);
484
485  controller()->OnAccept();
486  ASSERT_EQ(4U, form_structure()->field_count());
487  EXPECT_EQ("CA", UTF16ToUTF8(form_structure()->field(2)->value));
488  EXPECT_EQ("CA", UTF16ToUTF8(form_structure()->field(3)->value));
489  EXPECT_EQ(ADDRESS_BILLING_STATE, form_structure()->field(2)->type());
490  EXPECT_EQ(ADDRESS_HOME_STATE, form_structure()->field(3)->type());
491}
492
493TEST_F(AutofillDialogControllerTest, AcceptLegalDocuments) {
494  EXPECT_CALL(*controller()->GetTestingWalletClient(),
495              AcceptLegalDocuments(_, _, _)).Times(1);
496  EXPECT_CALL(*controller()->GetTestingWalletClient(),
497              GetFullWallet(_)).Times(1);
498
499  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
500  wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
501  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
502  wallet_items->AddAddress(wallet::GetTestShippingAddress());
503  controller()->OnDidGetWalletItems(wallet_items.Pass());
504  controller()->OnAccept();
505}
506
507// Makes sure the default object IDs are respected.
508TEST_F(AutofillDialogControllerTest, WalletDefaultItems) {
509  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
510  wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
511  wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
512  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
513  wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
514
515  wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
516  wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
517  wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
518  wallet_items->AddAddress(wallet::GetTestShippingAddress());
519  wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
520
521  controller()->OnDidGetWalletItems(wallet_items.Pass());
522  // "add", "manage", and 4 suggestions.
523  EXPECT_EQ(6,
524      controller()->MenuModelForSection(SECTION_CC_BILLING)->GetItemCount());
525  EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC_BILLING)->
526      IsItemCheckedAt(2));
527  // "use billing", "add", "manage", and 5 suggestions.
528  EXPECT_EQ(8,
529      controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
530  EXPECT_TRUE(controller()->MenuModelForSection(SECTION_SHIPPING)->
531      IsItemCheckedAt(4));
532}
533
534TEST_F(AutofillDialogControllerTest, SaveAddress) {
535  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
536  EXPECT_CALL(*controller()->GetTestingWalletClient(),
537              SaveAddress(_, _)).Times(1);
538
539  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
540  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
541  controller()->OnDidGetWalletItems(wallet_items.Pass());
542  controller()->OnAccept();
543}
544
545TEST_F(AutofillDialogControllerTest, SaveInstrument) {
546  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
547  EXPECT_CALL(*controller()->GetTestingWalletClient(),
548              SaveInstrument(_, _, _)).Times(1);
549
550  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
551  wallet_items->AddAddress(wallet::GetTestShippingAddress());
552  controller()->OnDidGetWalletItems(wallet_items.Pass());
553  controller()->OnAccept();
554}
555
556TEST_F(AutofillDialogControllerTest, SaveInstrumentAndAddress) {
557  EXPECT_CALL(*controller()->GetTestingWalletClient(),
558              SaveInstrumentAndAddress(_, _, _, _)).Times(1);
559
560  controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
561  controller()->OnAccept();
562}
563
564TEST_F(AutofillDialogControllerTest, CancelNoSave) {
565  EXPECT_CALL(*controller()->GetTestingWalletClient(),
566              SaveInstrumentAndAddress(_, _, _, _)).Times(0);
567
568  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
569
570  controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
571  controller()->OnCancel();
572}
573
574// Checks that clicking the Manage menu item opens a new tab with a different
575// URL for Wallet and Autofill.
576TEST_F(AutofillDialogControllerTest, ManageItem) {
577  AutofillProfile full_profile(test::GetFullProfile());
578  full_profile.set_origin(kSettingsOrigin);
579  full_profile.SetRawInfo(ADDRESS_HOME_LINE2, string16());
580  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
581  SwitchToAutofill();
582
583  SuggestionsMenuModel* model = static_cast<SuggestionsMenuModel*>(
584      controller()->MenuModelForSection(SECTION_SHIPPING));
585  model->ExecuteCommand(model->GetItemCount() - 1, 0);
586  GURL autofill_manage_url = controller()->open_tab_url();
587  EXPECT_EQ("chrome", autofill_manage_url.scheme());
588
589  SwitchToWallet();
590  controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
591  controller()->SuggestionItemSelected(model, model->GetItemCount() - 1);
592  GURL wallet_manage_url = controller()->open_tab_url();
593  EXPECT_EQ("https", wallet_manage_url.scheme());
594
595  EXPECT_NE(autofill_manage_url, wallet_manage_url);
596}
597
598TEST_F(AutofillDialogControllerTest, EditClickedCancelled) {
599  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
600
601  AutofillProfile full_profile(test::GetFullProfile());
602  const string16 kEmail = ASCIIToUTF16("first@johndoe.com");
603  full_profile.SetRawInfo(EMAIL_ADDRESS, kEmail);
604  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
605
606  ui::MenuModel* email_model =
607      controller()->MenuModelForSection(SECTION_EMAIL);
608  EXPECT_EQ(3, email_model->GetItemCount());
609
610  // When unedited, the initial_value should be empty.
611  email_model->ActivatedAt(0);
612  const DetailInputs& inputs0 =
613      controller()->RequestedFieldsForSection(SECTION_EMAIL);
614  EXPECT_EQ(string16(), inputs0[0].initial_value);
615  EXPECT_EQ(kEmail,
616            controller()->SuggestionStateForSection(SECTION_EMAIL).text);
617
618  // When edited, the initial_value should contain the value.
619  controller()->EditClickedForSection(SECTION_EMAIL);
620  const DetailInputs& inputs1 =
621      controller()->RequestedFieldsForSection(SECTION_EMAIL);
622  EXPECT_EQ(kEmail, inputs1[0].initial_value);
623  EXPECT_EQ(string16(),
624            controller()->SuggestionStateForSection(SECTION_EMAIL).text);
625
626  // When edit is cancelled, the initial_value should be empty.
627  controller()->EditCancelledForSection(SECTION_EMAIL);
628  const DetailInputs& inputs2 =
629      controller()->RequestedFieldsForSection(SECTION_EMAIL);
630  EXPECT_EQ(kEmail,
631            controller()->SuggestionStateForSection(SECTION_EMAIL).text);
632  EXPECT_EQ(string16(), inputs2[0].initial_value);
633}
634
635// Tests that editing an autofill profile and then submitting works.
636TEST_F(AutofillDialogControllerTest, EditAutofillProfile) {
637  SwitchToAutofill();
638
639  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
640
641  AutofillProfile full_profile(test::GetFullProfile());
642  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
643  controller()->EditClickedForSection(SECTION_SHIPPING);
644
645  DetailOutputMap outputs;
646  const DetailInputs& inputs =
647      controller()->RequestedFieldsForSection(SECTION_SHIPPING);
648  for (size_t i = 0; i < inputs.size(); ++i) {
649    const DetailInput& input = inputs[i];
650    outputs[&input] = input.type == NAME_FULL ? ASCIIToUTF16("Edited Name") :
651                                                input.initial_value;
652  }
653  controller()->GetView()->SetUserInput(SECTION_SHIPPING, outputs);
654
655  // We also have to simulate CC inputs to keep the controller happy.
656  FillCreditCardInputs();
657
658  controller()->OnAccept();
659  const AutofillProfile& edited_profile =
660      controller()->GetTestingManager()->imported_profile();
661
662  for (size_t i = 0; i < inputs.size(); ++i) {
663    const DetailInput& input = inputs[i];
664    EXPECT_EQ(input.type == NAME_FULL ? ASCIIToUTF16("Edited Name") :
665                                        input.initial_value,
666              edited_profile.GetInfo(input.type, "en-US"));
667  }
668}
669
670// Tests that adding an autofill profile and then submitting works.
671TEST_F(AutofillDialogControllerTest, AddAutofillProfile) {
672  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
673
674  AutofillProfile full_profile(test::GetFullProfile());
675  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
676
677  ui::MenuModel* model = controller()->MenuModelForSection(SECTION_BILLING);
678  // Activate the "Add billing address" menu item.
679  model->ActivatedAt(model->GetItemCount() - 2);
680
681  // Fill in the inputs from the profile.
682  DetailOutputMap outputs;
683  const DetailInputs& inputs =
684      controller()->RequestedFieldsForSection(SECTION_BILLING);
685  AutofillProfile full_profile2(test::GetFullProfile2());
686  for (size_t i = 0; i < inputs.size(); ++i) {
687    const DetailInput& input = inputs[i];
688    outputs[&input] = full_profile2.GetInfo(input.type, "en-US");
689  }
690  controller()->GetView()->SetUserInput(SECTION_BILLING, outputs);
691
692  // Fill in some CC info. The name field will be used to fill in the billing
693  // address name in the newly minted AutofillProfile.
694  DetailOutputMap cc_outputs;
695  const DetailInputs& cc_inputs =
696      controller()->RequestedFieldsForSection(SECTION_CC);
697  for (size_t i = 0; i < cc_inputs.size(); ++i) {
698    cc_outputs[&cc_inputs[i]] = cc_inputs[i].type == CREDIT_CARD_NAME ?
699        ASCIIToUTF16("Bill Money") : ASCIIToUTF16("111");
700  }
701  controller()->GetView()->SetUserInput(SECTION_CC, cc_outputs);
702
703  controller()->OnAccept();
704  const AutofillProfile& added_profile =
705      controller()->GetTestingManager()->imported_profile();
706
707  const DetailInputs& shipping_inputs =
708      controller()->RequestedFieldsForSection(SECTION_SHIPPING);
709  for (size_t i = 0; i < shipping_inputs.size(); ++i) {
710    const DetailInput& input = shipping_inputs[i];
711    string16 expected = input.type == NAME_FULL ?
712        ASCIIToUTF16("Bill Money") :
713        full_profile2.GetInfo(input.type, "en-US");
714    EXPECT_EQ(expected, added_profile.GetInfo(input.type, "en-US"));
715  }
716}
717
718TEST_F(AutofillDialogControllerTest, VerifyCvv) {
719  EXPECT_CALL(*controller()->GetTestingWalletClient(),
720              GetFullWallet(_)).Times(1);
721  EXPECT_CALL(*controller()->GetTestingWalletClient(),
722              AuthenticateInstrument(_, _, _)).Times(1);
723
724  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
725  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
726  wallet_items->AddAddress(wallet::GetTestShippingAddress());
727  controller()->OnDidGetWalletItems(wallet_items.Pass());
728  controller()->OnAccept();
729
730  EXPECT_TRUE(NotificationsOfType(DialogNotification::REQUIRED_ACTION).empty());
731  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
732  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
733  EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
734  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
735
736  SuggestionState suggestion_state =
737      controller()->SuggestionStateForSection(SECTION_CC_BILLING);
738  EXPECT_TRUE(suggestion_state.extra_text.empty());
739
740  controller()->OnDidGetFullWallet(CreateFullWalletWithVerifyCvv());
741
742  EXPECT_FALSE(
743      NotificationsOfType(DialogNotification::REQUIRED_ACTION).empty());
744  EXPECT_FALSE(controller()->SectionIsActive(SECTION_SHIPPING));
745  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
746
747  suggestion_state =
748      controller()->SuggestionStateForSection(SECTION_CC_BILLING);
749  EXPECT_FALSE(suggestion_state.extra_text.empty());
750  EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC_BILLING));
751
752  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
753  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
754
755  controller()->OnAccept();
756}
757
758TEST_F(AutofillDialogControllerTest, ErrorDuringSubmit) {
759  EXPECT_CALL(*controller()->GetTestingWalletClient(),
760              GetFullWallet(_)).Times(1);
761
762  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
763  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
764  wallet_items->AddAddress(wallet::GetTestShippingAddress());
765  controller()->OnDidGetWalletItems(wallet_items.Pass());
766  controller()->OnAccept();
767
768  EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
769  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
770
771  controller()->OnWalletError(wallet::WalletClient::UNKNOWN_ERROR);
772
773  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
774  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
775}
776
777// TODO(dbeam): disallow changing accounts instead and remove this test.
778TEST_F(AutofillDialogControllerTest, ChangeAccountDuringSubmit) {
779  EXPECT_CALL(*controller()->GetTestingWalletClient(),
780              GetFullWallet(_)).Times(1);
781
782  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
783  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
784  wallet_items->AddAddress(wallet::GetTestShippingAddress());
785  controller()->OnDidGetWalletItems(wallet_items.Pass());
786  controller()->OnAccept();
787
788  EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
789  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
790
791  SwitchToWallet();
792  SwitchToAutofill();
793
794  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
795  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
796}
797
798TEST_F(AutofillDialogControllerTest, ErrorDuringVerifyCvv) {
799  EXPECT_CALL(*controller()->GetTestingWalletClient(),
800              GetFullWallet(_)).Times(1);
801
802  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
803  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
804  wallet_items->AddAddress(wallet::GetTestShippingAddress());
805  controller()->OnDidGetWalletItems(wallet_items.Pass());
806  controller()->OnAccept();
807  controller()->OnDidGetFullWallet(CreateFullWalletWithVerifyCvv());
808
809  ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
810  ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
811
812  controller()->OnWalletError(wallet::WalletClient::UNKNOWN_ERROR);
813
814  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
815  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
816}
817
818// TODO(dbeam): disallow changing accounts instead and remove this test.
819TEST_F(AutofillDialogControllerTest, ChangeAccountDuringVerifyCvv) {
820  EXPECT_CALL(*controller()->GetTestingWalletClient(),
821              GetFullWallet(_)).Times(1);
822
823  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
824  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
825  wallet_items->AddAddress(wallet::GetTestShippingAddress());
826  controller()->OnDidGetWalletItems(wallet_items.Pass());
827  controller()->OnAccept();
828  controller()->OnDidGetFullWallet(CreateFullWalletWithVerifyCvv());
829
830  ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
831  ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
832
833  SwitchToWallet();
834  SwitchToAutofill();
835
836  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
837  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
838}
839
840// Test that when a wallet error happens only an error is shown (and no other
841// Wallet-related notifications).
842TEST_F(AutofillDialogControllerTest, WalletErrorNotification) {
843  controller()->OnWalletError(wallet::WalletClient::UNKNOWN_ERROR);
844
845  EXPECT_EQ(1U, NotificationsOfType(
846      DialogNotification::WALLET_ERROR).size());
847
848  // No other wallet notifications should show on Wallet error.
849  EXPECT_TRUE(NotificationsOfType(
850      DialogNotification::WALLET_SIGNIN_PROMO).empty());
851  EXPECT_TRUE(NotificationsOfType(
852      DialogNotification::WALLET_USAGE_CONFIRMATION).empty());
853  EXPECT_TRUE(NotificationsOfType(
854      DialogNotification::EXPLANATORY_MESSAGE).empty());
855}
856
857// Test that only on first run an explanation of where Chrome got the user's
858// data is shown (i.e. "Got these details from Wallet").
859TEST_F(AutofillDialogControllerTest, WalletDetailsExplanation) {
860  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
861  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
862  wallet_items->AddAddress(wallet::GetTestShippingAddress());
863  controller()->OnDidGetWalletItems(wallet_items.Pass());
864
865  EXPECT_EQ(1U, NotificationsOfType(
866      DialogNotification::EXPLANATORY_MESSAGE).size());
867
868  // Wallet notifications are mutually exclusive.
869  EXPECT_TRUE(NotificationsOfType(
870      DialogNotification::WALLET_USAGE_CONFIRMATION).empty());
871  EXPECT_TRUE(NotificationsOfType(
872      DialogNotification::WALLET_SIGNIN_PROMO).empty());
873
874  // Switch to using Autofill, no explanatory message should show.
875  SwitchToAutofill();
876  EXPECT_TRUE(NotificationsOfType(
877      DialogNotification::EXPLANATORY_MESSAGE).empty());
878
879  // Switch to Wallet, pretend this isn't first run. No message should show.
880  SwitchToWallet();
881  controller()->set_is_first_run(false);
882  EXPECT_TRUE(NotificationsOfType(
883      DialogNotification::EXPLANATORY_MESSAGE).empty());
884}
885
886// Verifies that the "[X] Save details in wallet" notification shows on first
887// run with an incomplete profile, stays showing when switching to Autofill in
888// the account chooser, and continues to show on second+ run when a user's
889// wallet is incomplete. This also tests that submitting disables interactivity.
890TEST_F(AutofillDialogControllerTest, SaveDetailsInWallet) {
891  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
892  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
893  controller()->OnDidGetWalletItems(wallet_items.Pass());
894
895  std::vector<DialogNotification> notifications =
896      NotificationsOfType(DialogNotification::WALLET_USAGE_CONFIRMATION);
897  EXPECT_EQ(1U, notifications.size());
898  EXPECT_TRUE(notifications.front().checked());
899  EXPECT_TRUE(notifications.front().interactive());
900
901  // Wallet notifications are mutually exclusive.
902  EXPECT_TRUE(NotificationsOfType(
903      DialogNotification::WALLET_SIGNIN_PROMO).empty());
904  EXPECT_TRUE(NotificationsOfType(
905      DialogNotification::EXPLANATORY_MESSAGE).empty());
906
907  // Using Autofill on second run, show an interactive, unchecked checkbox.
908  SwitchToAutofill();
909  controller()->set_is_first_run(false);
910
911  notifications =
912      NotificationsOfType(DialogNotification::WALLET_USAGE_CONFIRMATION);
913  EXPECT_EQ(1U, notifications.size());
914  EXPECT_FALSE(notifications.front().checked());
915  EXPECT_TRUE(notifications.front().interactive());
916
917  // Notifications shouldn't be interactive while submitting.
918  SwitchToWallet();
919  controller()->OnAccept();
920  EXPECT_FALSE(NotificationsOfType(
921      DialogNotification::WALLET_USAGE_CONFIRMATION).front().interactive());
922}
923
924// Verifies that no Wallet notifications are shown after first run (i.e. no
925// "[X] Save details to wallet" or "These details are from your Wallet") when
926// the user has a complete wallet.
927TEST_F(AutofillDialogControllerTest, NoWalletNotifications) {
928  controller()->set_is_first_run(false);
929
930  // Simulate a complete wallet.
931  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
932  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
933  wallet_items->AddAddress(wallet::GetTestShippingAddress());
934  controller()->OnDidGetWalletItems(wallet_items.Pass());
935
936  EXPECT_TRUE(NotificationsOfType(
937      DialogNotification::EXPLANATORY_MESSAGE).empty());
938  EXPECT_TRUE(NotificationsOfType(
939      DialogNotification::WALLET_USAGE_CONFIRMATION).empty());
940}
941
942TEST_F(AutofillDialogControllerTest, ViewCancelDoesntSetPref) {
943  ASSERT_FALSE(profile()->GetPrefs()->HasPrefPath(
944      ::prefs::kAutofillDialogPayWithoutWallet));
945
946  SwitchToAutofill();
947
948  controller()->OnCancel();
949  controller()->ViewClosed();
950
951  EXPECT_FALSE(profile()->GetPrefs()->HasPrefPath(
952      ::prefs::kAutofillDialogPayWithoutWallet));
953}
954
955TEST_F(AutofillDialogControllerTest, ViewSubmitSetsPref) {
956  ASSERT_FALSE(profile()->GetPrefs()->HasPrefPath(
957      ::prefs::kAutofillDialogPayWithoutWallet));
958
959  SwitchToAutofill();
960
961  // We also have to simulate CC inputs to keep the controller happy.
962  FillCreditCardInputs();
963
964  controller()->OnAccept();
965
966  EXPECT_TRUE(profile()->GetPrefs()->HasPrefPath(
967      ::prefs::kAutofillDialogPayWithoutWallet));
968  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
969      ::prefs::kAutofillDialogPayWithoutWallet));
970}
971
972TEST_F(AutofillDialogControllerTest, HideWalletEmail) {
973  SwitchToAutofill();
974
975  // Email section should be showing when using Autofill.
976  EXPECT_TRUE(controller()->SectionIsActive(SECTION_EMAIL));
977
978  SwitchToWallet();
979
980  // Setup some wallet state, submit, and get a full wallet to end the flow.
981  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
982  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
983  wallet_items->AddAddress(wallet::GetTestShippingAddress());
984
985  // Filling |form_structure()| depends on the current username and wallet items
986  // being fetched. Until both of these have occurred, the user should not be
987  // able to click Submit if using Wallet. The username fetch happened earlier.
988  EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
989  controller()->OnDidGetWalletItems(wallet_items.Pass());
990  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
991
992  // Email section should be hidden when using Wallet.
993  EXPECT_FALSE(controller()->SectionIsActive(SECTION_EMAIL));
994
995  controller()->OnAccept();
996  controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
997
998  size_t i = 0;
999  for (; i < form_structure()->field_count(); ++i) {
1000    if (form_structure()->field(i)->type() == EMAIL_ADDRESS) {
1001      EXPECT_EQ(ASCIIToUTF16(kFakeEmail), form_structure()->field(i)->value);
1002      break;
1003    }
1004  }
1005  ASSERT_LT(i, form_structure()->field_count());
1006}
1007
1008// Test if autofill types of returned form structure are correct for billing
1009// entries.
1010TEST_F(AutofillDialogControllerTest, AutofillTypes) {
1011  controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
1012  controller()->OnAccept();
1013  controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
1014  ASSERT_EQ(4U, form_structure()->field_count());
1015  EXPECT_EQ(EMAIL_ADDRESS, form_structure()->field(0)->type());
1016  EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure()->field(1)->type());
1017  EXPECT_EQ(ADDRESS_BILLING_STATE, form_structure()->field(2)->type());
1018  EXPECT_EQ(ADDRESS_HOME_STATE, form_structure()->field(3)->type());
1019}
1020
1021TEST_F(AutofillDialogControllerTest, SaveDetailsInChrome) {
1022  EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(2);
1023
1024  AutofillProfile full_profile(test::GetFullProfile());
1025  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
1026
1027  CreditCard card;
1028  test::SetCreditCardInfo(
1029      &card, "Donald Trump", "4111-1111-1111-1111", "10", "2025");
1030  controller()->GetTestingManager()->AddTestingCreditCard(&card);
1031  EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
1032
1033  controller()->EditClickedForSection(SECTION_EMAIL);
1034  EXPECT_TRUE(controller()->ShouldOfferToSaveInChrome());
1035
1036  controller()->EditCancelledForSection(SECTION_EMAIL);
1037  EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
1038
1039  controller()->MenuModelForSection(SECTION_EMAIL)->ActivatedAt(1);
1040  EXPECT_TRUE(controller()->ShouldOfferToSaveInChrome());
1041
1042  profile()->set_incognito(true);
1043  EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
1044}
1045
1046}  // namespace autofill
1047