autofill_dialog_controller_browsertest.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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/message_loop/message_loop.h"
9#include "base/strings/utf_string_conversions.h"
10#include "base/time/time.h"
11#include "chrome/browser/autofill/personal_data_manager_factory.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
14#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
15#include "chrome/browser/ui/autofill/data_model_wrapper.h"
16#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
17#include "chrome/browser/ui/autofill/testable_autofill_dialog_view.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/ui/tabs/tab_strip_model.h"
20#include "chrome/test/base/in_process_browser_test.h"
21#include "chrome/test/base/ui_test_utils.h"
22#include "components/autofill/content/browser/wallet/mock_wallet_client.h"
23#include "components/autofill/content/browser/wallet/wallet_test_util.h"
24#include "components/autofill/core/browser/autofill_common_test.h"
25#include "components/autofill/core/browser/autofill_metrics.h"
26#include "components/autofill/core/browser/test_personal_data_manager.h"
27#include "components/autofill/core/browser/validation.h"
28#include "components/autofill/core/common/autofill_switches.h"
29#include "components/autofill/core/common/form_data.h"
30#include "components/autofill/core/common/form_field_data.h"
31#include "content/public/browser/browser_thread.h"
32#include "content/public/browser/web_contents.h"
33#include "content/public/browser/web_contents_delegate.h"
34#include "content/public/test/browser_test_utils.h"
35#include "content/public/test/test_utils.h"
36#include "testing/gmock/include/gmock/gmock.h"
37#include "testing/gtest/include/gtest/gtest.h"
38#include "third_party/WebKit/public/web/WebInputEvent.h"
39
40namespace autofill {
41
42namespace {
43
44void MockCallback(const FormStructure*, const std::string&) {}
45
46class MockAutofillMetrics : public AutofillMetrics {
47 public:
48  MockAutofillMetrics()
49      : dialog_type_(static_cast<DialogType>(-1)),
50        dialog_dismissal_action_(
51            static_cast<AutofillMetrics::DialogDismissalAction>(-1)),
52        autocheckout_status_(
53            static_cast<AutofillMetrics::AutocheckoutCompletionStatus>(-1)) {}
54  virtual ~MockAutofillMetrics() {}
55
56  // AutofillMetrics:
57  virtual void LogAutocheckoutDuration(
58      const base::TimeDelta& duration,
59      AutocheckoutCompletionStatus status) const OVERRIDE {
60    // Ignore constness for testing.
61    MockAutofillMetrics* mutable_this = const_cast<MockAutofillMetrics*>(this);
62    mutable_this->autocheckout_status_ = status;
63  }
64
65  virtual void LogDialogUiDuration(
66      const base::TimeDelta& duration,
67      DialogType dialog_type,
68      DialogDismissalAction dismissal_action) const OVERRIDE {
69    // Ignore constness for testing.
70    MockAutofillMetrics* mutable_this = const_cast<MockAutofillMetrics*>(this);
71    mutable_this->dialog_type_ = dialog_type;
72    mutable_this->dialog_dismissal_action_ = dismissal_action;
73  }
74
75  DialogType dialog_type() const { return dialog_type_; }
76  AutofillMetrics::DialogDismissalAction dialog_dismissal_action() const {
77    return dialog_dismissal_action_;
78  }
79
80  AutofillMetrics::AutocheckoutCompletionStatus autocheckout_status() const {
81    return autocheckout_status_;
82  }
83
84  MOCK_CONST_METHOD2(LogDialogDismissalState,
85                     void(DialogType dialog_type, DialogDismissalState state));
86
87 private:
88  DialogType dialog_type_;
89  AutofillMetrics::DialogDismissalAction dialog_dismissal_action_;
90  AutofillMetrics::AutocheckoutCompletionStatus autocheckout_status_;
91
92  DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics);
93};
94
95class TestAutofillDialogController : public AutofillDialogControllerImpl {
96 public:
97  TestAutofillDialogController(content::WebContents* contents,
98                               const FormData& form_data,
99                               const AutofillMetrics& metric_logger,
100                               scoped_refptr<content::MessageLoopRunner> runner,
101                               const DialogType dialog_type)
102      : AutofillDialogControllerImpl(contents,
103                                     form_data,
104                                     GURL(),
105                                     dialog_type,
106                                     base::Bind(&MockCallback)),
107        metric_logger_(metric_logger),
108        mock_wallet_client_(
109            Profile::FromBrowserContext(contents->GetBrowserContext())->
110                GetRequestContext(), this),
111        message_loop_runner_(runner),
112        use_validation_(false) {}
113
114  virtual ~TestAutofillDialogController() {}
115
116  virtual void ViewClosed() OVERRIDE {
117    message_loop_runner_->Quit();
118    AutofillDialogControllerImpl::ViewClosed();
119  }
120
121  virtual string16 InputValidityMessage(
122      DialogSection section,
123      AutofillFieldType type,
124      const string16& value) OVERRIDE {
125    if (!use_validation_)
126      return string16();
127    return AutofillDialogControllerImpl::InputValidityMessage(
128        section, type, value);
129  }
130
131  virtual ValidityData InputsAreValid(
132      DialogSection section,
133      const DetailOutputMap& inputs,
134      ValidationType validation_type) OVERRIDE {
135    if (!use_validation_)
136      return ValidityData();
137    return AutofillDialogControllerImpl::InputsAreValid(
138        section, inputs, validation_type);
139  }
140
141  // Saving to Chrome is tested in AutofillDialogController unit tests.
142  // TODO(estade): test that the view defaults to saving to Chrome.
143  virtual bool ShouldOfferToSaveInChrome() const OVERRIDE {
144    return false;
145  }
146
147  // Increase visibility for testing.
148  using AutofillDialogControllerImpl::view;
149  using AutofillDialogControllerImpl::input_showing_popup;
150
151  virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE {
152    return notifications_;
153  }
154
155  void set_notifications(const std::vector<DialogNotification>& notifications) {
156    notifications_ = notifications;
157  }
158
159  TestPersonalDataManager* GetTestingManager() {
160    return &test_manager_;
161  }
162
163  using AutofillDialogControllerImpl::IsEditingExistingData;
164  using AutofillDialogControllerImpl::IsManuallyEditingSection;
165
166  void set_use_validation(bool use_validation) {
167    use_validation_ = use_validation;
168  }
169
170 protected:
171  virtual PersonalDataManager* GetManager() OVERRIDE {
172    return &test_manager_;
173  }
174
175  virtual wallet::WalletClient* GetWalletClient() OVERRIDE {
176    return &mock_wallet_client_;
177  }
178
179 private:
180  // To specify our own metric logger.
181  virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE {
182    return metric_logger_;
183  }
184
185  const AutofillMetrics& metric_logger_;
186  TestPersonalDataManager test_manager_;
187  testing::NiceMock<wallet::MockWalletClient> mock_wallet_client_;
188  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
189  bool use_validation_;
190
191  // A list of notifications to show in the notification area of the dialog.
192  // This is used to control what |CurrentNotifications()| returns for testing.
193  std::vector<DialogNotification> notifications_;
194
195  DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController);
196};
197
198}  // namespace
199
200class AutofillDialogControllerTest : public InProcessBrowserTest {
201 public:
202  AutofillDialogControllerTest() {}
203  virtual ~AutofillDialogControllerTest() {}
204
205  void InitializeControllerOfType(DialogType dialog_type) {
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        dialog_type);
224    controller_->Show();
225  }
226
227  content::WebContents* GetActiveWebContents() {
228    return browser()->tab_strip_model()->GetActiveWebContents();
229  }
230
231  const MockAutofillMetrics& metric_logger() { return metric_logger_; }
232  TestAutofillDialogController* controller() { return controller_; }
233
234  void RunMessageLoop() {
235    message_loop_runner_->Run();
236  }
237
238  // Loads an HTML page in |GetActiveWebContents()| with markup as follows:
239  // <form>|form_inner_html|</form>. After loading, emulates a click event on
240  // the page as requestAutocomplete() must be in response to a user gesture.
241  // Returns the |AutofillDialogControllerImpl| created by this invocation.
242  AutofillDialogControllerImpl* SetUpHtmlAndInvoke(
243      const std::string& form_inner_html) {
244    content::WebContents* contents = GetActiveWebContents();
245    TabAutofillManagerDelegate* delegate =
246        TabAutofillManagerDelegate::FromWebContents(contents);
247    DCHECK(!delegate->GetDialogControllerForTesting());
248
249    ui_test_utils::NavigateToURL(
250        browser(), GURL(std::string("data:text/html,") +
251        "<!doctype html>"
252        "<html>"
253          "<body>"
254            "<form>" + form_inner_html + "</form>"
255            "<script>"
256              "function send(msg) {"
257                "domAutomationController.setAutomationId(0);"
258                "domAutomationController.send(msg);"
259              "}"
260              "document.forms[0].onautocompleteerror = function(e) {"
261                "send('error: ' + e.reason);"
262              "};"
263              "document.forms[0].onautocomplete = function() {"
264                "send('success');"
265              "};"
266              "window.onclick = function() {"
267                "document.forms[0].requestAutocomplete();"
268                "send('clicked');"
269              "};"
270            "</script>"
271          "</body>"
272        "</html>"));
273    content::WaitForLoadStop(contents);
274
275    dom_message_queue_.reset(new content::DOMMessageQueue);
276
277    // Triggers the onclick handler which invokes requestAutocomplete().
278    content::SimulateMouseClick(contents, 0, WebKit::WebMouseEvent::ButtonLeft);
279    ExpectDomMessage("clicked");
280
281    AutofillDialogControllerImpl* controller =
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  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
324  controller()->GetTestableView()->SubmitForTesting();
325
326  RunMessageLoop();
327
328  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
329            metric_logger().dialog_dismissal_action());
330  EXPECT_EQ(DIALOG_TYPE_REQUEST_AUTOCOMPLETE, metric_logger().dialog_type());
331}
332
333// Cancel out of the dialog.
334IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Cancel) {
335  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
336  controller()->GetTestableView()->CancelForTesting();
337
338  RunMessageLoop();
339
340  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
341            metric_logger().dialog_dismissal_action());
342  EXPECT_EQ(DIALOG_TYPE_REQUEST_AUTOCOMPLETE, metric_logger().dialog_type());
343}
344
345// Take some other action that dismisses the dialog.
346IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Hide) {
347  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
348  controller()->Hide();
349
350  RunMessageLoop();
351
352  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
353            metric_logger().dialog_dismissal_action());
354  EXPECT_EQ(DIALOG_TYPE_REQUEST_AUTOCOMPLETE, metric_logger().dialog_type());
355}
356
357// Ensure that the expected metric is logged when the dialog is closed during
358// signin.
359IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, CloseDuringSignin) {
360  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
361  controller()->SignInLinkClicked();
362
363  EXPECT_CALL(metric_logger(),
364              LogDialogDismissalState(
365                  DIALOG_TYPE_REQUEST_AUTOCOMPLETE,
366                  AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN));
367  controller()->GetTestableView()->CancelForTesting();
368
369  RunMessageLoop();
370
371  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
372            metric_logger().dialog_dismissal_action());
373  EXPECT_EQ(DIALOG_TYPE_REQUEST_AUTOCOMPLETE, metric_logger().dialog_type());
374}
375
376// Test Autocheckout success metrics.
377IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocheckoutSuccess) {
378  InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
379  controller()->GetTestableView()->SubmitForTesting();
380
381  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
382            metric_logger().dialog_dismissal_action());
383  EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
384
385  controller()->OnAutocheckoutSuccess();
386  controller()->GetTestableView()->CancelForTesting();
387  RunMessageLoop();
388
389  EXPECT_EQ(AutofillMetrics::AUTOCHECKOUT_SUCCEEDED,
390            metric_logger().autocheckout_status());
391
392  // Ensure closing the dialog doesn't fire any new metrics.
393  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
394            metric_logger().dialog_dismissal_action());
395  EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
396}
397
398// Test Autocheckout failure metric.
399IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocheckoutError) {
400  InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
401  controller()->GetTestableView()->SubmitForTesting();
402
403  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
404            metric_logger().dialog_dismissal_action());
405  EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
406
407  controller()->OnAutocheckoutError();
408  controller()->GetTestableView()->CancelForTesting();
409  RunMessageLoop();
410
411  EXPECT_EQ(AutofillMetrics::AUTOCHECKOUT_FAILED,
412            metric_logger().autocheckout_status());
413
414  // Ensure closing the dialog doesn't fire any new metrics.
415  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
416            metric_logger().dialog_dismissal_action());
417  EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
418}
419
420IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocheckoutCancelled) {
421  InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
422  controller()->GetTestableView()->SubmitForTesting();
423
424  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
425            metric_logger().dialog_dismissal_action());
426  EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
427
428  controller()->GetTestableView()->CancelForTesting();
429  RunMessageLoop();
430
431  EXPECT_EQ(AutofillMetrics::AUTOCHECKOUT_CANCELLED,
432            metric_logger().autocheckout_status());
433
434  // Ensure closing the dialog doesn't fire any new metrics.
435  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
436            metric_logger().dialog_dismissal_action());
437  EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
438}
439
440#if defined(OS_MACOSX)
441// TODO(groby): Implement the necessary functionality and enable this test:
442// http://crbug.com/256864
443#define MAYBE_FillInputFromAutofill DISABLED_FillInputFromAutofill
444#else
445#define MAYBE_FillInputFromAutofill FillInputFromAutofill
446#endif
447IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
448                       MAYBE_FillInputFromAutofill) {
449  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
450
451  AutofillProfile full_profile(test::GetFullProfile());
452  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
453
454  const DetailInputs& inputs =
455      controller()->RequestedFieldsForSection(SECTION_SHIPPING);
456  const DetailInput& triggering_input = inputs[0];
457  string16 value = full_profile.GetRawInfo(triggering_input.type);
458  TestableAutofillDialogView* view = controller()->GetTestableView();
459  view->SetTextContentsOfInput(triggering_input,
460                               value.substr(0, value.size() / 2));
461  view->ActivateInput(triggering_input);
462
463  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
464  controller()->DidAcceptSuggestion(string16(), 0);
465
466  // All inputs should be filled.
467  AutofillProfileWrapper wrapper(&full_profile, 0);
468  for (size_t i = 0; i < inputs.size(); ++i) {
469    EXPECT_EQ(wrapper.GetInfo(inputs[i].type),
470              view->GetTextContentsOfInput(inputs[i]));
471  }
472
473  // Now simulate some user edits and try again.
474  std::vector<string16> expectations;
475  for (size_t i = 0; i < inputs.size(); ++i) {
476    string16 users_input = i % 2 == 0 ? string16() : ASCIIToUTF16("dummy");
477    view->SetTextContentsOfInput(inputs[i], users_input);
478    // Empty inputs should be filled, others should be left alone.
479    string16 expectation =
480        &inputs[i] == &triggering_input || users_input.empty() ?
481        wrapper.GetInfo(inputs[i].type) :
482        users_input;
483    expectations.push_back(expectation);
484  }
485
486  view->SetTextContentsOfInput(triggering_input,
487                               value.substr(0, value.size() / 2));
488  view->ActivateInput(triggering_input);
489  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
490  controller()->DidAcceptSuggestion(string16(), 0);
491
492  for (size_t i = 0; i < inputs.size(); ++i) {
493    EXPECT_EQ(expectations[i], view->GetTextContentsOfInput(inputs[i]));
494  }
495}
496
497// Test that Autocheckout steps are shown after submitting the
498// dialog for controller with type DIALOG_TYPE_AUTOCHECKOUT.
499IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocheckoutShowsSteps) {
500  InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
501  controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD);
502
503  EXPECT_TRUE(controller()->ShouldShowDetailArea());
504  EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty());
505  EXPECT_FALSE(controller()->ShouldShowProgressBar());
506
507  controller()->GetTestableView()->SubmitForTesting();
508  EXPECT_FALSE(controller()->ShouldShowDetailArea());
509  EXPECT_FALSE(controller()->CurrentAutocheckoutSteps().empty());
510  EXPECT_TRUE(controller()->ShouldShowProgressBar());
511}
512
513#if defined(OS_MACOSX)
514// TODO(groby): Implement the necessary functionality and enable this test:
515// http://crbug.com/256864
516#define MAYBE_RequestAutocompleteDoesntShowSteps \
517    DISABLED_RequestAutocompleteDoesntShowSteps
518#else
519#define MAYBE_RequestAutocompleteDoesntShowSteps \
520    RequestAutocompleteDoesntShowSteps
521#endif
522// Test that Autocheckout steps are not showing after submitting the
523// dialog for controller with type DIALOG_TYPE_REQUEST_AUTOCOMPLETE.
524IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
525                       MAYBE_RequestAutocompleteDoesntShowSteps) {
526  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
527  controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD);
528
529  EXPECT_TRUE(controller()->ShouldShowDetailArea());
530  EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty());
531  EXPECT_FALSE(controller()->ShouldShowProgressBar());
532
533  controller()->GetTestableView()->SubmitForTesting();
534  EXPECT_TRUE(controller()->ShouldShowDetailArea());
535  EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty());
536  EXPECT_FALSE(controller()->ShouldShowProgressBar());
537}
538
539#if defined(OS_MACOSX)
540// TODO(groby): Implement the necessary functionality and enable this test:
541// http://crbug.com/256864
542#define MAYBE_FillComboboxFromAutofill DISABLED_FillComboboxFromAutofill
543#else
544#define MAYBE_FillComboboxFromAutofill FillComboboxFromAutofill
545#endif
546// Tests that changing the value of a CC expiration date combobox works as
547// expected when Autofill is used to fill text inputs.
548IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
549                       MAYBE_FillComboboxFromAutofill) {
550  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
551
552  CreditCard card1;
553  test::SetCreditCardInfo(&card1, "JJ Smith", "4111111111111111", "12", "2018");
554  controller()->GetTestingManager()->AddTestingCreditCard(&card1);
555  CreditCard card2;
556  test::SetCreditCardInfo(&card2, "B Bird", "3111111111111111", "11", "2017");
557  controller()->GetTestingManager()->AddTestingCreditCard(&card2);
558  AutofillProfile full_profile(test::GetFullProfile());
559  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
560
561  const DetailInputs& inputs =
562      controller()->RequestedFieldsForSection(SECTION_CC);
563  const DetailInput& triggering_input = inputs[0];
564  string16 value = card1.GetRawInfo(triggering_input.type);
565  TestableAutofillDialogView* view = controller()->GetTestableView();
566  view->SetTextContentsOfInput(triggering_input,
567                               value.substr(0, value.size() / 2));
568  view->ActivateInput(triggering_input);
569
570  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
571  controller()->DidAcceptSuggestion(string16(), 0);
572
573  // All inputs should be filled.
574  AutofillCreditCardWrapper wrapper1(&card1);
575  for (size_t i = 0; i < inputs.size(); ++i) {
576    EXPECT_EQ(wrapper1.GetInfo(inputs[i].type),
577              view->GetTextContentsOfInput(inputs[i]));
578  }
579
580  // Try again with different data. Only expiration date and the triggering
581  // input should be overwritten.
582  value = card2.GetRawInfo(triggering_input.type);
583  view->SetTextContentsOfInput(triggering_input,
584                               value.substr(0, value.size() / 2));
585  view->ActivateInput(triggering_input);
586  ASSERT_EQ(&triggering_input, controller()->input_showing_popup());
587  controller()->DidAcceptSuggestion(string16(), 0);
588
589  AutofillCreditCardWrapper wrapper2(&card2);
590  for (size_t i = 0; i < inputs.size(); ++i) {
591    const DetailInput& input = inputs[i];
592    if (&input == &triggering_input ||
593        input.type == CREDIT_CARD_EXP_MONTH ||
594        input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
595      EXPECT_EQ(wrapper2.GetInfo(input.type),
596                view->GetTextContentsOfInput(input));
597    } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) {
598      EXPECT_TRUE(view->GetTextContentsOfInput(input).empty());
599    } else {
600      EXPECT_EQ(wrapper1.GetInfo(input.type),
601                view->GetTextContentsOfInput(input));
602    }
603  }
604
605  // Now fill from a profile. It should not overwrite any CC info.
606  const DetailInputs& billing_inputs =
607      controller()->RequestedFieldsForSection(SECTION_BILLING);
608  const DetailInput& billing_triggering_input = billing_inputs[0];
609  value = full_profile.GetRawInfo(triggering_input.type);
610  view->SetTextContentsOfInput(billing_triggering_input,
611                               value.substr(0, value.size() / 2));
612  view->ActivateInput(billing_triggering_input);
613
614  ASSERT_EQ(&billing_triggering_input, controller()->input_showing_popup());
615  controller()->DidAcceptSuggestion(string16(), 0);
616
617  for (size_t i = 0; i < inputs.size(); ++i) {
618    const DetailInput& input = inputs[i];
619    if (&input == &triggering_input ||
620        input.type == CREDIT_CARD_EXP_MONTH ||
621        input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
622      EXPECT_EQ(wrapper2.GetInfo(input.type),
623                view->GetTextContentsOfInput(input));
624    } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) {
625      EXPECT_TRUE(view->GetTextContentsOfInput(input).empty());
626    } else {
627      EXPECT_EQ(wrapper1.GetInfo(input.type),
628                view->GetTextContentsOfInput(input));
629    }
630  }
631}
632
633// Tests that credit card number is disabled while editing a Wallet instrument.
634IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, WalletCreditCardDisabled) {
635  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
636  controller()->OnUserNameFetchSuccess("user@example.com");
637
638  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
639  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
640  controller()->OnDidGetWalletItems(wallet_items.Pass());
641
642  // Click "Edit" in the billing section (while using Wallet).
643  controller()->EditClickedForSection(SECTION_CC_BILLING);
644
645  const DetailInputs& edit_inputs =
646      controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
647  size_t i;
648  for (i = 0; i < edit_inputs.size(); ++i) {
649    if (edit_inputs[i].type == CREDIT_CARD_NUMBER) {
650      EXPECT_FALSE(edit_inputs[i].editable);
651      break;
652    }
653  }
654  ASSERT_LT(i, edit_inputs.size());
655
656  // Select "Add new billing info..." while using Wallet.
657  ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC_BILLING);
658  model->ActivatedAt(model->GetItemCount() - 2);
659
660  const DetailInputs& add_inputs =
661      controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
662  for (i = 0; i < add_inputs.size(); ++i) {
663    if (add_inputs[i].type == CREDIT_CARD_NUMBER) {
664      EXPECT_TRUE(add_inputs[i].editable);
665      break;
666    }
667  }
668  ASSERT_LT(i, add_inputs.size());
669}
670
671// Ensure that expired cards trigger invalid suggestions.
672IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ExpiredCard) {
673  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
674
675  CreditCard verified_card(test::GetCreditCard());
676  verified_card.set_origin("Chrome settings");
677  ASSERT_TRUE(verified_card.IsVerified());
678  controller()->GetTestingManager()->AddTestingCreditCard(&verified_card);
679
680  CreditCard expired_card(test::GetCreditCard());
681  expired_card.set_origin("Chrome settings");
682  expired_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2007"));
683  ASSERT_TRUE(expired_card.IsVerified());
684  ASSERT_FALSE(
685      autofill::IsValidCreditCardExpirationDate(
686          expired_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR),
687          expired_card.GetRawInfo(CREDIT_CARD_EXP_MONTH),
688          base::Time::Now()));
689  controller()->GetTestingManager()->AddTestingCreditCard(&expired_card);
690
691  ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC);
692  ASSERT_EQ(4, model->GetItemCount());
693
694  ASSERT_TRUE(model->IsItemCheckedAt(0));
695  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));
696
697  model->ActivatedAt(1);
698  ASSERT_TRUE(model->IsItemCheckedAt(1));
699  EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC));
700}
701
702// Notifications with long message text should not make the dialog bigger.
703IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, LongNotifications) {
704  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
705
706  const gfx::Size no_notification_size =
707      controller()->GetTestableView()->GetSize();
708  ASSERT_GT(no_notification_size.width(), 0);
709
710  std::vector<DialogNotification> notifications;
711  notifications.push_back(
712      DialogNotification(DialogNotification::DEVELOPER_WARNING, ASCIIToUTF16(
713          "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
714          "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim "
715          "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut "
716          "aliquip ex ea commodo consequat. Duis aute irure dolor in "
717          "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
718          "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
719          "culpa qui officia deserunt mollit anim id est laborum.")));
720  controller()->set_notifications(notifications);
721  controller()->view()->UpdateNotificationArea();
722
723  EXPECT_EQ(no_notification_size.width(),
724            controller()->GetTestableView()->GetSize().width());
725}
726
727#if defined(OS_MACOSX)
728// TODO(groby): Implement the necessary functionality and enable this test:
729// http://crbug.com/256864
730#define MAYBE_AutocompleteEvent DISABLED_AutocompleteEvent
731#else
732#define MAYBE_AutocompleteEvent AutocompleteEvent
733#endif
734IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_AutocompleteEvent) {
735  AutofillDialogControllerImpl* controller =
736      SetUpHtmlAndInvoke("<input autocomplete='cc-name'>");
737
738  AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard());
739  AddAutofillProfileToProfile(controller->profile(),
740                              test::GetVerifiedProfile());
741
742  TestableAutofillDialogView* view = controller->GetTestableView();
743  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
744  view->SubmitForTesting();
745  ExpectDomMessage("success");
746}
747
748#if defined(OS_MACOSX)
749// TODO(groby): Implement the necessary functionality and enable this test:
750// http://crbug.com/256864
751#define MAYBE_AutocompleteErrorEventReasonInvalid \
752    DISABLED_AutocompleteErrorEventReasonInvalid
753#else
754#define MAYBE_AutocompleteErrorEventReasonInvalid \
755    AutocompleteErrorEventReasonInvalid
756#endif
757IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
758                       MAYBE_AutocompleteErrorEventReasonInvalid) {
759  AutofillDialogControllerImpl* controller =
760      SetUpHtmlAndInvoke("<input autocomplete='cc-name' pattern='.*zebra.*'>");
761
762  const CreditCard& credit_card = test::GetVerifiedCreditCard();
763  ASSERT_TRUE(
764    credit_card.GetRawInfo(CREDIT_CARD_NAME).find(ASCIIToUTF16("zebra")) ==
765        base::string16::npos);
766  AddCreditcardToProfile(controller->profile(), credit_card);
767  AddAutofillProfileToProfile(controller->profile(),
768                              test::GetVerifiedProfile());
769
770  TestableAutofillDialogView* view = controller->GetTestableView();
771  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
772  view->SubmitForTesting();
773  ExpectDomMessage("error: invalid");
774}
775
776#if defined(OS_MACOSX)
777// TODO(groby): Implement the necessary functionality and enable this test:
778// http://crbug.com/256864
779#define MAYBE_AutocompleteErrorEventReasonCancel \
780    DISABLED_AutocompleteErrorEventReasonCancel
781#else
782#define MAYBE_AutocompleteErrorEventReasonCancel \
783    AutocompleteErrorEventReasonCancel
784#endif
785IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
786                       MAYBE_AutocompleteErrorEventReasonCancel) {
787  SetUpHtmlAndInvoke("<input autocomplete='cc-name'>")->GetTestableView()->
788      CancelForTesting();
789  ExpectDomMessage("error: cancel");
790}
791
792IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, NoCvcSegfault) {
793  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
794  controller()->set_use_validation(true);
795
796  CreditCard credit_card(test::GetVerifiedCreditCard());
797  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
798  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));
799
800  ASSERT_NO_FATAL_FAILURE(
801      controller()->GetTestableView()->SubmitForTesting());
802}
803
804#if defined(OS_MACOSX)
805// TODO(groby): Implement the necessary functionality and enable this test:
806// http://crbug.com/256864
807#define MAYBE_PreservedSections  DISABLED_PreservedSections
808#else
809#define MAYBE_PreservedSections PreservedSections
810#endif
811IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_PreservedSections) {
812  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
813  controller()->set_use_validation(true);
814
815  // Set up some Autofill state.
816  CreditCard credit_card(test::GetVerifiedCreditCard());
817  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
818
819  AutofillProfile profile(test::GetVerifiedProfile());
820  controller()->GetTestingManager()->AddTestingProfile(&profile);
821
822  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC));
823  EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING));
824  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING));
825  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
826
827  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC));
828  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
829  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
830
831  // Set up some Wallet state.
832  controller()->OnUserNameFetchSuccess("user@example.com");
833  controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
834
835  ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser();
836  ASSERT_TRUE(account_chooser->IsItemCheckedAt(0));
837
838  // Check that the view's in the state we expect before starting to simulate
839  // user input.
840  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC));
841  EXPECT_FALSE(controller()->SectionIsActive(SECTION_BILLING));
842  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
843  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
844
845  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC_BILLING));
846
847  // Create some valid inputted billing data.
848  const DetailInput& cc_number =
849      controller()->RequestedFieldsForSection(SECTION_CC_BILLING)[0];
850  EXPECT_EQ(CREDIT_CARD_NUMBER, cc_number.type);
851  TestableAutofillDialogView* view = controller()->GetTestableView();
852  view->SetTextContentsOfInput(cc_number, ASCIIToUTF16("4111111111111111"));
853
854  // Select "Add new shipping info..." from suggestions menu.
855  ui::MenuModel* shipping_model =
856      controller()->MenuModelForSection(SECTION_SHIPPING);
857  shipping_model->ActivatedAt(shipping_model->GetItemCount() - 2);
858
859  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
860
861  // Create some invalid, manually inputted shipping data.
862  const DetailInput& shipping_zip =
863      controller()->RequestedFieldsForSection(SECTION_SHIPPING)[5];
864  ASSERT_EQ(ADDRESS_HOME_ZIP, shipping_zip.type);
865  view->SetTextContentsOfInput(shipping_zip, ASCIIToUTF16("shipping zip"));
866
867  // Switch to using Autofill.
868  account_chooser->ActivatedAt(1);
869
870  // Check that appropriate sections are preserved and in manually editing mode
871  // (or disabled, in the case of the combined cc + billing section).
872  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC));
873  EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING));
874  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING));
875  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
876
877  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC));
878  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
879  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
880
881  const DetailInput& new_cc_number =
882      controller()->RequestedFieldsForSection(SECTION_CC).front();
883  EXPECT_EQ(cc_number.type, new_cc_number.type);
884  EXPECT_EQ(ASCIIToUTF16("4111111111111111"),
885            view->GetTextContentsOfInput(new_cc_number));
886
887  EXPECT_NE(ASCIIToUTF16("shipping name"),
888            view->GetTextContentsOfInput(shipping_zip));
889}
890#endif  // defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
891
892}  // namespace autofill
893