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