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