autofill_dialog_controller_browsertest.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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 controller()->GetTestableView()->CancelForTesting(); 512 RunMessageLoop(); 513} 514 515#if defined(OS_MACOSX) 516// TODO(groby): Implement the necessary functionality and enable this test: 517// http://crbug.com/256864 518#define MAYBE_RequestAutocompleteDoesntShowSteps \ 519 DISABLED_RequestAutocompleteDoesntShowSteps 520#else 521#define MAYBE_RequestAutocompleteDoesntShowSteps \ 522 RequestAutocompleteDoesntShowSteps 523#endif 524// Test that Autocheckout steps are not showing after submitting the 525// dialog for controller with type DIALOG_TYPE_REQUEST_AUTOCOMPLETE. 526IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 527 MAYBE_RequestAutocompleteDoesntShowSteps) { 528 InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE); 529 controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD); 530 531 EXPECT_TRUE(controller()->ShouldShowDetailArea()); 532 EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty()); 533 EXPECT_FALSE(controller()->ShouldShowProgressBar()); 534 535 controller()->GetTestableView()->SubmitForTesting(); 536 EXPECT_TRUE(controller()->ShouldShowDetailArea()); 537 EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty()); 538 EXPECT_FALSE(controller()->ShouldShowProgressBar()); 539} 540 541#if defined(OS_MACOSX) 542// TODO(groby): Implement the necessary functionality and enable this test: 543// http://crbug.com/256864 544#define MAYBE_FillComboboxFromAutofill DISABLED_FillComboboxFromAutofill 545#else 546#define MAYBE_FillComboboxFromAutofill FillComboboxFromAutofill 547#endif 548// Tests that changing the value of a CC expiration date combobox works as 549// expected when Autofill is used to fill text inputs. 550IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 551 MAYBE_FillComboboxFromAutofill) { 552 InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE); 553 554 CreditCard card1; 555 test::SetCreditCardInfo(&card1, "JJ Smith", "4111111111111111", "12", "2018"); 556 controller()->GetTestingManager()->AddTestingCreditCard(&card1); 557 CreditCard card2; 558 test::SetCreditCardInfo(&card2, "B Bird", "3111111111111111", "11", "2017"); 559 controller()->GetTestingManager()->AddTestingCreditCard(&card2); 560 AutofillProfile full_profile(test::GetFullProfile()); 561 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 562 563 const DetailInputs& inputs = 564 controller()->RequestedFieldsForSection(SECTION_CC); 565 const DetailInput& triggering_input = inputs[0]; 566 string16 value = card1.GetRawInfo(triggering_input.type); 567 TestableAutofillDialogView* view = controller()->GetTestableView(); 568 view->SetTextContentsOfInput(triggering_input, 569 value.substr(0, value.size() / 2)); 570 view->ActivateInput(triggering_input); 571 572 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 573 controller()->DidAcceptSuggestion(string16(), 0); 574 575 // All inputs should be filled. 576 AutofillCreditCardWrapper wrapper1(&card1); 577 for (size_t i = 0; i < inputs.size(); ++i) { 578 EXPECT_EQ(wrapper1.GetInfo(inputs[i].type), 579 view->GetTextContentsOfInput(inputs[i])); 580 } 581 582 // Try again with different data. Only expiration date and the triggering 583 // input should be overwritten. 584 value = card2.GetRawInfo(triggering_input.type); 585 view->SetTextContentsOfInput(triggering_input, 586 value.substr(0, value.size() / 2)); 587 view->ActivateInput(triggering_input); 588 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 589 controller()->DidAcceptSuggestion(string16(), 0); 590 591 AutofillCreditCardWrapper wrapper2(&card2); 592 for (size_t i = 0; i < inputs.size(); ++i) { 593 const DetailInput& input = inputs[i]; 594 if (&input == &triggering_input || 595 input.type == CREDIT_CARD_EXP_MONTH || 596 input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { 597 EXPECT_EQ(wrapper2.GetInfo(input.type), 598 view->GetTextContentsOfInput(input)); 599 } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) { 600 EXPECT_TRUE(view->GetTextContentsOfInput(input).empty()); 601 } else { 602 EXPECT_EQ(wrapper1.GetInfo(input.type), 603 view->GetTextContentsOfInput(input)); 604 } 605 } 606 607 // Now fill from a profile. It should not overwrite any CC info. 608 const DetailInputs& billing_inputs = 609 controller()->RequestedFieldsForSection(SECTION_BILLING); 610 const DetailInput& billing_triggering_input = billing_inputs[0]; 611 value = full_profile.GetRawInfo(triggering_input.type); 612 view->SetTextContentsOfInput(billing_triggering_input, 613 value.substr(0, value.size() / 2)); 614 view->ActivateInput(billing_triggering_input); 615 616 ASSERT_EQ(&billing_triggering_input, controller()->input_showing_popup()); 617 controller()->DidAcceptSuggestion(string16(), 0); 618 619 for (size_t i = 0; i < inputs.size(); ++i) { 620 const DetailInput& input = inputs[i]; 621 if (&input == &triggering_input || 622 input.type == CREDIT_CARD_EXP_MONTH || 623 input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { 624 EXPECT_EQ(wrapper2.GetInfo(input.type), 625 view->GetTextContentsOfInput(input)); 626 } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) { 627 EXPECT_TRUE(view->GetTextContentsOfInput(input).empty()); 628 } else { 629 EXPECT_EQ(wrapper1.GetInfo(input.type), 630 view->GetTextContentsOfInput(input)); 631 } 632 } 633} 634 635// Tests that credit card number is disabled while editing a Wallet instrument. 636IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, WalletCreditCardDisabled) { 637 InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE); 638 controller()->OnUserNameFetchSuccess("user@example.com"); 639 640 scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems(); 641 wallet_items->AddInstrument(wallet::GetTestMaskedInstrument()); 642 controller()->OnDidGetWalletItems(wallet_items.Pass()); 643 644 // Click "Edit" in the billing section (while using Wallet). 645 controller()->EditClickedForSection(SECTION_CC_BILLING); 646 647 const DetailInputs& edit_inputs = 648 controller()->RequestedFieldsForSection(SECTION_CC_BILLING); 649 size_t i; 650 for (i = 0; i < edit_inputs.size(); ++i) { 651 if (edit_inputs[i].type == CREDIT_CARD_NUMBER) { 652 EXPECT_FALSE(edit_inputs[i].editable); 653 break; 654 } 655 } 656 ASSERT_LT(i, edit_inputs.size()); 657 658 // Select "Add new billing info..." while using Wallet. 659 ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC_BILLING); 660 model->ActivatedAt(model->GetItemCount() - 2); 661 662 const DetailInputs& add_inputs = 663 controller()->RequestedFieldsForSection(SECTION_CC_BILLING); 664 for (i = 0; i < add_inputs.size(); ++i) { 665 if (add_inputs[i].type == CREDIT_CARD_NUMBER) { 666 EXPECT_TRUE(add_inputs[i].editable); 667 break; 668 } 669 } 670 ASSERT_LT(i, add_inputs.size()); 671} 672 673// Ensure that expired cards trigger invalid suggestions. 674IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ExpiredCard) { 675 InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE); 676 677 CreditCard verified_card(test::GetCreditCard()); 678 verified_card.set_origin("Chrome settings"); 679 ASSERT_TRUE(verified_card.IsVerified()); 680 controller()->GetTestingManager()->AddTestingCreditCard(&verified_card); 681 682 CreditCard expired_card(test::GetCreditCard()); 683 expired_card.set_origin("Chrome settings"); 684 expired_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2007")); 685 ASSERT_TRUE(expired_card.IsVerified()); 686 ASSERT_FALSE( 687 autofill::IsValidCreditCardExpirationDate( 688 expired_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR), 689 expired_card.GetRawInfo(CREDIT_CARD_EXP_MONTH), 690 base::Time::Now())); 691 controller()->GetTestingManager()->AddTestingCreditCard(&expired_card); 692 693 ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC); 694 ASSERT_EQ(4, model->GetItemCount()); 695 696 ASSERT_TRUE(model->IsItemCheckedAt(0)); 697 EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC)); 698 699 model->ActivatedAt(1); 700 ASSERT_TRUE(model->IsItemCheckedAt(1)); 701 EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC)); 702} 703 704// Notifications with long message text should not make the dialog bigger. 705IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, LongNotifications) { 706 InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE); 707 708 const gfx::Size no_notification_size = 709 controller()->GetTestableView()->GetSize(); 710 ASSERT_GT(no_notification_size.width(), 0); 711 712 std::vector<DialogNotification> notifications; 713 notifications.push_back( 714 DialogNotification(DialogNotification::DEVELOPER_WARNING, ASCIIToUTF16( 715 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " 716 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim " 717 "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " 718 "aliquip ex ea commodo consequat. Duis aute irure dolor in " 719 "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " 720 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " 721 "culpa qui officia deserunt mollit anim id est laborum."))); 722 controller()->set_notifications(notifications); 723 controller()->view()->UpdateNotificationArea(); 724 725 EXPECT_EQ(no_notification_size.width(), 726 controller()->GetTestableView()->GetSize().width()); 727} 728 729#if defined(OS_MACOSX) 730// TODO(groby): Implement the necessary functionality and enable this test: 731// http://crbug.com/256864 732#define MAYBE_AutocompleteEvent DISABLED_AutocompleteEvent 733#else 734#define MAYBE_AutocompleteEvent AutocompleteEvent 735#endif 736IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_AutocompleteEvent) { 737 AutofillDialogControllerImpl* controller = 738 SetUpHtmlAndInvoke("<input autocomplete='cc-name'>"); 739 740 AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard()); 741 AddAutofillProfileToProfile(controller->profile(), 742 test::GetVerifiedProfile()); 743 744 TestableAutofillDialogView* view = controller->GetTestableView(); 745 view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123")); 746 view->SubmitForTesting(); 747 ExpectDomMessage("success"); 748} 749 750#if defined(OS_MACOSX) 751// TODO(groby): Implement the necessary functionality and enable this test: 752// http://crbug.com/256864 753#define MAYBE_AutocompleteErrorEventReasonInvalid \ 754 DISABLED_AutocompleteErrorEventReasonInvalid 755#else 756#define MAYBE_AutocompleteErrorEventReasonInvalid \ 757 AutocompleteErrorEventReasonInvalid 758#endif 759IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 760 MAYBE_AutocompleteErrorEventReasonInvalid) { 761 AutofillDialogControllerImpl* controller = 762 SetUpHtmlAndInvoke("<input autocomplete='cc-name' pattern='.*zebra.*'>"); 763 764 const CreditCard& credit_card = test::GetVerifiedCreditCard(); 765 ASSERT_TRUE( 766 credit_card.GetRawInfo(CREDIT_CARD_NAME).find(ASCIIToUTF16("zebra")) == 767 base::string16::npos); 768 AddCreditcardToProfile(controller->profile(), credit_card); 769 AddAutofillProfileToProfile(controller->profile(), 770 test::GetVerifiedProfile()); 771 772 TestableAutofillDialogView* view = controller->GetTestableView(); 773 view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123")); 774 view->SubmitForTesting(); 775 ExpectDomMessage("error: invalid"); 776} 777 778#if defined(OS_MACOSX) 779// TODO(groby): Implement the necessary functionality and enable this test: 780// http://crbug.com/256864 781#define MAYBE_AutocompleteErrorEventReasonCancel \ 782 DISABLED_AutocompleteErrorEventReasonCancel 783#else 784#define MAYBE_AutocompleteErrorEventReasonCancel \ 785 AutocompleteErrorEventReasonCancel 786#endif 787IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 788 MAYBE_AutocompleteErrorEventReasonCancel) { 789 SetUpHtmlAndInvoke("<input autocomplete='cc-name'>")->GetTestableView()-> 790 CancelForTesting(); 791 ExpectDomMessage("error: cancel"); 792} 793 794IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, NoCvcSegfault) { 795 InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE); 796 controller()->set_use_validation(true); 797 798 CreditCard credit_card(test::GetVerifiedCreditCard()); 799 controller()->GetTestingManager()->AddTestingCreditCard(&credit_card); 800 EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC)); 801 802 ASSERT_NO_FATAL_FAILURE( 803 controller()->GetTestableView()->SubmitForTesting()); 804} 805 806#if defined(OS_MACOSX) 807// TODO(groby): Implement the necessary functionality and enable this test: 808// http://crbug.com/256864 809#define MAYBE_PreservedSections DISABLED_PreservedSections 810#else 811#define MAYBE_PreservedSections PreservedSections 812#endif 813IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_PreservedSections) { 814 InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE); 815 controller()->set_use_validation(true); 816 817 // Set up some Autofill state. 818 CreditCard credit_card(test::GetVerifiedCreditCard()); 819 controller()->GetTestingManager()->AddTestingCreditCard(&credit_card); 820 821 AutofillProfile profile(test::GetVerifiedProfile()); 822 controller()->GetTestingManager()->AddTestingProfile(&profile); 823 824 EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC)); 825 EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING)); 826 EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING)); 827 EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING)); 828 829 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC)); 830 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING)); 831 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING)); 832 833 // Set up some Wallet state. 834 controller()->OnUserNameFetchSuccess("user@example.com"); 835 controller()->OnDidGetWalletItems(wallet::GetTestWalletItems()); 836 837 ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser(); 838 ASSERT_TRUE(account_chooser->IsItemCheckedAt(0)); 839 840 // Check that the view's in the state we expect before starting to simulate 841 // user input. 842 EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC)); 843 EXPECT_FALSE(controller()->SectionIsActive(SECTION_BILLING)); 844 EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING)); 845 EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING)); 846 847 EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC_BILLING)); 848 849 // Create some valid inputted billing data. 850 const DetailInput& cc_number = 851 controller()->RequestedFieldsForSection(SECTION_CC_BILLING)[0]; 852 EXPECT_EQ(CREDIT_CARD_NUMBER, cc_number.type); 853 TestableAutofillDialogView* view = controller()->GetTestableView(); 854 view->SetTextContentsOfInput(cc_number, ASCIIToUTF16("4111111111111111")); 855 856 // Select "Add new shipping info..." from suggestions menu. 857 ui::MenuModel* shipping_model = 858 controller()->MenuModelForSection(SECTION_SHIPPING); 859 shipping_model->ActivatedAt(shipping_model->GetItemCount() - 2); 860 861 EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING)); 862 863 // Create some invalid, manually inputted shipping data. 864 const DetailInput& shipping_zip = 865 controller()->RequestedFieldsForSection(SECTION_SHIPPING)[5]; 866 ASSERT_EQ(ADDRESS_HOME_ZIP, shipping_zip.type); 867 view->SetTextContentsOfInput(shipping_zip, ASCIIToUTF16("shipping zip")); 868 869 // Switch to using Autofill. 870 account_chooser->ActivatedAt(1); 871 872 // Check that appropriate sections are preserved and in manually editing mode 873 // (or disabled, in the case of the combined cc + billing section). 874 EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC)); 875 EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING)); 876 EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING)); 877 EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING)); 878 879 EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC)); 880 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING)); 881 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING)); 882 883 const DetailInput& new_cc_number = 884 controller()->RequestedFieldsForSection(SECTION_CC).front(); 885 EXPECT_EQ(cc_number.type, new_cc_number.type); 886 EXPECT_EQ(ASCIIToUTF16("4111111111111111"), 887 view->GetTextContentsOfInput(new_cc_number)); 888 889 EXPECT_NE(ASCIIToUTF16("shipping name"), 890 view->GetTextContentsOfInput(shipping_zip)); 891} 892#endif // defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) 893 894} // namespace autofill 895