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/logging.h" 8 #include "base/memory/ref_counted.h" 9 #include "base/memory/weak_ptr.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/prefs/pref_service.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/time/time.h" 14 #include "chrome/browser/autofill/personal_data_manager_factory.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/ui/autofill/account_chooser_model.h" 17 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h" 18 #include "chrome/browser/ui/autofill/autofill_dialog_view.h" 19 #include "chrome/browser/ui/autofill/data_model_wrapper.h" 20 #include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h" 21 #include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h" 22 #include "chrome/browser/ui/autofill/testable_autofill_dialog_view.h" 23 #include "chrome/browser/ui/browser.h" 24 #include "chrome/browser/ui/browser_tabstrip.h" 25 #include "chrome/browser/ui/tabs/tab_strip_model.h" 26 #include "chrome/common/pref_names.h" 27 #include "chrome/common/url_constants.h" 28 #include "chrome/test/base/in_process_browser_test.h" 29 #include "chrome/test/base/ui_test_utils.h" 30 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h" 31 #include "components/autofill/content/browser/wallet/mock_wallet_client.h" 32 #include "components/autofill/content/browser/wallet/wallet_test_util.h" 33 #include "components/autofill/core/browser/autofill_metrics.h" 34 #include "components/autofill/core/browser/autofill_test_utils.h" 35 #include "components/autofill/core/browser/test_personal_data_manager.h" 36 #include "components/autofill/core/browser/validation.h" 37 #include "components/autofill/core/common/autofill_switches.h" 38 #include "components/autofill/core/common/form_data.h" 39 #include "components/autofill/core/common/form_field_data.h" 40 #include "content/public/browser/browser_thread.h" 41 #include "content/public/browser/interstitial_page.h" 42 #include "content/public/browser/navigation_details.h" 43 #include "content/public/browser/navigation_entry.h" 44 #include "content/public/browser/notification_service.h" 45 #include "content/public/browser/notification_types.h" 46 #include "content/public/browser/page_navigator.h" 47 #include "content/public/browser/web_contents.h" 48 #include "content/public/browser/web_contents_delegate.h" 49 #include "content/public/common/content_switches.h" 50 #include "content/public/common/page_transition_types.h" 51 #include "content/public/common/referrer.h" 52 #include "content/public/common/url_constants.h" 53 #include "content/public/test/browser_test_utils.h" 54 #include "content/public/test/test_utils.h" 55 #include "google_apis/gaia/google_service_auth_error.h" 56 #include "net/test/spawned_test_server/spawned_test_server.h" 57 #include "testing/gmock/include/gmock/gmock.h" 58 #include "testing/gtest/include/gtest/gtest.h" 59 #include "third_party/WebKit/public/web/WebInputEvent.h" 60 #include "ui/base/window_open_disposition.h" 61 #include "url/gurl.h" 62 63 #if defined(OS_MACOSX) 64 #include "base/mac/mac_util.h" 65 #include "base/mac/scoped_nsautorelease_pool.h" 66 #include "chrome/browser/ui/cocoa/run_loop_testing.h" 67 #endif 68 69 namespace autofill { 70 71 namespace { 72 73 using testing::_; 74 75 void MockCallback(const FormStructure*) {} 76 77 class MockAutofillMetrics : public AutofillMetrics { 78 public: 79 MockAutofillMetrics() 80 : dialog_dismissal_action_( 81 static_cast<AutofillMetrics::DialogDismissalAction>(-1)) {} 82 virtual ~MockAutofillMetrics() {} 83 84 virtual void LogDialogUiDuration( 85 const base::TimeDelta& duration, 86 DialogDismissalAction dismissal_action) const OVERRIDE { 87 // Ignore constness for testing. 88 MockAutofillMetrics* mutable_this = const_cast<MockAutofillMetrics*>(this); 89 mutable_this->dialog_dismissal_action_ = dismissal_action; 90 } 91 92 AutofillMetrics::DialogDismissalAction dialog_dismissal_action() const { 93 return dialog_dismissal_action_; 94 } 95 96 MOCK_CONST_METHOD1(LogDialogDismissalState, 97 void(DialogDismissalState state)); 98 99 private: 100 AutofillMetrics::DialogDismissalAction dialog_dismissal_action_; 101 102 DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics); 103 }; 104 105 class TestAutofillDialogController : public AutofillDialogControllerImpl { 106 public: 107 TestAutofillDialogController( 108 content::WebContents* contents, 109 const FormData& form_data, 110 const AutofillMetrics& metric_logger, 111 scoped_refptr<content::MessageLoopRunner> runner) 112 : AutofillDialogControllerImpl(contents, 113 form_data, 114 form_data.origin, 115 base::Bind(&MockCallback)), 116 metric_logger_(metric_logger), 117 mock_wallet_client_( 118 Profile::FromBrowserContext(contents->GetBrowserContext())-> 119 GetRequestContext(), this, form_data.origin), 120 message_loop_runner_(runner), 121 use_validation_(false), 122 weak_ptr_factory_(this), 123 sign_in_user_index_(0U) {} 124 125 virtual ~TestAutofillDialogController() {} 126 127 virtual GURL SignInUrl() const OVERRIDE { 128 return GURL(chrome::kChromeUIVersionURL); 129 } 130 131 GURL SignInContinueUrl() const { 132 return GURL(content::kAboutBlankURL); 133 } 134 135 virtual void ViewClosed() OVERRIDE { 136 message_loop_runner_->Quit(); 137 AutofillDialogControllerImpl::ViewClosed(); 138 } 139 140 virtual base::string16 InputValidityMessage( 141 DialogSection section, 142 ServerFieldType type, 143 const base::string16& value) OVERRIDE { 144 if (!use_validation_) 145 return base::string16(); 146 return AutofillDialogControllerImpl::InputValidityMessage( 147 section, type, value); 148 } 149 150 virtual ValidityMessages InputsAreValid( 151 DialogSection section, 152 const FieldValueMap& inputs) OVERRIDE { 153 if (!use_validation_) 154 return ValidityMessages(); 155 return AutofillDialogControllerImpl::InputsAreValid(section, inputs); 156 } 157 158 // Saving to Chrome is tested in AutofillDialogControllerImpl unit tests. 159 // TODO(estade): test that the view defaults to saving to Chrome. 160 virtual bool ShouldOfferToSaveInChrome() const OVERRIDE { 161 return false; 162 } 163 164 void ForceFinishSubmit() { 165 DoFinishSubmit(); 166 } 167 168 // Increase visibility for testing. 169 using AutofillDialogControllerImpl::view; 170 using AutofillDialogControllerImpl::input_showing_popup; 171 172 MOCK_METHOD0(LoadRiskFingerprintData, void()); 173 174 virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE { 175 return notifications_; 176 } 177 178 void set_notifications(const std::vector<DialogNotification>& notifications) { 179 notifications_ = notifications; 180 } 181 182 TestPersonalDataManager* GetTestingManager() { 183 return &test_manager_; 184 } 185 186 using AutofillDialogControllerImpl::IsEditingExistingData; 187 using AutofillDialogControllerImpl::IsPayingWithWallet; 188 using AutofillDialogControllerImpl::IsSubmitPausedOn; 189 using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData; 190 using AutofillDialogControllerImpl::AccountChooserModelForTesting; 191 using AutofillDialogControllerImpl:: 192 ClearLastWalletItemsFetchTimestampForTesting; 193 194 void set_use_validation(bool use_validation) { 195 use_validation_ = use_validation; 196 } 197 198 base::WeakPtr<TestAutofillDialogController> AsWeakPtr() { 199 return weak_ptr_factory_.GetWeakPtr(); 200 } 201 202 wallet::MockWalletClient* GetTestingWalletClient() { 203 return &mock_wallet_client_; 204 } 205 206 void set_sign_in_user_index(size_t sign_in_user_index) { 207 sign_in_user_index_ = sign_in_user_index; 208 } 209 210 protected: 211 virtual PersonalDataManager* GetManager() const OVERRIDE { 212 return &const_cast<TestAutofillDialogController*>(this)->test_manager_; 213 } 214 215 virtual wallet::WalletClient* GetWalletClient() OVERRIDE { 216 return &mock_wallet_client_; 217 } 218 219 virtual bool IsSignInContinueUrl(const GURL& url, size_t* user_index) const 220 OVERRIDE { 221 *user_index = sign_in_user_index_; 222 return url == SignInContinueUrl(); 223 } 224 225 private: 226 // To specify our own metric logger. 227 virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE { 228 return metric_logger_; 229 } 230 231 const AutofillMetrics& metric_logger_; 232 TestPersonalDataManager test_manager_; 233 testing::NiceMock<wallet::MockWalletClient> mock_wallet_client_; 234 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; 235 bool use_validation_; 236 237 // A list of notifications to show in the notification area of the dialog. 238 // This is used to control what |CurrentNotifications()| returns for testing. 239 std::vector<DialogNotification> notifications_; 240 241 // Allows generation of WeakPtrs, so controller liveness can be tested. 242 base::WeakPtrFactory<TestAutofillDialogController> weak_ptr_factory_; 243 244 // The user index that is assigned in IsSignInContinueUrl(). 245 size_t sign_in_user_index_; 246 247 DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController); 248 }; 249 250 // This is a copy of ui_test_utils::UrlLoadObserver, except it observes 251 // NAV_ENTRY_COMMITTED instead of LOAD_STOP. This is to match the notification 252 // that AutofillDialogControllerImpl observes. Since NAV_ENTRY_COMMITTED comes 253 // before LOAD_STOP, and the controller deletes the web contents after receiving 254 // the former, we will sometimes fail to observe a LOAD_STOP. 255 // TODO(estade): Should the controller observe LOAD_STOP instead? 256 class NavEntryCommittedObserver : public content::WindowedNotificationObserver { 257 public: 258 NavEntryCommittedObserver(const GURL& url, 259 const content::NotificationSource& source) 260 : WindowedNotificationObserver(content::NOTIFICATION_NAV_ENTRY_COMMITTED, 261 source), 262 url_(url) {} 263 264 virtual ~NavEntryCommittedObserver() {} 265 266 // content::NotificationObserver: 267 virtual void Observe(int type, 268 const content::NotificationSource& source, 269 const content::NotificationDetails& details) OVERRIDE { 270 content::LoadCommittedDetails* load_details = 271 content::Details<content::LoadCommittedDetails>(details).ptr(); 272 if (load_details->entry->GetVirtualURL() != url_) 273 return; 274 275 WindowedNotificationObserver::Observe(type, source, details); 276 } 277 278 private: 279 GURL url_; 280 281 DISALLOW_COPY_AND_ASSIGN(NavEntryCommittedObserver); 282 }; 283 284 } // namespace 285 286 class AutofillDialogControllerTest : public InProcessBrowserTest { 287 public: 288 AutofillDialogControllerTest() {} 289 virtual ~AutofillDialogControllerTest() {} 290 291 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 292 command_line->AppendSwitch(::switches::kReduceSecurityForTesting); 293 } 294 295 virtual void SetUpOnMainThread() OVERRIDE { 296 autofill::test::DisableSystemServices(browser()->profile()); 297 InitializeController(); 298 } 299 300 // A helper function that cycles the MessageLoop, and on Mac, the Cocoa run 301 // loop. It also drains the NSAutoreleasePool. 302 void CycleRunLoops() { 303 content::RunAllPendingInMessageLoop(); 304 #if defined(OS_MACOSX) 305 chrome::testing::NSRunLoopRunAllPending(); 306 AutoreleasePool()->Recycle(); 307 #endif 308 } 309 310 void InitializeController() { 311 FormData form; 312 form.name = ASCIIToUTF16("TestForm"); 313 form.method = ASCIIToUTF16("POST"); 314 form.user_submitted = true; 315 316 FormFieldData field; 317 field.autocomplete_attribute = "shipping tel"; 318 form.fields.push_back(field); 319 320 test_generated_bubble_controller_ = 321 new testing::NiceMock<TestGeneratedCreditCardBubbleController>( 322 GetActiveWebContents()); 323 ASSERT_TRUE(test_generated_bubble_controller_->IsInstalled()); 324 325 message_loop_runner_ = new content::MessageLoopRunner; 326 controller_ = new TestAutofillDialogController( 327 GetActiveWebContents(), 328 form, 329 metric_logger_, 330 message_loop_runner_); 331 controller_->Show(); 332 CycleRunLoops(); // Ensures dialog is fully visible. 333 } 334 335 content::WebContents* GetActiveWebContents() { 336 return browser()->tab_strip_model()->GetActiveWebContents(); 337 } 338 339 const MockAutofillMetrics& metric_logger() { return metric_logger_; } 340 TestAutofillDialogController* controller() { return controller_; } 341 342 void RunMessageLoop() { 343 message_loop_runner_->Run(); 344 } 345 346 // Loads an HTML page in |GetActiveWebContents()| with markup as follows: 347 // <form>|form_inner_html|</form>. After loading, emulates a click event on 348 // the page as requestAutocomplete() must be in response to a user gesture. 349 // Returns the |AutofillDialogControllerImpl| created by this invocation. 350 AutofillDialogControllerImpl* SetUpHtmlAndInvoke( 351 const std::string& form_inner_html) { 352 content::WebContents* contents = GetActiveWebContents(); 353 TabAutofillManagerDelegate* delegate = 354 TabAutofillManagerDelegate::FromWebContents(contents); 355 CHECK(!delegate->GetDialogControllerForTesting()); 356 357 ui_test_utils::NavigateToURL( 358 browser(), GURL(std::string("data:text/html,") + 359 "<!doctype html>" 360 "<html>" 361 "<body>" 362 "<form>" + form_inner_html + "</form>" 363 "<script>" 364 "function send(msg) {" 365 "domAutomationController.setAutomationId(0);" 366 "domAutomationController.send(msg);" 367 "}" 368 "document.forms[0].onautocompleteerror = function(e) {" 369 "send('error: ' + e.reason);" 370 "};" 371 "document.forms[0].onautocomplete = function() {" 372 "send('success');" 373 "};" 374 "window.onclick = function() {" 375 "document.forms[0].requestAutocomplete();" 376 "send('clicked');" 377 "};" 378 "function getValueForFieldOfType(type) {" 379 " var fields = document.getElementsByTagName('input');" 380 " for (var i = 0; i < fields.length; i++) {" 381 " if (fields[i].autocomplete == type) {" 382 " send(fields[i].value);" 383 " return;" 384 " }" 385 " }" 386 " send('');" 387 "};" 388 "</script>" 389 "</body>" 390 "</html>")); 391 392 InitiateDialog(); 393 AutofillDialogControllerImpl* controller = 394 static_cast<AutofillDialogControllerImpl*>( 395 delegate->GetDialogControllerForTesting()); 396 return controller; 397 } 398 399 // Loads an html page on a provided server, the causes it to launch rAc. 400 // Returns whether rAc succesfully launched. 401 bool RunTestPage(const net::SpawnedTestServer& server) { 402 GURL url = server.GetURL( 403 "files/request_autocomplete/test_page.html"); 404 ui_test_utils::NavigateToURL(browser(), url); 405 406 // Pass through the broken SSL interstitial, if any. 407 content::WebContents* contents = GetActiveWebContents(); 408 content::InterstitialPage* interstitial_page = 409 contents->GetInterstitialPage(); 410 if (interstitial_page) { 411 ui_test_utils::UrlLoadObserver observer( 412 url, 413 content::Source<content::NavigationController>( 414 &contents->GetController())); 415 interstitial_page->Proceed(); 416 observer.Wait(); 417 } 418 419 InitiateDialog(); 420 421 TabAutofillManagerDelegate* delegate = 422 TabAutofillManagerDelegate::FromWebContents(contents); 423 AutofillDialogControllerImpl* controller = 424 static_cast<AutofillDialogControllerImpl*>( 425 delegate->GetDialogControllerForTesting()); 426 return !!controller; 427 } 428 429 // Wait for a message from the DOM automation controller (from JS in the 430 // page). Requires |SetUpHtmlAndInvoke()| be called first. 431 void ExpectDomMessage(const std::string& expected) { 432 std::string message; 433 ASSERT_TRUE(dom_message_queue_->WaitForMessage(&message)); 434 dom_message_queue_->ClearQueue(); 435 EXPECT_EQ("\"" + expected + "\"", message); 436 } 437 438 void InitiateDialog() { 439 dom_message_queue_.reset(new content::DOMMessageQueue); 440 441 // Triggers the onclick handler which invokes requestAutocomplete(). 442 content::WebContents* contents = GetActiveWebContents(); 443 content::SimulateMouseClick(contents, 0, blink::WebMouseEvent::ButtonLeft); 444 ExpectDomMessage("clicked"); 445 } 446 447 // Returns the value filled into the first field with autocomplete attribute 448 // equal to |autocomplete_type|, or an empty string if there is no such field. 449 std::string GetValueForHTMLFieldOfType(const std::string& autocomplete_type) { 450 content::RenderViewHost* render_view_host = 451 browser()->tab_strip_model()->GetActiveWebContents()-> 452 GetRenderViewHost(); 453 std::string script = "getValueForFieldOfType('" + autocomplete_type + "');"; 454 std::string result; 455 EXPECT_TRUE(content::ExecuteScriptAndExtractString(render_view_host, script, 456 &result)); 457 return result; 458 } 459 460 void AddCreditcardToProfile(Profile* profile, const CreditCard& card) { 461 PersonalDataManagerFactory::GetForProfile(profile)->AddCreditCard(card); 462 WaitForWebDB(); 463 } 464 465 void AddAutofillProfileToProfile(Profile* profile, 466 const AutofillProfile& autofill_profile) { 467 PersonalDataManagerFactory::GetForProfile(profile)->AddProfile( 468 autofill_profile); 469 WaitForWebDB(); 470 } 471 472 TestGeneratedCreditCardBubbleController* test_generated_bubble_controller() { 473 return test_generated_bubble_controller_; 474 } 475 476 private: 477 void WaitForWebDB() { 478 content::RunAllPendingInMessageLoop(content::BrowserThread::DB); 479 } 480 481 testing::NiceMock<MockAutofillMetrics> metric_logger_; 482 TestAutofillDialogController* controller_; // Weak reference. 483 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; 484 scoped_ptr<content::DOMMessageQueue> dom_message_queue_; 485 486 // Weak; owned by the active web contents. 487 TestGeneratedCreditCardBubbleController* test_generated_bubble_controller_; 488 489 DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerTest); 490 }; 491 492 #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) 493 // Submit the form data. 494 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Submit) { 495 controller()->GetTestableView()->SubmitForTesting(); 496 497 RunMessageLoop(); 498 499 EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED, 500 metric_logger().dialog_dismissal_action()); 501 } 502 503 // Cancel out of the dialog. 504 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Cancel) { 505 controller()->GetTestableView()->CancelForTesting(); 506 507 RunMessageLoop(); 508 509 EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED, 510 metric_logger().dialog_dismissal_action()); 511 } 512 513 // Take some other action that dismisses the dialog. 514 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Hide) { 515 controller()->Hide(); 516 517 RunMessageLoop(); 518 519 EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED, 520 metric_logger().dialog_dismissal_action()); 521 } 522 523 // Ensure that Hide() will only destroy the controller object after the 524 // message loop has run. Otherwise, there may be read-after-free issues 525 // during some tests. 526 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, DeferredDestruction) { 527 base::WeakPtr<TestAutofillDialogController> weak_ptr = 528 controller()->AsWeakPtr(); 529 EXPECT_TRUE(weak_ptr.get()); 530 531 controller()->Hide(); 532 EXPECT_TRUE(weak_ptr.get()); 533 534 RunMessageLoop(); 535 EXPECT_FALSE(weak_ptr.get()); 536 } 537 538 // Ensure that the expected metric is logged when the dialog is closed during 539 // signin. 540 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, CloseDuringSignin) { 541 controller()->SignInLinkClicked(); 542 543 EXPECT_CALL(metric_logger(), 544 LogDialogDismissalState( 545 AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN)); 546 controller()->GetTestableView()->CancelForTesting(); 547 548 RunMessageLoop(); 549 550 EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED, 551 metric_logger().dialog_dismissal_action()); 552 } 553 554 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, FillInputFromAutofill) { 555 AutofillProfile full_profile(test::GetFullProfile()); 556 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 557 558 const DetailInputs& inputs = 559 controller()->RequestedFieldsForSection(SECTION_SHIPPING); 560 const DetailInput& triggering_input = inputs[0]; 561 base::string16 value = full_profile.GetRawInfo(triggering_input.type); 562 TestableAutofillDialogView* view = controller()->GetTestableView(); 563 view->SetTextContentsOfInput(triggering_input, 564 value.substr(0, value.size() / 2)); 565 view->ActivateInput(triggering_input); 566 567 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 568 controller()->DidAcceptSuggestion(base::string16(), 0); 569 570 // All inputs should be filled. 571 AutofillProfileWrapper wrapper(&full_profile); 572 for (size_t i = 0; i < inputs.size(); ++i) { 573 EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)), 574 view->GetTextContentsOfInput(inputs[i])); 575 } 576 577 // Now simulate some user edits and try again. 578 std::vector<base::string16> expectations; 579 for (size_t i = 0; i < inputs.size(); ++i) { 580 base::string16 users_input = i % 2 == 0 ? base::string16() 581 : ASCIIToUTF16("dummy"); 582 view->SetTextContentsOfInput(inputs[i], users_input); 583 // Empty inputs should be filled, others should be left alone. 584 base::string16 expectation = 585 &inputs[i] == &triggering_input || users_input.empty() ? 586 wrapper.GetInfo(AutofillType(inputs[i].type)) : 587 users_input; 588 expectations.push_back(expectation); 589 } 590 591 view->SetTextContentsOfInput(triggering_input, 592 value.substr(0, value.size() / 2)); 593 view->ActivateInput(triggering_input); 594 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 595 controller()->DidAcceptSuggestion(base::string16(), 0); 596 597 for (size_t i = 0; i < inputs.size(); ++i) { 598 EXPECT_EQ(expectations[i], view->GetTextContentsOfInput(inputs[i])); 599 } 600 } 601 602 // For now, no matter what, the country must always be US. See 603 // http://crbug.com/247518 604 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 605 FillInputFromForeignProfile) { 606 AutofillProfile full_profile(test::GetFullProfile()); 607 full_profile.SetInfo(AutofillType(ADDRESS_HOME_COUNTRY), 608 ASCIIToUTF16("France"), "en-US"); 609 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 610 611 const DetailInputs& inputs = 612 controller()->RequestedFieldsForSection(SECTION_SHIPPING); 613 const DetailInput& triggering_input = inputs[0]; 614 base::string16 value = full_profile.GetRawInfo(triggering_input.type); 615 TestableAutofillDialogView* view = controller()->GetTestableView(); 616 view->SetTextContentsOfInput(triggering_input, 617 value.substr(0, value.size() / 2)); 618 view->ActivateInput(triggering_input); 619 620 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 621 controller()->DidAcceptSuggestion(base::string16(), 0); 622 623 // All inputs should be filled. 624 AutofillProfileWrapper wrapper(&full_profile); 625 for (size_t i = 0; i < inputs.size(); ++i) { 626 base::string16 expectation = 627 AutofillType(inputs[i].type).GetStorableType() == ADDRESS_HOME_COUNTRY ? 628 ASCIIToUTF16("United States") : 629 wrapper.GetInfo(AutofillType(inputs[i].type)); 630 EXPECT_EQ(expectation, view->GetTextContentsOfInput(inputs[i])); 631 } 632 633 // Now simulate some user edits and try again. 634 std::vector<base::string16> expectations; 635 for (size_t i = 0; i < inputs.size(); ++i) { 636 base::string16 users_input = i % 2 == 0 ? base::string16() 637 : ASCIIToUTF16("dummy"); 638 view->SetTextContentsOfInput(inputs[i], users_input); 639 // Empty inputs should be filled, others should be left alone. 640 base::string16 expectation = 641 &inputs[i] == &triggering_input || users_input.empty() ? 642 wrapper.GetInfo(AutofillType(inputs[i].type)) : 643 users_input; 644 if (AutofillType(inputs[i].type).GetStorableType() == ADDRESS_HOME_COUNTRY) 645 expectation = ASCIIToUTF16("United States"); 646 647 expectations.push_back(expectation); 648 } 649 650 view->SetTextContentsOfInput(triggering_input, 651 value.substr(0, value.size() / 2)); 652 view->ActivateInput(triggering_input); 653 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 654 controller()->DidAcceptSuggestion(base::string16(), 0); 655 656 for (size_t i = 0; i < inputs.size(); ++i) { 657 EXPECT_EQ(expectations[i], view->GetTextContentsOfInput(inputs[i])); 658 } 659 } 660 661 // This test makes sure that picking a profile variant in the Autofill 662 // popup works as expected. 663 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 664 FillInputFromAutofillVariant) { 665 AutofillProfile full_profile(test::GetFullProfile()); 666 667 // Set up some variant data. 668 std::vector<base::string16> names; 669 names.push_back(ASCIIToUTF16("John Doe")); 670 names.push_back(ASCIIToUTF16("Jane Doe")); 671 full_profile.SetRawMultiInfo(NAME_FULL, names); 672 std::vector<base::string16> emails; 673 emails.push_back(ASCIIToUTF16("user (at) example.com")); 674 emails.push_back(ASCIIToUTF16("admin (at) example.com")); 675 full_profile.SetRawMultiInfo(EMAIL_ADDRESS, emails); 676 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 677 678 const DetailInputs& inputs = 679 controller()->RequestedFieldsForSection(SECTION_BILLING); 680 const DetailInput& triggering_input = inputs[0]; 681 EXPECT_EQ(NAME_BILLING_FULL, triggering_input.type); 682 TestableAutofillDialogView* view = controller()->GetTestableView(); 683 view->ActivateInput(triggering_input); 684 685 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 686 687 // Choose the variant suggestion. 688 controller()->DidAcceptSuggestion(base::string16(), 1); 689 690 // All inputs should be filled. 691 AutofillProfileWrapper wrapper( 692 &full_profile, AutofillType(NAME_BILLING_FULL), 1); 693 for (size_t i = 0; i < inputs.size(); ++i) { 694 EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)), 695 view->GetTextContentsOfInput(inputs[i])); 696 } 697 698 // Make sure the wrapper applies the variant index to the right group. 699 EXPECT_EQ(names[1], wrapper.GetInfo(AutofillType(NAME_BILLING_FULL))); 700 // Make sure the wrapper doesn't apply the variant index to the wrong group. 701 EXPECT_EQ(emails[0], wrapper.GetInfo(AutofillType(EMAIL_ADDRESS))); 702 } 703 704 // Tests that changing the value of a CC expiration date combobox works as 705 // expected when Autofill is used to fill text inputs. 706 // 707 // Flaky on Win7, WinXP, and Win Aura. http://crbug.com/270314. 708 #if defined(OS_WIN) 709 #define MAYBE_FillComboboxFromAutofill DISABLED_FillComboboxFromAutofill 710 #else 711 #define MAYBE_FillComboboxFromAutofill FillComboboxFromAutofill 712 #endif 713 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 714 MAYBE_FillComboboxFromAutofill) { 715 CreditCard card1; 716 test::SetCreditCardInfo(&card1, "JJ Smith", "4111111111111111", "12", "2018"); 717 controller()->GetTestingManager()->AddTestingCreditCard(&card1); 718 CreditCard card2; 719 test::SetCreditCardInfo(&card2, "B Bird", "3111111111111111", "11", "2017"); 720 controller()->GetTestingManager()->AddTestingCreditCard(&card2); 721 AutofillProfile full_profile(test::GetFullProfile()); 722 controller()->GetTestingManager()->AddTestingProfile(&full_profile); 723 724 const DetailInputs& inputs = 725 controller()->RequestedFieldsForSection(SECTION_CC); 726 const DetailInput& triggering_input = inputs[0]; 727 base::string16 value = card1.GetRawInfo(triggering_input.type); 728 TestableAutofillDialogView* view = controller()->GetTestableView(); 729 view->SetTextContentsOfInput(triggering_input, 730 value.substr(0, value.size() / 2)); 731 view->ActivateInput(triggering_input); 732 733 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 734 controller()->DidAcceptSuggestion(base::string16(), 0); 735 736 // All inputs should be filled. 737 AutofillCreditCardWrapper wrapper1(&card1); 738 for (size_t i = 0; i < inputs.size(); ++i) { 739 EXPECT_EQ(wrapper1.GetInfo(AutofillType(inputs[i].type)), 740 view->GetTextContentsOfInput(inputs[i])); 741 } 742 743 // Try again with different data. Only expiration date and the triggering 744 // input should be overwritten. 745 value = card2.GetRawInfo(triggering_input.type); 746 view->SetTextContentsOfInput(triggering_input, 747 value.substr(0, value.size() / 2)); 748 view->ActivateInput(triggering_input); 749 ASSERT_EQ(&triggering_input, controller()->input_showing_popup()); 750 controller()->DidAcceptSuggestion(base::string16(), 0); 751 752 AutofillCreditCardWrapper wrapper2(&card2); 753 for (size_t i = 0; i < inputs.size(); ++i) { 754 const DetailInput& input = inputs[i]; 755 if (&input == &triggering_input || 756 input.type == CREDIT_CARD_EXP_MONTH || 757 input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { 758 EXPECT_EQ(wrapper2.GetInfo(AutofillType(input.type)), 759 view->GetTextContentsOfInput(input)); 760 } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) { 761 EXPECT_TRUE(view->GetTextContentsOfInput(input).empty()); 762 } else { 763 EXPECT_EQ(wrapper1.GetInfo(AutofillType(input.type)), 764 view->GetTextContentsOfInput(input)); 765 } 766 } 767 768 // Now fill from a profile. It should not overwrite any CC info. 769 const DetailInputs& billing_inputs = 770 controller()->RequestedFieldsForSection(SECTION_BILLING); 771 const DetailInput& billing_triggering_input = billing_inputs[0]; 772 value = full_profile.GetRawInfo(triggering_input.type); 773 view->SetTextContentsOfInput(billing_triggering_input, 774 value.substr(0, value.size() / 2)); 775 view->ActivateInput(billing_triggering_input); 776 777 ASSERT_EQ(&billing_triggering_input, controller()->input_showing_popup()); 778 controller()->DidAcceptSuggestion(base::string16(), 0); 779 780 for (size_t i = 0; i < inputs.size(); ++i) { 781 const DetailInput& input = inputs[i]; 782 if (&input == &triggering_input || 783 input.type == CREDIT_CARD_EXP_MONTH || 784 input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { 785 EXPECT_EQ(wrapper2.GetInfo(AutofillType(input.type)), 786 view->GetTextContentsOfInput(input)); 787 } else if (input.type == CREDIT_CARD_VERIFICATION_CODE) { 788 EXPECT_TRUE(view->GetTextContentsOfInput(input).empty()); 789 } else { 790 EXPECT_EQ(wrapper1.GetInfo(AutofillType(input.type)), 791 view->GetTextContentsOfInput(input)); 792 } 793 } 794 } 795 796 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ShouldShowErrorBubble) { 797 EXPECT_TRUE(controller()->ShouldShowErrorBubble()); 798 799 CreditCard card(test::GetCreditCard()); 800 ASSERT_FALSE(card.IsVerified()); 801 controller()->GetTestingManager()->AddTestingCreditCard(&card); 802 803 const DetailInputs& cc_inputs = 804 controller()->RequestedFieldsForSection(SECTION_CC); 805 const DetailInput& cc_number_input = cc_inputs[0]; 806 ASSERT_EQ(CREDIT_CARD_NUMBER, cc_number_input.type); 807 808 TestableAutofillDialogView* view = controller()->GetTestableView(); 809 view->SetTextContentsOfInput( 810 cc_number_input, 811 card.GetRawInfo(CREDIT_CARD_NUMBER).substr(0, 1)); 812 813 view->ActivateInput(cc_number_input); 814 EXPECT_FALSE(controller()->ShouldShowErrorBubble()); 815 816 controller()->FocusMoved(); 817 EXPECT_TRUE(controller()->ShouldShowErrorBubble()); 818 } 819 820 // Ensure that expired cards trigger invalid suggestions. 821 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ExpiredCard) { 822 CreditCard verified_card(test::GetCreditCard()); 823 verified_card.set_origin("Chrome settings"); 824 ASSERT_TRUE(verified_card.IsVerified()); 825 controller()->GetTestingManager()->AddTestingCreditCard(&verified_card); 826 827 CreditCard expired_card(test::GetCreditCard()); 828 expired_card.set_origin("Chrome settings"); 829 expired_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2007")); 830 ASSERT_TRUE(expired_card.IsVerified()); 831 ASSERT_FALSE( 832 autofill::IsValidCreditCardExpirationDate( 833 expired_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR), 834 expired_card.GetRawInfo(CREDIT_CARD_EXP_MONTH), 835 base::Time::Now())); 836 controller()->GetTestingManager()->AddTestingCreditCard(&expired_card); 837 838 ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC); 839 ASSERT_EQ(4, model->GetItemCount()); 840 841 ASSERT_TRUE(model->IsItemCheckedAt(0)); 842 EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC)); 843 844 model->ActivatedAt(1); 845 ASSERT_TRUE(model->IsItemCheckedAt(1)); 846 EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC)); 847 } 848 849 // Notifications with long message text should not make the dialog bigger. 850 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, LongNotifications) { 851 const gfx::Size no_notification_size = 852 controller()->GetTestableView()->GetSize(); 853 ASSERT_GT(no_notification_size.width(), 0); 854 855 std::vector<DialogNotification> notifications; 856 notifications.push_back( 857 DialogNotification(DialogNotification::DEVELOPER_WARNING, ASCIIToUTF16( 858 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " 859 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim " 860 "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " 861 "aliquip ex ea commodo consequat. Duis aute irure dolor in " 862 "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " 863 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " 864 "culpa qui officia deserunt mollit anim id est laborum."))); 865 controller()->set_notifications(notifications); 866 controller()->view()->UpdateNotificationArea(); 867 868 EXPECT_EQ(no_notification_size.width(), 869 controller()->GetTestableView()->GetSize().width()); 870 } 871 872 // http://crbug.com/318526 873 #if defined(OS_MACOSX) 874 #define MAYBE_AutocompleteEvent DISABLED_AutocompleteEvent 875 #else 876 #define MAYBE_AutocompleteEvent AutocompleteEvent 877 #endif 878 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_AutocompleteEvent) { 879 AutofillDialogControllerImpl* controller = 880 SetUpHtmlAndInvoke("<input autocomplete='cc-name'>"); 881 ASSERT_TRUE(controller); 882 883 AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard()); 884 AddAutofillProfileToProfile(controller->profile(), 885 test::GetVerifiedProfile()); 886 887 TestableAutofillDialogView* view = controller->GetTestableView(); 888 view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123")); 889 view->SubmitForTesting(); 890 ExpectDomMessage("success"); 891 } 892 893 // http://crbug.com/318526 894 #if defined(OS_MACOSX) 895 #define MAYBE_AutocompleteErrorEventReasonInvalid \ 896 DISABLED_AutocompleteErrorEventReasonInvalid 897 #else 898 #define MAYBE_AutocompleteErrorEventReasonInvalid \ 899 AutocompleteErrorEventReasonInvalid 900 #endif 901 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 902 MAYBE_AutocompleteErrorEventReasonInvalid) { 903 AutofillDialogControllerImpl* controller = 904 SetUpHtmlAndInvoke("<input autocomplete='cc-name' pattern='.*zebra.*'>"); 905 ASSERT_TRUE(controller); 906 907 const CreditCard& credit_card = test::GetVerifiedCreditCard(); 908 ASSERT_TRUE( 909 credit_card.GetRawInfo(CREDIT_CARD_NAME).find(ASCIIToUTF16("zebra")) == 910 base::string16::npos); 911 AddCreditcardToProfile(controller->profile(), credit_card); 912 AddAutofillProfileToProfile(controller->profile(), 913 test::GetVerifiedProfile()); 914 915 TestableAutofillDialogView* view = controller->GetTestableView(); 916 view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123")); 917 view->SubmitForTesting(); 918 ExpectDomMessage("error: invalid"); 919 } 920 921 // http://crbug.com/318526 922 #if defined(OS_MACOSX) 923 #define MAYBE_AutocompleteErrorEventReasonCancel \ 924 DISABLED_AutocompleteErrorEventReasonCancel 925 #else 926 #define MAYBE_AutocompleteErrorEventReasonCancel \ 927 AutocompleteErrorEventReasonCancel 928 #endif 929 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 930 MAYBE_AutocompleteErrorEventReasonCancel) { 931 AutofillDialogControllerImpl* controller = 932 SetUpHtmlAndInvoke("<input autocomplete='cc-name'>"); 933 ASSERT_TRUE(controller); 934 controller->GetTestableView()->CancelForTesting(); 935 ExpectDomMessage("error: cancel"); 936 } 937 938 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, NoCvcSegfault) { 939 controller()->set_use_validation(true); 940 941 CreditCard credit_card(test::GetVerifiedCreditCard()); 942 controller()->GetTestingManager()->AddTestingCreditCard(&credit_card); 943 EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC)); 944 945 ASSERT_NO_FATAL_FAILURE( 946 controller()->GetTestableView()->SubmitForTesting()); 947 } 948 949 // Flaky on Win7, WinXP, and Win Aura. http://crbug.com/270314. 950 #if defined(OS_WIN) 951 #define MAYBE_PreservedSections DISABLED_PreservedSections 952 #else 953 #define MAYBE_PreservedSections PreservedSections 954 #endif 955 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_PreservedSections) { 956 controller()->set_use_validation(true); 957 958 TestableAutofillDialogView* view = controller()->GetTestableView(); 959 960 { 961 // Create some valid inputted billing data. 962 const DetailInput& cc_number = 963 controller()->RequestedFieldsForSection(SECTION_CC)[0]; 964 EXPECT_EQ(cc_number.type, CREDIT_CARD_NUMBER); 965 view->SetTextContentsOfInput(cc_number, ASCIIToUTF16("4111111111111111")); 966 } 967 968 // Create some invalid, manually inputted shipping data. 969 const DetailInput& shipping_zip = 970 controller()->RequestedFieldsForSection(SECTION_SHIPPING)[5]; 971 ASSERT_EQ(ADDRESS_HOME_ZIP, shipping_zip.type); 972 view->SetTextContentsOfInput(shipping_zip, ASCIIToUTF16("shipping zip")); 973 974 // Switch to Wallet by simulating a successful server response. 975 controller()->OnDidFetchWalletCookieValue(std::string()); 976 controller()->OnDidGetWalletItems( 977 wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED)); 978 ASSERT_TRUE(controller()->IsPayingWithWallet()); 979 980 { 981 // The valid data should be preserved. 982 const DetailInput& cc_number = 983 controller()->RequestedFieldsForSection(SECTION_CC_BILLING)[0]; 984 EXPECT_EQ(cc_number.type, CREDIT_CARD_NUMBER); 985 EXPECT_EQ(ASCIIToUTF16("4111111111111111"), 986 view->GetTextContentsOfInput(cc_number)); 987 } 988 989 // The invalid data should be dropped. 990 EXPECT_TRUE(view->GetTextContentsOfInput(shipping_zip).empty()); 991 992 // Switch back to Autofill. 993 ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser(); 994 account_chooser->ActivatedAt(account_chooser->GetItemCount() - 1); 995 ASSERT_FALSE(controller()->IsPayingWithWallet()); 996 997 { 998 // The valid data should still be preserved when switched back. 999 const DetailInput& cc_number = 1000 controller()->RequestedFieldsForSection(SECTION_CC)[0]; 1001 EXPECT_EQ(cc_number.type, CREDIT_CARD_NUMBER); 1002 EXPECT_EQ(ASCIIToUTF16("4111111111111111"), 1003 view->GetTextContentsOfInput(cc_number)); 1004 } 1005 } 1006 #endif // defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) 1007 1008 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 1009 GeneratedCardLastFourAfterVerifyCvv) { 1010 controller()->OnDidFetchWalletCookieValue(std::string()); 1011 1012 scoped_ptr<wallet::WalletItems> wallet_items = 1013 wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED); 1014 wallet_items->AddInstrument(wallet::GetTestMaskedInstrument()); 1015 wallet_items->AddAddress(wallet::GetTestShippingAddress()); 1016 1017 base::string16 last_four = 1018 wallet_items->instruments()[0]->TypeAndLastFourDigits(); 1019 controller()->OnDidGetWalletItems(wallet_items.Pass()); 1020 1021 TestableAutofillDialogView* test_view = controller()->GetTestableView(); 1022 EXPECT_FALSE(test_view->IsShowingOverlay()); 1023 EXPECT_CALL(*controller(), LoadRiskFingerprintData()); 1024 controller()->OnAccept(); 1025 EXPECT_TRUE(test_view->IsShowingOverlay()); 1026 1027 EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_)); 1028 scoped_ptr<risk::Fingerprint> fingerprint(new risk::Fingerprint()); 1029 fingerprint->mutable_machine_characteristics()->mutable_screen_size()-> 1030 set_width(1024); 1031 controller()->OnDidLoadRiskFingerprintData(fingerprint.Pass()); 1032 1033 controller()->OnDidGetFullWallet( 1034 wallet::GetTestFullWalletWithRequiredActions( 1035 std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV))); 1036 1037 ASSERT_TRUE(controller()->IsSubmitPausedOn(wallet::VERIFY_CVV)); 1038 1039 std::string fake_cvc("123"); 1040 test_view->SetTextContentsOfSuggestionInput(SECTION_CC_BILLING, 1041 ASCIIToUTF16(fake_cvc)); 1042 1043 EXPECT_FALSE(test_view->IsShowingOverlay()); 1044 EXPECT_CALL(*controller()->GetTestingWalletClient(), 1045 AuthenticateInstrument(_, fake_cvc)); 1046 controller()->OnAccept(); 1047 EXPECT_TRUE(test_view->IsShowingOverlay()); 1048 1049 EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_)); 1050 controller()->OnDidAuthenticateInstrument(true); 1051 controller()->OnDidGetFullWallet(wallet::GetTestFullWallet()); 1052 controller()->ForceFinishSubmit(); 1053 1054 RunMessageLoop(); 1055 1056 EXPECT_EQ(1, test_generated_bubble_controller()->bubbles_shown()); 1057 EXPECT_EQ(last_four, test_generated_bubble_controller()->backing_card_name()); 1058 } 1059 1060 // Simulates the user signing in to the dialog from the inline web contents. 1061 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, SimulateSuccessfulSignIn) { 1062 browser()->profile()->GetPrefs()->SetBoolean( 1063 ::prefs::kAutofillDialogPayWithoutWallet, 1064 true); 1065 1066 InitializeController(); 1067 1068 controller()->OnDidFetchWalletCookieValue(std::string()); 1069 controller()->OnDidGetWalletItems( 1070 wallet::GetTestWalletItemsWithRequiredAction(wallet::GAIA_AUTH)); 1071 1072 NavEntryCommittedObserver sign_in_page_observer( 1073 controller()->SignInUrl(), 1074 content::NotificationService::AllSources()); 1075 1076 // Simulate a user clicking "Sign In" (which loads dialog's web contents). 1077 controller()->SignInLinkClicked(); 1078 EXPECT_TRUE(controller()->ShouldShowSignInWebView()); 1079 1080 TestableAutofillDialogView* view = controller()->GetTestableView(); 1081 content::WebContents* sign_in_contents = view->GetSignInWebContents(); 1082 ASSERT_TRUE(sign_in_contents); 1083 1084 sign_in_page_observer.Wait(); 1085 1086 NavEntryCommittedObserver continue_page_observer( 1087 controller()->SignInContinueUrl(), 1088 content::NotificationService::AllSources()); 1089 1090 EXPECT_EQ(sign_in_contents->GetURL(), controller()->SignInUrl()); 1091 1092 AccountChooserModel* account_chooser_model = 1093 controller()->AccountChooserModelForTesting(); 1094 EXPECT_FALSE(account_chooser_model->WalletIsSelected()); 1095 1096 sign_in_contents->GetController().LoadURL( 1097 controller()->SignInContinueUrl(), 1098 content::Referrer(), 1099 content::PAGE_TRANSITION_FORM_SUBMIT, 1100 std::string()); 1101 1102 EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems()); 1103 continue_page_observer.Wait(); 1104 content::RunAllPendingInMessageLoop(); 1105 1106 EXPECT_FALSE(controller()->ShouldShowSignInWebView()); 1107 1108 controller()->OnDidGetWalletItems( 1109 wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED)); 1110 1111 // Wallet should now be selected and Chrome shouldn't have crashed (which can 1112 // happen if the WebContents is deleted while proccessing a nav entry commit). 1113 EXPECT_TRUE(account_chooser_model->WalletIsSelected()); 1114 } 1115 1116 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AddAccount) { 1117 InitializeController(); 1118 1119 controller()->OnDidFetchWalletCookieValue(std::string()); 1120 std::vector<std::string> usernames; 1121 usernames.push_back("user_0 (at) example.com"); 1122 controller()->OnDidGetWalletItems( 1123 wallet::GetTestWalletItemsWithUsers(usernames, 0)); 1124 1125 // Switch to Autofill. 1126 AccountChooserModel* account_chooser_model = 1127 controller()->AccountChooserModelForTesting(); 1128 account_chooser_model->ActivatedAt( 1129 account_chooser_model->GetItemCount() - 1); 1130 1131 NavEntryCommittedObserver sign_in_page_observer( 1132 controller()->SignInUrl(), 1133 content::NotificationService::AllSources()); 1134 1135 // Simulate a user clicking "add account". 1136 account_chooser_model->ActivatedAt( 1137 account_chooser_model->GetItemCount() - 2); 1138 EXPECT_TRUE(controller()->ShouldShowSignInWebView()); 1139 1140 TestableAutofillDialogView* view = controller()->GetTestableView(); 1141 content::WebContents* sign_in_contents = view->GetSignInWebContents(); 1142 ASSERT_TRUE(sign_in_contents); 1143 1144 sign_in_page_observer.Wait(); 1145 1146 NavEntryCommittedObserver continue_page_observer( 1147 controller()->SignInContinueUrl(), 1148 content::NotificationService::AllSources()); 1149 1150 EXPECT_EQ(sign_in_contents->GetURL(), controller()->SignInUrl()); 1151 1152 EXPECT_FALSE(account_chooser_model->WalletIsSelected()); 1153 1154 // User signs into new account, account 3. 1155 controller()->set_sign_in_user_index(3U); 1156 sign_in_contents->GetController().LoadURL( 1157 controller()->SignInContinueUrl(), 1158 content::Referrer(), 1159 content::PAGE_TRANSITION_FORM_SUBMIT, 1160 std::string()); 1161 1162 EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems()); 1163 continue_page_observer.Wait(); 1164 content::RunAllPendingInMessageLoop(); 1165 1166 EXPECT_FALSE(controller()->ShouldShowSignInWebView()); 1167 EXPECT_EQ(3U, controller()->GetTestingWalletClient()->user_index()); 1168 1169 usernames.push_back("user_1 (at) example.com"); 1170 usernames.push_back("user_2 (at) example.com"); 1171 usernames.push_back("user_3 (at) example.com"); 1172 usernames.push_back("user_4 (at) example.com"); 1173 // Curveball: wallet items comes back with user 4 selected. 1174 controller()->OnDidGetWalletItems( 1175 wallet::GetTestWalletItemsWithUsers(usernames, 4U)); 1176 1177 EXPECT_TRUE(account_chooser_model->WalletIsSelected()); 1178 EXPECT_EQ(4U, account_chooser_model->GetActiveWalletAccountIndex()); 1179 EXPECT_EQ(4U, controller()->GetTestingWalletClient()->user_index()); 1180 } 1181 1182 // http://crbug.com/318526 1183 #if defined(OS_MACOSX) 1184 #define MAYBE_FillFormIncludesCVC DISABLED_FillFormIncludesCVC 1185 #else 1186 #define MAYBE_FillFormIncludesCVC FillFormIncludesCVC 1187 #endif 1188 // Verify that filling a form works correctly, including filling the CVC when 1189 // that is requested separately. 1190 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 1191 MAYBE_FillFormIncludesCVC) { 1192 AutofillDialogControllerImpl* controller = 1193 SetUpHtmlAndInvoke("<input autocomplete='cc-csc'>"); 1194 ASSERT_TRUE(controller); 1195 1196 AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard()); 1197 AddAutofillProfileToProfile(controller->profile(), 1198 test::GetVerifiedProfile()); 1199 1200 TestableAutofillDialogView* view = controller->GetTestableView(); 1201 view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123")); 1202 view->SubmitForTesting(); 1203 ExpectDomMessage("success"); 1204 EXPECT_EQ("123", GetValueForHTMLFieldOfType("cc-csc")); 1205 } 1206 1207 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AddNewClearsComboboxes) { 1208 // Ensure the input under test is a combobox. 1209 ASSERT_TRUE( 1210 controller()->ComboboxModelForAutofillType(CREDIT_CARD_EXP_MONTH)); 1211 1212 // Set up an expired card. 1213 CreditCard card; 1214 test::SetCreditCardInfo(&card, "Roy Demeo", "4111111111111111", "8", "2013"); 1215 card.set_origin("Chrome settings"); 1216 ASSERT_TRUE(card.IsVerified()); 1217 1218 // Add the card and check that there's a menu for that section. 1219 controller()->GetTestingManager()->AddTestingCreditCard(&card); 1220 ASSERT_TRUE(controller()->MenuModelForSection(SECTION_CC)); 1221 1222 // Select the invalid, suggested card from the menu. 1223 controller()->MenuModelForSection(SECTION_CC)->ActivatedAt(0); 1224 EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC)); 1225 1226 const DetailInputs& inputs = 1227 controller()->RequestedFieldsForSection(SECTION_CC); 1228 const DetailInput& cc_exp_month = inputs[1]; 1229 ASSERT_EQ(CREDIT_CARD_EXP_MONTH, cc_exp_month.type); 1230 1231 // Get the contents of the combobox of the credit card's expiration month. 1232 TestableAutofillDialogView* view = controller()->GetTestableView(); 1233 base::string16 cc_exp_month_text = view->GetTextContentsOfInput(cc_exp_month); 1234 1235 // Select "New X..." from the suggestion menu to clear the section's inputs. 1236 controller()->MenuModelForSection(SECTION_CC)->ActivatedAt(1); 1237 EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC)); 1238 1239 // Ensure that the credit card expiration month has changed. 1240 EXPECT_NE(cc_exp_month_text, view->GetTextContentsOfInput(cc_exp_month)); 1241 } 1242 1243 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, TabOpensToJustRight) { 1244 ASSERT_TRUE(browser()->is_type_tabbed()); 1245 1246 // Tabs should currently be: / rAc() \. 1247 content::WebContents* dialog_invoker = controller()->GetWebContents(); 1248 EXPECT_EQ(dialog_invoker, GetActiveWebContents()); 1249 1250 TabStripModel* tab_strip = browser()->tab_strip_model(); 1251 ASSERT_EQ(1, tab_strip->count()); 1252 EXPECT_EQ(0, tab_strip->GetIndexOfWebContents(dialog_invoker)); 1253 1254 // Open a tab to about:blank in the background at the end of the tab strip. 1255 chrome::AddTabAt(browser(), GURL(), -1, false); 1256 // Tabs should now be: / rAc() \/ blank \. 1257 EXPECT_EQ(2, tab_strip->count()); 1258 EXPECT_EQ(0, tab_strip->active_index()); 1259 EXPECT_EQ(dialog_invoker, GetActiveWebContents()); 1260 1261 content::WebContents* blank_tab = tab_strip->GetWebContentsAt(1); 1262 1263 // Simulate clicking "Manage X...". 1264 controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2); 1265 // Tab should now be: / rAc() \/ manage 1 \/ blank \. 1266 EXPECT_EQ(3, tab_strip->count()); 1267 int dialog_index = tab_strip->GetIndexOfWebContents(dialog_invoker); 1268 EXPECT_EQ(0, dialog_index); 1269 EXPECT_EQ(1, tab_strip->active_index()); 1270 EXPECT_EQ(2, tab_strip->GetIndexOfWebContents(blank_tab)); 1271 1272 content::WebContents* first_manage_tab = tab_strip->GetWebContentsAt(1); 1273 1274 // Re-activate the dialog's tab (like a user would have to). 1275 tab_strip->ActivateTabAt(dialog_index, true); 1276 EXPECT_EQ(dialog_invoker, GetActiveWebContents()); 1277 1278 // Simulate clicking "Manage X...". 1279 controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2); 1280 // Tabs should now be: / rAc() \/ manage 2 \/ manage 1 \/ blank \. 1281 EXPECT_EQ(4, tab_strip->count()); 1282 EXPECT_EQ(0, tab_strip->GetIndexOfWebContents(dialog_invoker)); 1283 EXPECT_EQ(1, tab_strip->active_index()); 1284 EXPECT_EQ(2, tab_strip->GetIndexOfWebContents(first_manage_tab)); 1285 EXPECT_EQ(3, tab_strip->GetIndexOfWebContents(blank_tab)); 1286 } 1287 1288 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 1289 SignInWebViewOpensLinksInNewTab) { 1290 controller()->OnDidFetchWalletCookieValue(std::string()); 1291 controller()->OnDidGetWalletItems( 1292 wallet::GetTestWalletItemsWithRequiredAction(wallet::GAIA_AUTH)); 1293 1294 NavEntryCommittedObserver sign_in_page_observer( 1295 controller()->SignInUrl(), 1296 content::NotificationService::AllSources()); 1297 1298 controller()->SignInLinkClicked(); 1299 1300 TestableAutofillDialogView* view = controller()->GetTestableView(); 1301 content::WebContents* sign_in_contents = view->GetSignInWebContents(); 1302 ASSERT_TRUE(sign_in_contents); 1303 1304 sign_in_page_observer.Wait(); 1305 1306 content::OpenURLParams params(GURL("http://google.com"), 1307 content::Referrer(), 1308 CURRENT_TAB, 1309 content::PAGE_TRANSITION_LINK, 1310 true); 1311 int num_tabs = browser()->tab_strip_model()->count(); 1312 sign_in_contents->GetDelegate()->OpenURLFromTab(sign_in_contents, params); 1313 EXPECT_EQ(num_tabs + 1, browser()->tab_strip_model()->count()); 1314 } 1315 1316 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, RefreshOnManageTabClose) { 1317 ASSERT_TRUE(browser()->is_type_tabbed()); 1318 1319 // GetWalletItems() is called when controller() is created in SetUp(). 1320 EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems()); 1321 controller()->OnDidFetchWalletCookieValue(std::string()); 1322 controller()->OnDidGetWalletItems( 1323 wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED)); 1324 1325 content::WebContents* dialog_invoker = controller()->GetWebContents(); 1326 TabAutofillManagerDelegate::FromWebContents(dialog_invoker)-> 1327 SetDialogControllerForTesting(controller()->AsWeakPtr()); 1328 1329 // Open a new tab by selecting "Manage my shipping details..." in Wallet mode. 1330 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 1331 controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2); 1332 EXPECT_EQ(2, browser()->tab_strip_model()->count()); 1333 ASSERT_NE(dialog_invoker, GetActiveWebContents()); 1334 1335 // Closing the tab opened by "Manage my shipping details..." should refresh 1336 // the dialog. 1337 controller()->ClearLastWalletItemsFetchTimestampForTesting(); 1338 EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems()); 1339 GetActiveWebContents()->Close(); 1340 } 1341 1342 // http://crbug.com/318526 1343 #if defined(OS_MACOSX) 1344 #define MAYBE_DoesWorkOnHttpWithFlag DISABLED_DoesWorkOnHttpWithFlag 1345 #else 1346 #define MAYBE_DoesWorkOnHttpWithFlag DoesWorkOnHttpWithFlag 1347 #endif 1348 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, 1349 MAYBE_DoesWorkOnHttpWithFlag) { 1350 net::SpawnedTestServer http_server( 1351 net::SpawnedTestServer::TYPE_HTTP, 1352 net::SpawnedTestServer::kLocalhost, 1353 base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); 1354 ASSERT_TRUE(http_server.Start()); 1355 EXPECT_TRUE(RunTestPage(http_server)); 1356 } 1357 1358 // Like the parent test, but doesn't add the --reduce-security-for-testing flag. 1359 class AutofillDialogControllerSecurityTest : 1360 public AutofillDialogControllerTest { 1361 public: 1362 AutofillDialogControllerSecurityTest() {} 1363 virtual ~AutofillDialogControllerSecurityTest() {} 1364 1365 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1366 CHECK(!command_line->HasSwitch(::switches::kReduceSecurityForTesting)); 1367 } 1368 1369 typedef net::BaseTestServer::SSLOptions SSLOptions; 1370 1371 private: 1372 DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerSecurityTest); 1373 }; 1374 1375 // http://crbug.com/318526 1376 #if defined(OS_MACOSX) 1377 #define MAYBE_DoesntWorkOnHttp DISABLED_DoesntWorkOnHttp 1378 #else 1379 #define MAYBE_DoesntWorkOnHttp DoesntWorkOnHttp 1380 #endif 1381 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerSecurityTest, 1382 MAYBE_DoesntWorkOnHttp) { 1383 net::SpawnedTestServer http_server( 1384 net::SpawnedTestServer::TYPE_HTTP, 1385 net::SpawnedTestServer::kLocalhost, 1386 base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); 1387 ASSERT_TRUE(http_server.Start()); 1388 EXPECT_FALSE(RunTestPage(http_server)); 1389 } 1390 1391 // http://crbug.com/318526 1392 #if defined(OS_MACOSX) 1393 #define MAYBE_DoesWorkOnHttpWithFlags DISABLED_DoesWorkOnHttpWithFlags 1394 #else 1395 #define MAYBE_DoesWorkOnHttpWithFlags DoesWorkOnHttpWithFlags 1396 #endif 1397 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerSecurityTest, 1398 MAYBE_DoesWorkOnHttpWithFlags) { 1399 net::SpawnedTestServer https_server( 1400 net::SpawnedTestServer::TYPE_HTTPS, 1401 SSLOptions(SSLOptions::CERT_OK), 1402 base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); 1403 ASSERT_TRUE(https_server.Start()); 1404 EXPECT_TRUE(RunTestPage(https_server)); 1405 } 1406 1407 // http://crbug.com/318526 1408 #if defined(OS_MACOSX) 1409 #define MAYBE_DoesntWorkOnBrokenHttps DISABLED_DoesntWorkOnBrokenHttps 1410 #else 1411 #define MAYBE_DoesntWorkOnBrokenHttps DoesntWorkOnBrokenHttps 1412 #endif 1413 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerSecurityTest, 1414 MAYBE_DoesntWorkOnBrokenHttps) { 1415 net::SpawnedTestServer https_server( 1416 net::SpawnedTestServer::TYPE_HTTPS, 1417 SSLOptions(SSLOptions::CERT_EXPIRED), 1418 base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); 1419 ASSERT_TRUE(https_server.Start()); 1420 EXPECT_FALSE(RunTestPage(https_server)); 1421 } 1422 1423 } // namespace autofill 1424