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