autofill_dialog_controller_browsertest.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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*) {} 46 47class MockAutofillMetrics : public AutofillMetrics { 48 public: 49 MockAutofillMetrics() 50 : dialog_dismissal_action_( 51 static_cast<AutofillMetrics::DialogDismissalAction>(-1)) {} 52 virtual ~MockAutofillMetrics() {} 53 54 virtual void LogDialogUiDuration( 55 const base::TimeDelta& duration, 56 DialogDismissalAction dismissal_action) const OVERRIDE { 57 // Ignore constness for testing. 58 MockAutofillMetrics* mutable_this = const_cast<MockAutofillMetrics*>(this); 59 mutable_this->dialog_dismissal_action_ = dismissal_action; 60 } 61 62 AutofillMetrics::DialogDismissalAction dialog_dismissal_action() const { 63 return dialog_dismissal_action_; 64 } 65 66 MOCK_CONST_METHOD1(LogDialogDismissalState, 67 void(DialogDismissalState state)); 68 69 private: 70 AutofillMetrics::DialogDismissalAction dialog_dismissal_action_; 71 72 DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics); 73}; 74 75class TestAutofillDialogController : public AutofillDialogControllerImpl { 76 public: 77 TestAutofillDialogController(content::WebContents* contents, 78 const FormData& form_data, 79 const AutofillMetrics& metric_logger, 80 scoped_refptr<content::MessageLoopRunner> runner) 81 : AutofillDialogControllerImpl(contents, 82 form_data, 83 GURL(), 84 base::Bind(&MockCallback)), 85 metric_logger_(metric_logger), 86 mock_wallet_client_( 87 Profile::FromBrowserContext(contents->GetBrowserContext())-> 88 GetRequestContext(), this), 89 message_loop_runner_(runner), 90 use_validation_(false), 91 weak_ptr_factory_(this) {} 92 93 virtual ~TestAutofillDialogController() {} 94 95 virtual void ViewClosed() OVERRIDE { 96 message_loop_runner_->Quit(); 97 AutofillDialogControllerImpl::ViewClosed(); 98 } 99 100 virtual string16 InputValidityMessage( 101 DialogSection section, 102 ServerFieldType type, 103 const string16& value) OVERRIDE { 104 if (!use_validation_) 105 return string16(); 106 return AutofillDialogControllerImpl::InputValidityMessage( 107 section, type, value); 108 } 109 110 virtual ValidityData InputsAreValid( 111 DialogSection section, 112 const DetailOutputMap& inputs, 113 ValidationType validation_type) OVERRIDE { 114 if (!use_validation_) 115 return ValidityData(); 116 return AutofillDialogControllerImpl::InputsAreValid( 117 section, inputs, validation_type); 118 } 119 120 // Saving to Chrome is tested in AutofillDialogControllerImpl unit tests. 121 // TODO(estade): test that the view defaults to saving to Chrome. 122 virtual bool ShouldOfferToSaveInChrome() const OVERRIDE { 123 return false; 124 } 125 126 // Increase visibility for testing. 127 using AutofillDialogControllerImpl::view; 128 using AutofillDialogControllerImpl::input_showing_popup; 129 130 virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE { 131 return notifications_; 132 } 133 134 void set_notifications(const std::vector<DialogNotification>& notifications) { 135 notifications_ = notifications; 136 } 137 138 TestPersonalDataManager* GetTestingManager() { 139 return &test_manager_; 140 } 141 142 using AutofillDialogControllerImpl::IsEditingExistingData; 143 using AutofillDialogControllerImpl::IsManuallyEditingSection; 144 145 void set_use_validation(bool use_validation) { 146 use_validation_ = use_validation; 147 } 148 149 base::WeakPtr<TestAutofillDialogController> AsWeakPtr() { 150 return weak_ptr_factory_.GetWeakPtr(); 151 } 152 153 protected: 154 virtual PersonalDataManager* GetManager() OVERRIDE { 155 return &test_manager_; 156 } 157 158 virtual wallet::WalletClient* GetWalletClient() OVERRIDE { 159 return &mock_wallet_client_; 160 } 161 162 private: 163 // To specify our own metric logger. 164 virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE { 165 return metric_logger_; 166 } 167 168 const AutofillMetrics& metric_logger_; 169 TestPersonalDataManager test_manager_; 170 testing::NiceMock<wallet::MockWalletClient> mock_wallet_client_; 171 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; 172 bool use_validation_; 173 174 // A list of notifications to show in the notification area of the dialog. 175 // This is used to control what |CurrentNotifications()| returns for testing. 176 std::vector<DialogNotification> notifications_; 177 178 // Allows generation of WeakPtrs, so controller liveness can be tested. 179 base::WeakPtrFactory<TestAutofillDialogController> weak_ptr_factory_; 180 181 DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController); 182}; 183 184} // namespace 185 186class AutofillDialogControllerTest : public InProcessBrowserTest { 187 public: 188 AutofillDialogControllerTest() {} 189 virtual ~AutofillDialogControllerTest() {} 190 191 virtual void SetUpOnMainThread() OVERRIDE { 192 autofill::test::DisableSystemServices(browser()->profile()); 193 InitializeController(); 194 } 195 196 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 197#if defined(OS_MACOSX) 198 // OSX support for requestAutocomplete is still hidden behind a switch. 199 // Pending resolution of http://crbug.com/157274 200 CommandLine::ForCurrentProcess()->AppendSwitch( 201 switches::kEnableInteractiveAutocomplete); 202#endif 203 } 204 205 void InitializeController() { 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 controller_->Show(); 224 } 225 226 content::WebContents* GetActiveWebContents() { 227 return browser()->tab_strip_model()->GetActiveWebContents(); 228 } 229 230 const MockAutofillMetrics& metric_logger() { return metric_logger_; } 231 TestAutofillDialogController* controller() { return controller_; } 232 233 void RunMessageLoop() { 234 message_loop_runner_->Run(); 235 } 236 237 // Loads an HTML page in |GetActiveWebContents()| with markup as follows: 238 // <form>|form_inner_html|</form>. After loading, emulates a click event on 239 // the page as requestAutocomplete() must be in response to a user gesture. 240 // Returns the |AutofillDialogControllerImpl| created by this invocation. 241 AutofillDialogControllerImpl* SetUpHtmlAndInvoke( 242 const std::string& form_inner_html) { 243 content::WebContents* contents = GetActiveWebContents(); 244 TabAutofillManagerDelegate* delegate = 245 TabAutofillManagerDelegate::FromWebContents(contents); 246 DCHECK(!delegate->GetDialogControllerForTesting()); 247 248 ui_test_utils::NavigateToURL( 249 browser(), GURL(std::string("data:text/html,") + 250 "<!doctype html>" 251 "<html>" 252 "<body>" 253 "<form>" + form_inner_html + "</form>" 254 "<script>" 255 "function send(msg) {" 256 "domAutomationController.setAutomationId(0);" 257 "domAutomationController.send(msg);" 258 "}" 259 "document.forms[0].onautocompleteerror = function(e) {" 260 "send('error: ' + e.reason);" 261 "};" 262 "document.forms[0].onautocomplete = function() {" 263 "send('success');" 264 "};" 265 "window.onclick = function() {" 266 "document.forms[0].requestAutocomplete();" 267 "send('clicked');" 268 "};" 269 "</script>" 270 "</body>" 271 "</html>")); 272 content::WaitForLoadStop(contents); 273 274 dom_message_queue_.reset(new content::DOMMessageQueue); 275 276 // Triggers the onclick handler which invokes requestAutocomplete(). 277 content::SimulateMouseClick(contents, 0, WebKit::WebMouseEvent::ButtonLeft); 278 ExpectDomMessage("clicked"); 279 280 AutofillDialogControllerImpl* controller = 281 static_cast<AutofillDialogControllerImpl*>( 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 controller()->GetTestableView()->SubmitForTesting(); 324 325 RunMessageLoop(); 326 327 EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED, 328 metric_logger().dialog_dismissal_action()); 329} 330 331// Cancel out of the dialog. 332IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Cancel) { 333 controller()->GetTestableView()->CancelForTesting(); 334 335 RunMessageLoop(); 336 337 EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED, 338 metric_logger().dialog_dismissal_action()); 339} 340 341// Take some other action that dismisses the dialog. 342IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Hide) { 343 controller()->Hide(); 344 345 RunMessageLoop(); 346 347 EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED, 348 metric_logger().dialog_dismissal_action()); 349} 350 351// Ensure that Hide() will only destroy the controller object after the 352// message loop has run. Otherwise, there may be read-after-free issues 353// during some tests. 354IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, DeferredDestruction) { 355 base::WeakPtr<TestAutofillDialogController> weak_ptr = 356 controller()->AsWeakPtr(); 357 EXPECT_TRUE(weak_ptr.get()); 358 359 controller()->Hide(); 360 EXPECT_TRUE(weak_ptr.get()); 361 362 RunMessageLoop(); 363 EXPECT_FALSE(weak_ptr.get()); 364} 365 366// Ensure that the expected metric is logged when the dialog is closed during 367// signin. 368IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, CloseDuringSignin) { 369 controller()->SignInLinkClicked(); 370 371 EXPECT_CALL(metric_logger(), 372 LogDialogDismissalState( 373 AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN)); 374 controller()->GetTestableView()->CancelForTesting(); 375 376 RunMessageLoop(); 377 378 EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED, 379 metric_logger().dialog_dismissal_action()); 380} 381 382IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, FillInputFromAutofill) { 383 AutofillProfile full_profile(test::GetFullProfile()); 384 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 385 386 const DetailInputs& inputs = 387 controller()->RequestedFieldsForSection(SECTION_SHIPPING); 388 const DetailInput& triggering_input = inputs[0]; 389 string16 value = full_profile.GetRawInfo(triggering_input.type); 390 TestableAutofillDialogView* view = controller()->GetTestableView(); 391 view->SetTextContentsOfInput(triggering_input, 392 value.substr(0, value.size() / 2)); 393 view->ActivateInput(triggering_input); 394 395 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 396 controller()->DidAcceptSuggestion(string16(), 0); 397 398 // All inputs should be filled. 399 AutofillProfileWrapper wrapper(&full_profile); 400 for (size_t i = 0; i < inputs.size(); ++i) { 401 EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)), 402 view->GetTextContentsOfInput(inputs[i])); 403 } 404 405 // Now simulate some user edits and try again. 406 std::vector<string16> expectations; 407 for (size_t i = 0; i < inputs.size(); ++i) { 408 string16 users_input = i % 2 == 0 ? string16() : ASCIIToUTF16("dummy"); 409 view->SetTextContentsOfInput(inputs[i], users_input); 410 // Empty inputs should be filled, others should be left alone. 411 string16 expectation = 412 &inputs[i] == &triggering_input || users_input.empty() ? 413 wrapper.GetInfo(AutofillType(inputs[i].type)) : 414 users_input; 415 expectations.push_back(expectation); 416 } 417 418 view->SetTextContentsOfInput(triggering_input, 419 value.substr(0, value.size() / 2)); 420 view->ActivateInput(triggering_input); 421 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 422 controller()->DidAcceptSuggestion(string16(), 0); 423 424 for (size_t i = 0; i < inputs.size(); ++i) { 425 EXPECT_EQ(expectations[i], view->GetTextContentsOfInput(inputs[i])); 426 } 427} 428 429// This test makes sure that picking a profile variant in the Autofill 430// popup works as expected. 431IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 432 FillInputFromAutofillVariant) { 433 AutofillProfile full_profile(test::GetFullProfile()); 434 435 // Set up some variant data. 436 std::vector<string16> names; 437 names.push_back(ASCIIToUTF16("John Doe")); 438 names.push_back(ASCIIToUTF16("Jane Doe")); 439 full_profile.SetRawMultiInfo(NAME_FULL, names); 440 std::vector<string16> emails; 441 emails.push_back(ASCIIToUTF16("user@example.com")); 442 emails.push_back(ASCIIToUTF16("admin@example.com")); 443 full_profile.SetRawMultiInfo(EMAIL_ADDRESS, emails); 444 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 445 446 const DetailInputs& inputs = 447 controller()->RequestedFieldsForSection(SECTION_BILLING); 448 const DetailInput& triggering_input = inputs[0]; 449 EXPECT_EQ(NAME_BILLING_FULL, triggering_input.type); 450 TestableAutofillDialogView* view = controller()->GetTestableView(); 451 view->ActivateInput(triggering_input); 452 453 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 454 455 // Choose the variant suggestion. 456 controller()->DidAcceptSuggestion(string16(), 1); 457 458 // All inputs should be filled. 459 AutofillProfileWrapper wrapper( 460 &full_profile, AutofillType(NAME_BILLING_FULL), 1); 461 for (size_t i = 0; i < inputs.size(); ++i) { 462 EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)), 463 view->GetTextContentsOfInput(inputs[i])); 464 } 465 466 // Make sure the wrapper applies the variant index to the right group. 467 EXPECT_EQ(names[1], wrapper.GetInfo(AutofillType(NAME_BILLING_FULL))); 468 // Make sure the wrapper doesn't apply the variant index to the wrong group. 469 EXPECT_EQ(emails[0], wrapper.GetInfo(AutofillType(EMAIL_ADDRESS))); 470} 471 472// Tests that changing the value of a CC expiration date combobox works as 473// expected when Autofill is used to fill text inputs. 474// 475// Flaky on Win7, WinXP, and Win Aura. http://crbug.com/270314. 476// TODO(groby): Enable this test on mac once AutofillDialogCocoa handles 477// comboboxes for GetTextContentsForInput. http://crbug.com/270205 478#if defined(OS_MACOSX) || defined(OS_WIN) 479#define MAYBE_FillComboboxFromAutofill DISABLED_FillComboboxFromAutofill 480#else 481#define MAYBE_FillComboboxFromAutofill FillComboboxFromAutofill 482#endif 483IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 484 MAYBE_FillComboboxFromAutofill) { 485 CreditCard card1; 486 test::SetCreditCardInfo(&card1, "JJ Smith", "4111111111111111", "12", "2018"); 487 controller()->GetTestingManager()->AddTestingCreditCard(&card1); 488 CreditCard card2; 489 test::SetCreditCardInfo(&card2, "B Bird", "3111111111111111", "11", "2017"); 490 controller()->GetTestingManager()->AddTestingCreditCard(&card2); 491 AutofillProfile full_profile(test::GetFullProfile()); 492 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 493 494 const DetailInputs& inputs = 495 controller()->RequestedFieldsForSection(SECTION_CC); 496 const DetailInput& triggering_input = inputs[0]; 497 string16 value = card1.GetRawInfo(triggering_input.type); 498 TestableAutofillDialogView* view = controller()->GetTestableView(); 499 view->SetTextContentsOfInput(triggering_input, 500 value.substr(0, value.size() / 2)); 501 view->ActivateInput(triggering_input); 502 503 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 504 controller()->DidAcceptSuggestion(string16(), 0); 505 506 // All inputs should be filled. 507 AutofillCreditCardWrapper wrapper1(&card1); 508 for (size_t i = 0; i < inputs.size(); ++i) { 509 EXPECT_EQ(wrapper1.GetInfo(AutofillType(inputs[i].type)), 510 view->GetTextContentsOfInput(inputs[i])); 511 } 512 513 // Try again with different data. Only expiration date and the triggering 514 // input should be overwritten. 515 value = card2.GetRawInfo(triggering_input.type); 516 view->SetTextContentsOfInput(triggering_input, 517 value.substr(0, value.size() / 2)); 518 view->ActivateInput(triggering_input); 519 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 520 controller()->DidAcceptSuggestion(string16(), 0); 521 522 AutofillCreditCardWrapper wrapper2(&card2); 523 for (size_t i = 0; i < inputs.size(); ++i) { 524 const DetailInput& input = inputs[i]; 525 if (&input == &triggering_input || 526 input.type == CREDIT_CARD_EXP_MONTH || 527 input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { 528 EXPECT_EQ(wrapper2.GetInfo(AutofillType(input.type)), 529 view->GetTextContentsOfInput(input)); 530 } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) { 531 EXPECT_TRUE(view->GetTextContentsOfInput(input).empty()); 532 } else { 533 EXPECT_EQ(wrapper1.GetInfo(AutofillType(input.type)), 534 view->GetTextContentsOfInput(input)); 535 } 536 } 537 538 // Now fill from a profile. It should not overwrite any CC info. 539 const DetailInputs& billing_inputs = 540 controller()->RequestedFieldsForSection(SECTION_BILLING); 541 const DetailInput& billing_triggering_input = billing_inputs[0]; 542 value = full_profile.GetRawInfo(triggering_input.type); 543 view->SetTextContentsOfInput(billing_triggering_input, 544 value.substr(0, value.size() / 2)); 545 view->ActivateInput(billing_triggering_input); 546 547 ASSERT_EQ(&billing_triggering_input, controller()->input_showing_popup()); 548 controller()->DidAcceptSuggestion(string16(), 0); 549 550 for (size_t i = 0; i < inputs.size(); ++i) { 551 const DetailInput& input = inputs[i]; 552 if (&input == &triggering_input || 553 input.type == CREDIT_CARD_EXP_MONTH || 554 input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { 555 EXPECT_EQ(wrapper2.GetInfo(AutofillType(input.type)), 556 view->GetTextContentsOfInput(input)); 557 } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) { 558 EXPECT_TRUE(view->GetTextContentsOfInput(input).empty()); 559 } else { 560 EXPECT_EQ(wrapper1.GetInfo(AutofillType(input.type)), 561 view->GetTextContentsOfInput(input)); 562 } 563 } 564} 565 566// Tests that credit card number is disabled while editing a Wallet instrument. 567IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, WalletCreditCardDisabled) { 568 controller()->OnUserNameFetchSuccess("user@example.com"); 569 570 scoped_ptr<wallet::WalletItems> wallet_items = 571 wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED); 572 // An expired card will be forced into edit mode. 573 wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentWithDetails( 574 "instrument_id", 575 wallet::GetTestAddress(), 576 wallet::WalletItems::MaskedInstrument::VISA, 577 wallet::WalletItems::MaskedInstrument::EXPIRED)); 578 controller()->OnDidGetWalletItems(wallet_items.Pass()); 579 580 const DetailInputs& edit_inputs = 581 controller()->RequestedFieldsForSection(SECTION_CC_BILLING); 582 size_t i; 583 for (i = 0; i < edit_inputs.size(); ++i) { 584 if (edit_inputs[i].type == CREDIT_CARD_NUMBER) { 585 EXPECT_FALSE(edit_inputs[i].editable); 586 break; 587 } 588 } 589 ASSERT_LT(i, edit_inputs.size()); 590 591 // Select "Add new billing info..." while using Wallet. 592 ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC_BILLING); 593 model->ActivatedAt(model->GetItemCount() - 2); 594 595 const DetailInputs& add_inputs = 596 controller()->RequestedFieldsForSection(SECTION_CC_BILLING); 597 for (i = 0; i < add_inputs.size(); ++i) { 598 if (add_inputs[i].type == CREDIT_CARD_NUMBER) { 599 EXPECT_TRUE(add_inputs[i].editable); 600 break; 601 } 602 } 603 ASSERT_LT(i, add_inputs.size()); 604} 605 606// Ensure that expired cards trigger invalid suggestions. 607IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ExpiredCard) { 608 CreditCard verified_card(test::GetCreditCard()); 609 verified_card.set_origin("Chrome settings"); 610 ASSERT_TRUE(verified_card.IsVerified()); 611 controller()->GetTestingManager()->AddTestingCreditCard(&verified_card); 612 613 CreditCard expired_card(test::GetCreditCard()); 614 expired_card.set_origin("Chrome settings"); 615 expired_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2007")); 616 ASSERT_TRUE(expired_card.IsVerified()); 617 ASSERT_FALSE( 618 autofill::IsValidCreditCardExpirationDate( 619 expired_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR), 620 expired_card.GetRawInfo(CREDIT_CARD_EXP_MONTH), 621 base::Time::Now())); 622 controller()->GetTestingManager()->AddTestingCreditCard(&expired_card); 623 624 ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC); 625 ASSERT_EQ(4, model->GetItemCount()); 626 627 ASSERT_TRUE(model->IsItemCheckedAt(0)); 628 EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC)); 629 630 model->ActivatedAt(1); 631 ASSERT_TRUE(model->IsItemCheckedAt(1)); 632 EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC)); 633} 634 635// Notifications with long message text should not make the dialog bigger. 636IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, LongNotifications) { 637 const gfx::Size no_notification_size = 638 controller()->GetTestableView()->GetSize(); 639 ASSERT_GT(no_notification_size.width(), 0); 640 641 std::vector<DialogNotification> notifications; 642 notifications.push_back( 643 DialogNotification(DialogNotification::DEVELOPER_WARNING, ASCIIToUTF16( 644 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " 645 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim " 646 "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " 647 "aliquip ex ea commodo consequat. Duis aute irure dolor in " 648 "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " 649 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " 650 "culpa qui officia deserunt mollit anim id est laborum."))); 651 controller()->set_notifications(notifications); 652 controller()->view()->UpdateNotificationArea(); 653 654 EXPECT_EQ(no_notification_size.width(), 655 controller()->GetTestableView()->GetSize().width()); 656} 657 658IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocompleteEvent) { 659 AutofillDialogControllerImpl* controller = 660 SetUpHtmlAndInvoke("<input autocomplete='cc-name'>"); 661 662 AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard()); 663 AddAutofillProfileToProfile(controller->profile(), 664 test::GetVerifiedProfile()); 665 666 TestableAutofillDialogView* view = controller->GetTestableView(); 667 view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123")); 668 view->SubmitForTesting(); 669 ExpectDomMessage("success"); 670} 671 672IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 673 AutocompleteErrorEventReasonInvalid) { 674 AutofillDialogControllerImpl* controller = 675 SetUpHtmlAndInvoke("<input autocomplete='cc-name' pattern='.*zebra.*'>"); 676 677 const CreditCard& credit_card = test::GetVerifiedCreditCard(); 678 ASSERT_TRUE( 679 credit_card.GetRawInfo(CREDIT_CARD_NAME).find(ASCIIToUTF16("zebra")) == 680 base::string16::npos); 681 AddCreditcardToProfile(controller->profile(), credit_card); 682 AddAutofillProfileToProfile(controller->profile(), 683 test::GetVerifiedProfile()); 684 685 TestableAutofillDialogView* view = controller->GetTestableView(); 686 view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123")); 687 view->SubmitForTesting(); 688 ExpectDomMessage("error: invalid"); 689} 690 691IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 692 AutocompleteErrorEventReasonCancel) { 693 SetUpHtmlAndInvoke("<input autocomplete='cc-name'>")->GetTestableView()-> 694 CancelForTesting(); 695 ExpectDomMessage("error: cancel"); 696} 697 698IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, NoCvcSegfault) { 699 controller()->set_use_validation(true); 700 701 CreditCard credit_card(test::GetVerifiedCreditCard()); 702 controller()->GetTestingManager()->AddTestingCreditCard(&credit_card); 703 EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC)); 704 705 ASSERT_NO_FATAL_FAILURE( 706 controller()->GetTestableView()->SubmitForTesting()); 707} 708 709// Flaky on Win7, WinXP, and Win Aura. http://crbug.com/270314. 710#if defined(OS_WIN) 711#define MAYBE_PreservedSections DISABLED_PreservedSections 712#else 713#define MAYBE_PreservedSections PreservedSections 714#endif 715IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_PreservedSections) { 716 controller()->set_use_validation(true); 717 718 // Set up some Autofill state. 719 CreditCard credit_card(test::GetVerifiedCreditCard()); 720 controller()->GetTestingManager()->AddTestingCreditCard(&credit_card); 721 722 AutofillProfile profile(test::GetVerifiedProfile()); 723 controller()->GetTestingManager()->AddTestingProfile(&profile); 724 725 EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC)); 726 EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING)); 727 EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING)); 728 EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING)); 729 730 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC)); 731 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING)); 732 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING)); 733 734 // Set up some Wallet state. 735 controller()->OnUserNameFetchSuccess("user@example.com"); 736 controller()->OnDidGetWalletItems( 737 wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED)); 738 739 ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser(); 740 ASSERT_TRUE(account_chooser->IsItemCheckedAt(0)); 741 742 // Check that the view's in the state we expect before starting to simulate 743 // user input. 744 EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC)); 745 EXPECT_FALSE(controller()->SectionIsActive(SECTION_BILLING)); 746 EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING)); 747 EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING)); 748 749 EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC_BILLING)); 750 751 // Create some valid inputted billing data. 752 const DetailInput& cc_number = 753 controller()->RequestedFieldsForSection(SECTION_CC_BILLING)[0]; 754 EXPECT_EQ(CREDIT_CARD_NUMBER, cc_number.type); 755 TestableAutofillDialogView* view = controller()->GetTestableView(); 756 view->SetTextContentsOfInput(cc_number, ASCIIToUTF16("4111111111111111")); 757 758 // Select "Add new shipping info..." from suggestions menu. 759 ui::MenuModel* shipping_model = 760 controller()->MenuModelForSection(SECTION_SHIPPING); 761 shipping_model->ActivatedAt(shipping_model->GetItemCount() - 2); 762 763 EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING)); 764 765 // Create some invalid, manually inputted shipping data. 766 const DetailInput& shipping_zip = 767 controller()->RequestedFieldsForSection(SECTION_SHIPPING)[5]; 768 ASSERT_EQ(ADDRESS_HOME_ZIP, shipping_zip.type); 769 view->SetTextContentsOfInput(shipping_zip, ASCIIToUTF16("shipping zip")); 770 771 // Switch to using Autofill. 772 account_chooser->ActivatedAt(1); 773 774 // Check that appropriate sections are preserved and in manually editing mode 775 // (or disabled, in the case of the combined cc + billing section). 776 EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC)); 777 EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING)); 778 EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING)); 779 EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING)); 780 781 EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC)); 782 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING)); 783 EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING)); 784 785 const DetailInput& new_cc_number = 786 controller()->RequestedFieldsForSection(SECTION_CC).front(); 787 EXPECT_EQ(cc_number.type, new_cc_number.type); 788 EXPECT_EQ(ASCIIToUTF16("4111111111111111"), 789 view->GetTextContentsOfInput(new_cc_number)); 790 791 EXPECT_NE(ASCIIToUTF16("shipping name"), 792 view->GetTextContentsOfInput(shipping_zip)); 793} 794#endif // defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) 795 796} // namespace autofill 797