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