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