| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| #include <tuple> |
| #include <utility> |
| |
| #include "base/base_switches.h" |
| #include "base/command_line.h" |
| #include "base/files/file_util.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/rand_util.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/mock_entropy_provider.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/autofill/autofill_uitest_util.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/metrics/subprocess_metrics_provider.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/translate/chrome_translate_client.h" |
| #include "chrome/browser/translate/translate_service.h" |
| #include "chrome/browser/ui/autofill/chrome_autofill_client.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/translate/translate_bubble_test_utils.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/interactive_test_utils.h" |
| #include "chrome/test/base/test_switches.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/autofill/content/browser/content_autofill_driver.h" |
| #include "components/autofill/content/browser/content_autofill_driver_factory.h" |
| #include "components/autofill/core/browser/autofill_experiments.h" |
| #include "components/autofill/core/browser/autofill_manager.h" |
| #include "components/autofill/core/browser/autofill_manager_test_delegate.h" |
| #include "components/autofill/core/browser/autofill_profile.h" |
| #include "components/autofill/core/browser/autofill_test_utils.h" |
| #include "components/autofill/core/browser/validation.h" |
| #include "components/autofill/core/common/autofill_features.h" |
| #include "components/network_session_configurator/common/network_switches.h" |
| #include "components/translate/core/browser/translate_manager.h" |
| #include "components/translate/core/common/translate_switches.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_registrar.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/render_widget_host.h" |
| #include "content/public/browser/render_widget_host_view.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_renderer_host.h" |
| #include "content/public/test/test_utils.h" |
| #include "net/base/net_errors.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/controllable_http_response.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/url_request/test_url_fetcher_factory.h" |
| #include "net/url_request/url_request_status.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/events/base_event_utils.h" |
| #include "ui/events/keycodes/dom_us_layout_data.h" |
| #include "ui/events/keycodes/keyboard_code_conversion.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| |
| using base::ASCIIToUTF16; |
| |
| namespace autofill { |
| |
| namespace { |
| |
| static const char kDataURIPrefix[] = "data:text/html;charset=utf-8,"; |
| static const char kTestShippingFormString[] = |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"firstname\">First name:</label>" |
| " <input type=\"text\" id=\"firstname\"><br>" |
| "<label for=\"lastname\">Last name:</label>" |
| " <input type=\"text\" id=\"lastname\"><br>" |
| "<label for=\"address1\">Address line 1:</label>" |
| " <input type=\"text\" id=\"address1\"><br>" |
| "<label for=\"address2\">Address line 2:</label>" |
| " <input type=\"text\" id=\"address2\"><br>" |
| "<label for=\"city\">City:</label>" |
| " <input type=\"text\" id=\"city\"><br>" |
| "<label for=\"state\">State:</label>" |
| " <select id=\"state\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br>" |
| "<label for=\"zip\">ZIP code:</label>" |
| " <input type=\"text\" id=\"zip\"><br>" |
| "<label for=\"country\">Country:</label>" |
| " <select id=\"country\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br>" |
| "<label for=\"phone\">Phone number:</label>" |
| " <input type=\"text\" id=\"phone\"><br>" |
| "</form>"; |
| |
| static const char kTestBillingFormString[] = |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"firstname_billing\">First name:</label>" |
| " <input type=\"text\" id=\"firstname_billing\"><br>" |
| "<label for=\"lastname_billing\">Last name:</label>" |
| " <input type=\"text\" id=\"lastname_billing\"><br>" |
| "<label for=\"address1_billing\">Address line 1:</label>" |
| " <input type=\"text\" id=\"address1_billing\"><br>" |
| "<label for=\"address2_billing\">Address line 2:</label>" |
| " <input type=\"text\" id=\"address2_billing\"><br>" |
| "<label for=\"city_billing\">City:</label>" |
| " <input type=\"text\" id=\"city_billing\"><br>" |
| "<label for=\"state_billing\">State:</label>" |
| " <select id=\"state_billing\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br>" |
| "<label for=\"zip_billing\">ZIP code:</label>" |
| " <input type=\"text\" id=\"zip_billing\"><br>" |
| "<label for=\"country_billing\">Country:</label>" |
| " <select id=\"country_billing\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br>" |
| "<label for=\"phone_billing\">Phone number:</label>" |
| " <input type=\"text\" id=\"phone_billing\"><br>" |
| "</form>"; |
| |
| // TODO(crbug.com/609861): Remove the autocomplete attribute from the textarea |
| // field when the bug is fixed. |
| static const char kTestEventFormString[] = |
| "<script type=\"text/javascript\">" |
| "var inputfocus = false;" |
| "var inputkeydown = false;" |
| "var inputinput = false;" |
| "var inputchange = false;" |
| "var inputkeyup = false;" |
| "var inputblur = false;" |
| "var textfocus = false;" |
| "var textkeydown = false;" |
| "var textinput= false;" |
| "var textchange = false;" |
| "var textkeyup = false;" |
| "var textblur = false;" |
| "var selectfocus = false;" |
| "var selectinput = false;" |
| "var selectchange = false;" |
| "var selectblur = false;" |
| "</script>" |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"firstname\">First name:</label>" |
| " <input type=\"text\" id=\"firstname\"><br>" |
| "<label for=\"lastname\">Last name:</label>" |
| " <input type=\"text\" id=\"lastname\"" |
| " onfocus=\"inputfocus = true\" onkeydown=\"inputkeydown = true\"" |
| " oninput=\"inputinput = true\" onchange=\"inputchange = true\"" |
| " onkeyup=\"inputkeyup = true\" onblur=\"inputblur = true\" ><br>" |
| "<label for=\"address1\">Address line 1:</label>" |
| " <input type=\"text\" id=\"address1\"><br>" |
| "<label for=\"address2\">Address line 2:</label>" |
| " <input type=\"text\" id=\"address2\"><br>" |
| "<label for=\"city\">City:</label>" |
| " <textarea rows=\"4\" cols=\"50\" id=\"city\" name=\"city\"" |
| " autocomplete=\"address-level2\" onfocus=\"textfocus = true\"" |
| " onkeydown=\"textkeydown = true\" oninput=\"textinput = true\"" |
| " onchange=\"textchange = true\" onkeyup=\"textkeyup = true\"" |
| " onblur=\"textblur = true\"></textarea><br>" |
| "<label for=\"state\">State:</label>" |
| " <select id=\"state\"" |
| " onfocus=\"selectfocus = true\" oninput=\"selectinput = true\"" |
| " onchange=\"selectchange = true\" onblur=\"selectblur = true\" >" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br>" |
| "<label for=\"zip\">ZIP code:</label>" |
| " <input type=\"text\" id=\"zip\"><br>" |
| "<label for=\"country\">Country:</label>" |
| " <select id=\"country\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br>" |
| "<label for=\"phone\">Phone number:</label>" |
| " <input type=\"text\" id=\"phone\"><br>" |
| "</form>"; |
| |
| // AutofillManagerTestDelegateImpl -------------------------------------------- |
| |
| class AutofillManagerTestDelegateImpl |
| : public autofill::AutofillManagerTestDelegate { |
| public: |
| AutofillManagerTestDelegateImpl() {} |
| ~AutofillManagerTestDelegateImpl() override {} |
| |
| // autofill::AutofillManagerTestDelegate: |
| void DidPreviewFormData() override { |
| ASSERT_TRUE(loop_runner_); |
| loop_runner_->Quit(); |
| } |
| |
| void DidFillFormData() override { |
| ASSERT_TRUE(loop_runner_); |
| if (!is_expecting_dynamic_refill_) |
| ASSERT_TRUE(loop_runner_->running()); |
| loop_runner_->Quit(); |
| } |
| |
| void DidShowSuggestions() override { |
| ASSERT_TRUE(loop_runner_); |
| loop_runner_->Quit(); |
| } |
| |
| void OnTextFieldChanged() override { |
| if (!waiting_for_text_change_) |
| return; |
| waiting_for_text_change_ = false; |
| ASSERT_TRUE(loop_runner_); |
| loop_runner_->Quit(); |
| } |
| |
| void Reset() { loop_runner_ = std::make_unique<base::RunLoop>(); } |
| |
| void Wait() { |
| loop_runner_->Run(); |
| } |
| |
| void WaitForTextChange() { |
| waiting_for_text_change_ = true; |
| loop_runner_->Run(); |
| } |
| |
| void SetIsExpectingDynamicRefill(bool expect_refill) { |
| is_expecting_dynamic_refill_ = expect_refill; |
| } |
| |
| private: |
| std::unique_ptr<base::RunLoop> loop_runner_; |
| bool waiting_for_text_change_ = false; |
| bool is_expecting_dynamic_refill_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutofillManagerTestDelegateImpl); |
| }; |
| |
| // Searches all frames of |web_contents| and returns one called |name|. If |
| // there are none, returns null, if there are more, returns an arbitrary one. |
| content::RenderFrameHost* RenderFrameHostForName( |
| content::WebContents* web_contents, |
| const std::string& name) { |
| return content::FrameMatchingPredicate( |
| web_contents, base::BindRepeating(&content::FrameMatchesName, name)); |
| } |
| |
| } // namespace |
| |
| // AutofillInteractiveTestBase ------------------------------------------------ |
| |
| // Test fixtures derive from this class and indicate via constructor parameter |
| // if feature kAutofillExpandedPopupViews is enabled. This class hierarchy |
| // allows test fixtures to have distinct list of test parameters. |
| // |
| // TODO(crbug.com/832707): Parametrize this class to ensure that all tests in |
| // this run with all possible valid combinations of |
| // features and field trials. |
| class AutofillInteractiveTestBase : public InProcessBrowserTest { |
| protected: |
| explicit AutofillInteractiveTestBase(bool popup_views_enabled) |
| : https_server_(net::EmbeddedTestServer::TYPE_HTTPS), |
| key_press_event_sink_(base::BindRepeating( |
| &AutofillInteractiveTestBase::HandleKeyPressEvent, |
| base::Unretained(this))), |
| popup_views_enabled_(popup_views_enabled) { |
| scoped_feature_list_.InitWithFeatureState(kAutofillExpandedPopupViews, |
| popup_views_enabled_); |
| } |
| |
| ~AutofillInteractiveTestBase() override {} |
| |
| // InProcessBrowserTest: |
| void SetUp() override { |
| ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| InProcessBrowserTest::SetUp(); |
| } |
| |
| void SetUpOnMainThread() override { |
| https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK); |
| https_server_.ServeFilesFromSourceDirectory("chrome/test/data"); |
| ASSERT_TRUE(https_server_.InitializeAndListen()); |
| https_server_.StartAcceptingConnections(); |
| |
| InProcessBrowserTest::SetUpOnMainThread(); |
| // Don't want Keychain coming up on Mac. |
| test::DisableSystemServices(browser()->profile()->GetPrefs()); |
| |
| // Inject the test delegate into the AutofillManager. |
| GetAutofillManager()->SetTestDelegate(&test_delegate_); |
| |
| // If the mouse happened to be over where the suggestions are shown, then |
| // the preview will show up and will fail the tests. We need to give it a |
| // point that's within the browser frame, or else the method hangs. |
| gfx::Point reset_mouse(GetWebContents()->GetContainerBounds().origin()); |
| reset_mouse = gfx::Point(reset_mouse.x() + 5, reset_mouse.y() + 5); |
| ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(reset_mouse)); |
| |
| controllable_http_response_ = |
| std::make_unique<net::test_server::ControllableHttpResponse>( |
| embedded_test_server(), "/mock_translate_script.js", |
| true /*relative_url_is_prefix*/); |
| |
| // Ensure that |embedded_test_server()| serves both domains used below. |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| embedded_test_server()->StartAcceptingConnections(); |
| } |
| |
| void TearDownOnMainThread() override { |
| // Make sure to close any showing popups prior to tearing down the UI. |
| GetAutofillManager()->client()->HideAutofillPopup(); |
| test::ReenableSystemServices(); |
| } |
| |
| content::WebContents* GetWebContents() { |
| return browser()->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| content::RenderViewHost* GetRenderViewHost() { |
| return GetWebContents()->GetRenderViewHost(); |
| } |
| |
| AutofillManager* GetAutofillManager() { |
| content::WebContents* web_contents = GetWebContents(); |
| return ContentAutofillDriverFactory::FromWebContents(web_contents) |
| ->DriverForFrame(web_contents->GetMainFrame()) |
| ->autofill_manager(); |
| } |
| |
| void CreateTestProfile() { |
| AutofillProfile profile; |
| test::SetProfileInfo(&profile, "Milton", "C.", "Waddams", |
| "red.swingline@initech.com", "Initech", |
| "4120 Freidrich Lane", "Basement", "Austin", "Texas", |
| "78744", "US", "15125551234"); |
| profile.set_use_count(9999999); // We want this to be the first profile. |
| AddTestProfile(browser(), profile); |
| } |
| |
| void CreateSecondTestProfile() { |
| AutofillProfile profile; |
| test::SetProfileInfo(&profile, "Alice", "M.", "Wonderland", |
| "alice@wonderland.com", "Magic", "333 Cat Queen St.", |
| "Rooftop", "Liliput", "CA", "10003", "US", |
| "15166900292"); |
| AddTestProfile(browser(), profile); |
| } |
| |
| void CreateTestCreditCart() { |
| CreditCard card; |
| test::SetCreditCardInfo(&card, "Milton Waddams", "4111111111111111", "09", |
| "2999", ""); |
| AddTestCreditCard(browser(), card); |
| } |
| |
| // Populates a webpage form using autofill data and keypress events. |
| // This function focuses the specified input field in the form, and then |
| // sends keypress events to the tab to cause the form to be populated. |
| void PopulateForm(const std::string& field_id) { |
| std::string js("document.getElementById('" + field_id + "').focus();"); |
| ASSERT_TRUE(content::ExecuteScript(GetWebContents(), js)); |
| |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| } |
| |
| void ExpectFieldValue(const std::string& field_name, |
| const std::string& expected_value) { |
| std::string value; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| GetWebContents(), |
| "window.domAutomationController.send(" |
| " document.getElementById('" + field_name + "').value);", |
| &value)); |
| EXPECT_EQ(expected_value, value) << "for field " << field_name; |
| } |
| |
| void AssertFieldValue(const std::string& field_name, |
| const std::string& expected_value) { |
| std::string value; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| GetWebContents(), |
| "window.domAutomationController.send(" |
| " document.getElementById('" + |
| field_name + "').value);", |
| &value)); |
| ASSERT_EQ(expected_value, value) << "for field " << field_name; |
| } |
| |
| void GetFieldBackgroundColor(const std::string& field_name, |
| std::string* color) { |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| GetWebContents(), |
| "window.domAutomationController.send(" |
| " document.defaultView.getComputedStyle(document.getElementById('" + |
| field_name + "')).backgroundColor);", |
| color)); |
| } |
| |
| void SimulateURLFetch() { |
| std::string script = |
| " var google = {};" |
| "google.translate = (function() {" |
| " return {" |
| " TranslateService: function() {" |
| " return {" |
| " isAvailable : function() {" |
| " return true;" |
| " }," |
| " restore : function() {" |
| " return;" |
| " }," |
| " getDetectedLanguage : function() {" |
| " return \"ja\";" |
| " }," |
| " translatePage : function(originalLang, targetLang," |
| " onTranslateProgress) {" |
| " document.getElementsByTagName(\"body\")[0].innerHTML = '" + |
| std::string(kTestShippingFormString) + |
| " ';" |
| " onTranslateProgress(100, true, false);" |
| " }" |
| " };" |
| " }" |
| " };" |
| "})();" |
| "cr.googleTranslate.onTranslateElementLoad();"; |
| |
| controllable_http_response_->WaitForRequest(); |
| controllable_http_response_->Send( |
| "HTTP/1.1 200 OK\r\n" |
| "Content-Type: text/javascript\r\n" |
| "\r\n"); |
| controllable_http_response_->Send(script); |
| controllable_http_response_->Done(); |
| } |
| |
| void FocusFieldByName(const std::string& name) { |
| bool result = false; |
| std::string script = base::StringPrintf( |
| R"( function onFocusHandler(e) { |
| e.target.removeEventListener(e.type, arguments.callee); |
| domAutomationController.send(true); |
| } |
| if (document.readyState === 'complete') { |
| var target = document.getElementById('%s'); |
| target.addEventListener('focus', onFocusHandler); |
| target.focus(); |
| } else { |
| domAutomationController.send(false); |
| })", |
| name.c_str()); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetWebContents(), script, |
| &result)); |
| ASSERT_TRUE(result); |
| } |
| |
| void FocusFirstNameField() { FocusFieldByName("firstname"); } |
| |
| // Simulates a click on the middle of the DOM element with the given |id|. |
| void ClickElementWithId(const std::string& id) { |
| int x; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
| GetWebContents(), |
| "var bounds = document.getElementById('" + id + |
| "').getBoundingClientRect();" |
| "domAutomationController.send(" |
| " Math.floor(bounds.left + bounds.width / 2));", |
| &x)); |
| int y; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
| GetWebContents(), |
| "var bounds = document.getElementById('" + id + |
| "').getBoundingClientRect();" |
| "domAutomationController.send(" |
| " Math.floor(bounds.top + bounds.height / 2));", |
| &y)); |
| content::SimulateMouseClickAt(GetWebContents(), 0, |
| blink::WebMouseEvent::Button::kLeft, |
| gfx::Point(x, y)); |
| } |
| |
| void ClickFirstNameField() { |
| ASSERT_NO_FATAL_FAILURE(ClickElementWithId("firstname")); |
| } |
| |
| // Make a pointless round trip to the renderer, giving the popup a chance to |
| // show if it's going to. If it does show, an assert in |
| // AutofillManagerTestDelegateImpl will trigger. |
| void MakeSurePopupDoesntAppear() { |
| int unused; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
| GetWebContents(), "domAutomationController.send(42)", &unused)); |
| } |
| |
| void ExpectFilledTestForm() { |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("lastname", "Waddams"); |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("address2", "Basement"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("zip", "78744"); |
| ExpectFieldValue("country", "US"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| void ExpectClearedForm() { |
| ExpectFieldValue("firstname", ""); |
| ExpectFieldValue("lastname", ""); |
| ExpectFieldValue("address1", ""); |
| ExpectFieldValue("address2", ""); |
| ExpectFieldValue("city", ""); |
| ExpectFieldValue("state", ""); |
| ExpectFieldValue("zip", ""); |
| ExpectFieldValue("country", ""); |
| ExpectFieldValue("phone", ""); |
| } |
| |
| void FillElementWithValue(const std::string& element_name, |
| const std::string& value) { |
| for (base::char16 character : value) { |
| ui::DomKey dom_key = ui::DomKey::FromCharacter(character); |
| const ui::PrintableCodeEntry* code_entry = std::find_if( |
| std::begin(ui::kPrintableCodeMap), std::end(ui::kPrintableCodeMap), |
| [character](const ui::PrintableCodeEntry& entry) { |
| return entry.character[0] == character || |
| entry.character[1] == character; |
| }); |
| ASSERT_TRUE(code_entry != std::end(ui::kPrintableCodeMap)); |
| bool shift = code_entry->character[1] == character; |
| ui::DomCode dom_code = code_entry->dom_code; |
| content::SimulateKeyPress(GetWebContents(), dom_key, dom_code, |
| ui::DomCodeToUsLayoutKeyboardCode(dom_code), |
| false, shift, false, false); |
| } |
| AssertFieldValue(element_name, value); |
| } |
| |
| void DeleteElementValue(const std::string& element_name) { |
| ASSERT_TRUE(content::ExecuteScript( |
| GetWebContents(), |
| "document.getElementById('" + element_name + "').value = '';")); |
| AssertFieldValue(element_name, ""); |
| } |
| |
| void SendKeyToPageAndWait(ui::DomKey key) { |
| ui::KeyboardCode key_code = ui::NonPrintableDomKeyToKeyboardCode(key); |
| ui::DomCode code = ui::UsLayoutKeyboardCodeToDomCode(key_code); |
| SendKeyToPageAndWait(key, code, key_code); |
| } |
| |
| void SendKeyToPageAndWait(ui::DomKey key, |
| ui::DomCode code, |
| ui::KeyboardCode key_code) { |
| test_delegate_.Reset(); |
| content::SimulateKeyPress(GetWebContents(), key, code, key_code, false, |
| false, false, false); |
| test_delegate_.Wait(); |
| } |
| |
| bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event) { |
| return true; |
| } |
| |
| void SendKeyToPopupAndWait(ui::DomKey key) { |
| ui::KeyboardCode key_code = ui::NonPrintableDomKeyToKeyboardCode(key); |
| ui::DomCode code = ui::UsLayoutKeyboardCodeToDomCode(key_code); |
| SendKeyToPopupAndWait(key, code, key_code, |
| GetRenderViewHost()->GetWidget()); |
| } |
| |
| void SendKeyToPopupAndWait(ui::DomKey key, |
| ui::DomCode code, |
| ui::KeyboardCode key_code, |
| content::RenderWidgetHost* widget) { |
| // Route popup-targeted key presses via the render view host. |
| content::NativeWebKeyboardEvent event(blink::WebKeyboardEvent::kRawKeyDown, |
| blink::WebInputEvent::kNoModifiers, |
| ui::EventTimeForNow()); |
| event.windows_key_code = key_code; |
| event.dom_code = static_cast<int>(code); |
| event.dom_key = key; |
| test_delegate_.Reset(); |
| // Install the key press event sink to ensure that any events that are not |
| // handled by the installed callbacks do not end up crashing the test. |
| widget->AddKeyPressEventCallback(key_press_event_sink_); |
| widget->ForwardKeyboardEvent(event); |
| test_delegate_.Wait(); |
| widget->RemoveKeyPressEventCallback(key_press_event_sink_); |
| } |
| |
| void SendKeyToDataListPopup(ui::DomKey key) { |
| ui::KeyboardCode key_code = ui::NonPrintableDomKeyToKeyboardCode(key); |
| ui::DomCode code = ui::UsLayoutKeyboardCodeToDomCode(key_code); |
| SendKeyToDataListPopup(key, code, key_code); |
| } |
| |
| // Datalist does not support autofill preview. There is no need to start |
| // message loop for Datalist. |
| void SendKeyToDataListPopup(ui::DomKey key, |
| ui::DomCode code, |
| ui::KeyboardCode key_code) { |
| // Route popup-targeted key presses via the render view host. |
| content::NativeWebKeyboardEvent event(blink::WebKeyboardEvent::kRawKeyDown, |
| blink::WebInputEvent::kNoModifiers, |
| ui::EventTimeForNow()); |
| event.windows_key_code = key_code; |
| event.dom_code = static_cast<int>(code); |
| event.dom_key = key; |
| // Install the key press event sink to ensure that any events that are not |
| // handled by the installed callbacks do not end up crashing the test. |
| GetRenderViewHost()->GetWidget()->AddKeyPressEventCallback( |
| key_press_event_sink_); |
| GetRenderViewHost()->GetWidget()->ForwardKeyboardEvent(event); |
| GetRenderViewHost()->GetWidget()->RemoveKeyPressEventCallback( |
| key_press_event_sink_); |
| } |
| |
| void TryBasicFormFill() { |
| FocusFirstNameField(); |
| |
| // Start filling the first name field with "M" and wait for the popup to be |
| // shown. |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // The previewed values should not be accessible to JavaScript. |
| ExpectFieldValue("firstname", "M"); |
| ExpectFieldValue("lastname", std::string()); |
| ExpectFieldValue("address1", std::string()); |
| ExpectFieldValue("address2", std::string()); |
| ExpectFieldValue("city", std::string()); |
| ExpectFieldValue("state", std::string()); |
| ExpectFieldValue("zip", std::string()); |
| ExpectFieldValue("country", std::string()); |
| ExpectFieldValue("phone", std::string()); |
| // TODO(isherman): It would be nice to test that the previewed values are |
| // displayed: http://crbug.com/57220 |
| |
| // Press Enter to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| void TryClearForm() { |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToDataListPopup(ui::DomKey::ARROW_DOWN); // clear |
| SendKeyToDataListPopup(ui::DomKey::ENTER); |
| |
| ExpectClearedForm(); |
| } |
| |
| void TriggerFormFill(const std::string& field_name) { |
| FocusFieldByName(field_name); |
| |
| // Start filling the first name field with "M" and wait for the popup to be |
| // shown. |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press Enter to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| } |
| |
| AutofillManagerTestDelegateImpl* test_delegate() { return &test_delegate_; } |
| net::EmbeddedTestServer* https_server() { return &https_server_; } |
| |
| private: |
| net::EmbeddedTestServer https_server_; |
| AutofillManagerTestDelegateImpl test_delegate_; |
| net::TestURLFetcherFactory url_fetcher_factory_; |
| |
| // KeyPressEventCallback that serves as a sink to ensure that every key press |
| // event the tests create and have the WebContents forward is handled by some |
| // key press event callback. It is necessary to have this sinkbecause if no |
| // key press event callback handles the event (at least on Mac), a DCHECK |
| // ends up going off that the |event| doesn't have an |os_event| associated |
| // with it. |
| content::RenderWidgetHost::KeyPressEventCallback key_press_event_sink_; |
| |
| // Indicates if AutofillExpandedPopupViews is enabled. |
| const bool popup_views_enabled_; |
| |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| std::unique_ptr<net::test_server::ControllableHttpResponse> |
| controllable_http_response_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutofillInteractiveTestBase); |
| }; |
| |
| // AutofillInteractiveTest ---------------------------------------------------- |
| |
| // Test params: |
| // - bool popup_views_enabled: whether feature AutofillExpandedPopupViews |
| // is enabled for testing. |
| class AutofillInteractiveTest : public AutofillInteractiveTestBase, |
| public testing::WithParamInterface<bool> { |
| protected: |
| AutofillInteractiveTest() : AutofillInteractiveTestBase(GetParam()) {} |
| ~AutofillInteractiveTest() override = default; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| AutofillInteractiveTestBase::SetUpCommandLine(command_line); |
| |
| command_line->AppendSwitchASCII( |
| translate::switches::kTranslateScriptURL, |
| embedded_test_server()->GetURL("/mock_translate_script.js").spec()); |
| } |
| }; |
| |
| // Test that basic form fill is working. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, BasicFormFill) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, BasicClear) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| TryBasicFormFill(); |
| |
| TryClearForm(); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, ClearTwoSection) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + |
| kTestBillingFormString))); |
| |
| // Fill first section. |
| TryBasicFormFill(); |
| |
| // Fill second section. |
| FocusFieldByName("firstname_billing"); |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // Clear second section. |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToDataListPopup(ui::DomKey::ARROW_DOWN); // clear |
| SendKeyToDataListPopup(ui::DomKey::ENTER); |
| |
| ExpectFieldValue("firstname_billing", ""); |
| ExpectFieldValue("lastname_billing", ""); |
| ExpectFieldValue("address1_billing", ""); |
| ExpectFieldValue("address2_billing", ""); |
| ExpectFieldValue("city_billing", ""); |
| ExpectFieldValue("state_billing", ""); |
| ExpectFieldValue("zip_billing", ""); |
| ExpectFieldValue("country_billing", ""); |
| ExpectFieldValue("phone_billing", ""); |
| |
| // First section should still be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| // Test that autofill doesn't refill a field initially modified by the user. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, ModifyFieldAndFill) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // Modify a field. |
| FocusFieldByName("city"); |
| FillElementWithValue("city", "Montreal"); |
| |
| // Fill |
| FocusFirstNameField(); |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("lastname", "Waddams"); // Modified by the user. |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("address2", "Basement"); |
| ExpectFieldValue("city", "Montreal"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("zip", "78744"); |
| ExpectFieldValue("country", "US"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| // Test that autofill works when the website prefills the form. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, PrefillFormAndFill) { |
| const char kPrefillScript[] = |
| "<script>" |
| "document.getElementById('firstname').value = 'Seb';" |
| "document.getElementById('lastname').value = 'Bell';" |
| "document.getElementById('address1').value = '3243 Notre-Dame Ouest';" |
| "document.getElementById('address2').value = 'apt 843';" |
| "document.getElementById('city').value = 'Montreal';" |
| "document.getElementById('zip').value = 'H5D 4D3';" |
| "document.getElementById('phone').value = '15142223344';" |
| "</script>"; |
| |
| // Load the test page and prefill it with the above script. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + |
| kPrefillScript))); |
| |
| CreateTestProfile(); |
| |
| // We need to delete the prefilled value and then trigger the autofill. |
| FocusFirstNameField(); |
| DeleteElementValue("firstname"); |
| |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| ExpectFilledTestForm(); |
| } |
| |
| // Test that autofill doesn't refill a field modified by the user. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| FillChangeSecondFieldRefillAndClearFirstFill) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| TryBasicFormFill(); |
| |
| // Change the last name. |
| FocusFieldByName("lastname"); |
| SendKeyToPageAndWait(ui::DomKey::BACKSPACE); |
| SendKeyToPageAndWait(ui::DomKey::BACKSPACE); |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("lastname", "Wadda"); // Modified by the user. |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("address2", "Basement"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("zip", "78744"); |
| ExpectFieldValue("country", "US"); |
| ExpectFieldValue("phone", "15125551234"); |
| |
| // Fill again by focusing on the first field. |
| FocusFirstNameField(); |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("lastname", |
| "Wadda"); // Modified by the user, should not be autofilled. |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("address2", "Basement"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("zip", "78744"); |
| ExpectFieldValue("country", "US"); |
| ExpectFieldValue("phone", "15125551234"); |
| |
| // Clear everything except last name by selecting 'clear' on the first field. |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToDataListPopup(ui::DomKey::ARROW_DOWN); // clear |
| SendKeyToDataListPopup(ui::DomKey::ENTER); |
| |
| ExpectFieldValue("firstname", ""); |
| ExpectFieldValue("lastname", |
| "Wadda"); // Modified by the user, should not be autofilled. |
| ExpectFieldValue("address1", ""); |
| ExpectFieldValue("address2", ""); |
| ExpectFieldValue("city", ""); |
| ExpectFieldValue("state", ""); |
| ExpectFieldValue("zip", ""); |
| ExpectFieldValue("country", ""); |
| ExpectFieldValue("phone", ""); |
| } |
| |
| // Test that multiple autofillings work. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| FillChangeSecondFieldRefillAndClearSecondField) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| TryBasicFormFill(); |
| |
| // Change the last name. |
| FocusFieldByName("lastname"); |
| SendKeyToPageAndWait(ui::DomKey::BACKSPACE); |
| SendKeyToPageAndWait(ui::DomKey::BACKSPACE); |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("lastname", "Wadda"); // Modified by the user. |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("address2", "Basement"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("zip", "78744"); |
| ExpectFieldValue("country", "US"); |
| ExpectFieldValue("phone", "15125551234"); |
| |
| // Autofill the last name. |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| ExpectFilledTestForm(); |
| |
| TryClearForm(); |
| } |
| |
| // Test that multiple autofillings work. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| FillChangeSecondFieldRefillSecondFieldClearFirst) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| TryBasicFormFill(); |
| |
| // Change the last name. |
| FocusFieldByName("lastname"); |
| SendKeyToPageAndWait(ui::DomKey::BACKSPACE); |
| SendKeyToPageAndWait(ui::DomKey::BACKSPACE); |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("lastname", "Wadda"); // Modified by the user. |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("address2", "Basement"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("zip", "78744"); |
| ExpectFieldValue("country", "US"); |
| ExpectFieldValue("phone", "15125551234"); |
| |
| // Autofill the last name. |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| ExpectFilledTestForm(); |
| |
| // Clear everything by selecting 'clear' on the first field. |
| FocusFirstNameField(); |
| TryClearForm(); |
| } |
| |
| // Test that multiple autofillings work. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| FillThenFillSomeWithAnotherProfileThenClear) { |
| CreateTestProfile(); |
| CreateSecondTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| TryBasicFormFill(); |
| |
| // Delete some fields. |
| FocusFieldByName("city"); |
| DeleteElementValue("city"); |
| FocusFieldByName("address1"); |
| DeleteElementValue("address1"); |
| |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); // second profile |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("lastname", "Waddams"); |
| ExpectFieldValue("address1", "333 Cat Queen St."); // second profile |
| ExpectFieldValue("address2", "Basement"); |
| ExpectFieldValue("city", "Liliput"); // second profile |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("zip", "78744"); |
| ExpectFieldValue("country", "US"); |
| ExpectFieldValue("phone", "15125551234"); |
| |
| // Clear everything by selecting 'clear' on the first field. |
| FocusFirstNameField(); |
| TryClearForm(); |
| } |
| |
| // Test that form filling can be initiated by pressing the down arrow. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, AutofillViaDownArrow) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // Focus a fillable field. |
| FocusFirstNameField(); |
| |
| // Press the down arrow to initiate Autofill and wait for the popup to be |
| // shown. |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press Enter to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, AutofillSelectViaTab) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // Focus a fillable field. |
| FocusFirstNameField(); |
| |
| // Press the down arrow to initiate Autofill and wait for the popup to be |
| // shown. |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press tab to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::TAB); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, AutofillViaClick) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| // Focus a fillable field. |
| ASSERT_NO_FATAL_FAILURE(FocusFirstNameField()); |
| |
| // Now click it. |
| test_delegate()->Reset(); |
| ASSERT_NO_FATAL_FAILURE(ClickFirstNameField()); |
| test_delegate()->Wait(); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press Enter to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| // Test params: |
| // - bool popup_views_enabled_: whether feature AutofillExpandedPopupViews |
| // is enabled. |
| // - bool single_click_enabled_: whether AutofillSingleClick is enabled. |
| class AutofillSingleClickTest |
| : public AutofillInteractiveTestBase, |
| public testing::WithParamInterface<std::tuple<bool, bool>> { |
| protected: |
| AutofillSingleClickTest() |
| : AutofillInteractiveTestBase(std::get<0>(GetParam())), |
| single_click_enabled_(std::get<1>(GetParam())) {} |
| |
| void SetUp() override { |
| scoped_feature_list_.InitWithFeatureState(features::kSingleClickAutofill, |
| single_click_enabled_); |
| AutofillInteractiveTestBase::SetUp(); |
| } |
| |
| const bool single_click_enabled_; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| // Depending on whether or not AutofillSingleClick is enabled, makes sure that |
| // the first click does or does not activate the autofill popup on the initial |
| // click within a fillable field. |
| IN_PROC_BROWSER_TEST_P(AutofillSingleClickTest, Click) { |
| // Make sure autofill data exists. |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // If AutofillSingleClick is NOT enabled, then the first time we click on the |
| // first name field, nothing should happen. |
| if (!single_click_enabled_) { |
| // Click the first name field while it's out of focus, then twiddle our |
| // thumbs a bit. If the autofill popup shows, it will hit the CHECKs in |
| // AutofillManagerTestDelegateImpl while we're waiting. |
| ASSERT_NO_FATAL_FAILURE(ClickFirstNameField()); |
| ASSERT_NO_FATAL_FAILURE(MakeSurePopupDoesntAppear()); |
| } |
| |
| // This click should activate the autofill popup. |
| test_delegate()->Reset(); |
| ASSERT_NO_FATAL_FAILURE(ClickFirstNameField()); |
| test_delegate()->Wait(); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press Enter to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| } |
| |
| // Makes sure that clicking outside the focused field doesn't activate |
| // the popup. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, DontAutofillForOutsideClick) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), |
| GURL(std::string(kDataURIPrefix) + kTestShippingFormString + |
| "<button disabled id='disabled-button'>Cant click this</button>"))); |
| |
| ASSERT_NO_FATAL_FAILURE(FocusFirstNameField()); |
| |
| // Clicking a disabled button will generate a mouse event but focus doesn't |
| // change. This tests that autofill can handle a mouse event outside a focused |
| // input *without* showing the popup. |
| ASSERT_NO_FATAL_FAILURE(ClickElementWithId("disabled-button")); |
| ASSERT_NO_FATAL_FAILURE(MakeSurePopupDoesntAppear()); |
| |
| test_delegate()->Reset(); |
| ASSERT_NO_FATAL_FAILURE(ClickFirstNameField()); |
| test_delegate()->Wait(); |
| } |
| |
| // Test that a field is still autofillable after the previously autofilled |
| // value is deleted. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, OnDeleteValueAfterAutofill) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // Invoke and accept the Autofill popup and verify the form was filled. |
| FocusFirstNameField(); |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| ExpectFilledTestForm(); |
| |
| // Delete the value of a filled field. |
| ASSERT_TRUE(content::ExecuteScript( |
| GetWebContents(), "document.getElementById('firstname').value = '';")); |
| ExpectFieldValue("firstname", ""); |
| |
| // Invoke and accept the Autofill popup and verify the field was filled. |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| ExpectFieldValue("firstname", "Milton"); |
| } |
| |
| // Test that an input field is not rendered with the yellow autofilled |
| // background color when choosing an option from the datalist suggestion list. |
| #if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_WIN) || \ |
| defined(OS_LINUX) |
| // Flakily triggers and assert on Mac; flakily gets empty string instead |
| // of "Adam" on ChromeOS. |
| // http://crbug.com/419868, http://crbug.com/595385. |
| // Flaky on Windows and Linux as well: http://crbug.com/595385 |
| #define MAYBE_OnSelectOptionFromDatalist DISABLED_OnSelectOptionFromDatalist |
| #else |
| #define MAYBE_OnSelectOptionFromDatalist OnSelectOptionFromDatalist |
| #endif |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| MAYBE_OnSelectOptionFromDatalist) { |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), |
| GURL(std::string(kDataURIPrefix) + |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| " <input list=\"dl\" type=\"search\" id=\"firstname\"><br>" |
| " <datalist id=\"dl\">" |
| " <option value=\"Adam\"></option>" |
| " <option value=\"Bob\"></option>" |
| " <option value=\"Carl\"></option>" |
| " </datalist>" |
| "</form>"))); |
| std::string orginalcolor; |
| GetFieldBackgroundColor("firstname", &orginalcolor); |
| |
| FocusFirstNameField(); |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToDataListPopup(ui::DomKey::ARROW_DOWN); |
| SendKeyToDataListPopup(ui::DomKey::ENTER); |
| ExpectFieldValue("firstname", "Adam"); |
| std::string color; |
| GetFieldBackgroundColor("firstname", &color); |
| EXPECT_EQ(color, orginalcolor); |
| } |
| |
| // Test that a JavaScript oninput event is fired after auto-filling a form. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, OnInputAfterAutofill) { |
| CreateTestProfile(); |
| |
| const char kOnInputScript[] = |
| "<script>" |
| "focused_fired = false;" |
| "unfocused_fired = false;" |
| "changed_select_fired = false;" |
| "unchanged_select_fired = false;" |
| "document.getElementById('firstname').oninput = function() {" |
| " focused_fired = true;" |
| "};" |
| "document.getElementById('lastname').oninput = function() {" |
| " unfocused_fired = true;" |
| "};" |
| "document.getElementById('state').oninput = function() {" |
| " changed_select_fired = true;" |
| "};" |
| "document.getElementById('country').oninput = function() {" |
| " unchanged_select_fired = true;" |
| "};" |
| "document.getElementById('country').value = 'US';" |
| "</script>"; |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + |
| kOnInputScript))); |
| |
| // Invoke Autofill. |
| FocusFirstNameField(); |
| |
| // Start filling the first name field with "M" and wait for the popup to be |
| // shown. |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press Enter to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| |
| bool focused_fired = false; |
| bool unfocused_fired = false; |
| bool changed_select_fired = false; |
| bool unchanged_select_fired = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(focused_fired);", |
| &focused_fired)); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(unfocused_fired);", |
| &unfocused_fired)); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(changed_select_fired);", |
| &changed_select_fired)); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(unchanged_select_fired);", |
| &unchanged_select_fired)); |
| EXPECT_TRUE(focused_fired); |
| EXPECT_TRUE(unfocused_fired); |
| EXPECT_TRUE(changed_select_fired); |
| EXPECT_FALSE(unchanged_select_fired); |
| } |
| |
| // Test that a JavaScript onchange event is fired after auto-filling a form. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, OnChangeAfterAutofill) { |
| CreateTestProfile(); |
| |
| const char kOnChangeScript[] = |
| "<script>" |
| "focused_fired = false;" |
| "unfocused_fired = false;" |
| "changed_select_fired = false;" |
| "unchanged_select_fired = false;" |
| "document.getElementById('firstname').onchange = function() {" |
| " focused_fired = true;" |
| "};" |
| "document.getElementById('lastname').onchange = function() {" |
| " unfocused_fired = true;" |
| "};" |
| "document.getElementById('state').onchange = function() {" |
| " changed_select_fired = true;" |
| "};" |
| "document.getElementById('country').onchange = function() {" |
| " unchanged_select_fired = true;" |
| "};" |
| "document.getElementById('country').value = 'US';" |
| "</script>"; |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + |
| kOnChangeScript))); |
| |
| // Invoke Autofill. |
| FocusFirstNameField(); |
| |
| // Start filling the first name field with "M" and wait for the popup to be |
| // shown. |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| |
| // Press the down arrow to select the suggestion and preview the autofilled |
| // form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| |
| // Press Enter to accept the autofill suggestions. |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // The form should be filled. |
| ExpectFilledTestForm(); |
| |
| bool focused_fired = false; |
| bool unfocused_fired = false; |
| bool changed_select_fired = false; |
| bool unchanged_select_fired = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(focused_fired);", |
| &focused_fired)); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(unfocused_fired);", |
| &unfocused_fired)); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(changed_select_fired);", |
| &changed_select_fired)); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(unchanged_select_fired);", |
| &unchanged_select_fired)); |
| EXPECT_TRUE(focused_fired); |
| EXPECT_TRUE(unfocused_fired); |
| EXPECT_TRUE(changed_select_fired); |
| EXPECT_FALSE(unchanged_select_fired); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, InputFiresBeforeChange) { |
| CreateTestProfile(); |
| |
| const char kInputFiresBeforeChangeScript[] = |
| "<script>" |
| "inputElementEvents = [];" |
| "function recordInputElementEvent(e) {" |
| " if (e.target.tagName != 'INPUT') throw 'only <input> tags allowed';" |
| " inputElementEvents.push(e.type);" |
| "}" |
| "selectElementEvents = [];" |
| "function recordSelectElementEvent(e) {" |
| " if (e.target.tagName != 'SELECT') throw 'only <select> tags allowed';" |
| " selectElementEvents.push(e.type);" |
| "}" |
| "document.getElementById('lastname').oninput = recordInputElementEvent;" |
| "document.getElementById('lastname').onchange = recordInputElementEvent;" |
| "document.getElementById('country').oninput = recordSelectElementEvent;" |
| "document.getElementById('country').onchange = recordSelectElementEvent;" |
| "</script>"; |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + |
| kInputFiresBeforeChangeScript))); |
| |
| // Invoke and accept the Autofill popup and verify the form was filled. |
| FocusFirstNameField(); |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| ExpectFilledTestForm(); |
| |
| int num_input_element_events = -1; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
| GetWebContents(), |
| "domAutomationController.send(inputElementEvents.length);", |
| &num_input_element_events)); |
| EXPECT_EQ(2, num_input_element_events); |
| |
| std::vector<std::string> input_element_events; |
| input_element_events.resize(2); |
| |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| GetWebContents(), "domAutomationController.send(inputElementEvents[0]);", |
| &input_element_events[0])); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| GetWebContents(), "domAutomationController.send(inputElementEvents[1]);", |
| &input_element_events[1])); |
| |
| EXPECT_EQ("input", input_element_events[0]); |
| EXPECT_EQ("change", input_element_events[1]); |
| |
| int num_select_element_events = -1; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
| GetWebContents(), |
| "domAutomationController.send(selectElementEvents.length);", |
| &num_select_element_events)); |
| EXPECT_EQ(2, num_select_element_events); |
| |
| std::vector<std::string> select_element_events; |
| select_element_events.resize(2); |
| |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| GetWebContents(), "domAutomationController.send(selectElementEvents[0]);", |
| &select_element_events[0])); |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| GetWebContents(), "domAutomationController.send(selectElementEvents[1]);", |
| &select_element_events[1])); |
| |
| EXPECT_EQ("input", select_element_events[0]); |
| EXPECT_EQ("change", select_element_events[1]); |
| } |
| |
| // Test that we can autofill forms distinguished only by their |id| attribute. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| AutofillFormsDistinguishedById) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| const std::string kURL = |
| std::string(kDataURIPrefix) + kTestShippingFormString + |
| "<script>" |
| "var mainForm = document.forms[0];" |
| "mainForm.id = 'mainForm';" |
| "var newForm = document.createElement('form');" |
| "newForm.action = mainForm.action;" |
| "newForm.method = mainForm.method;" |
| "newForm.id = 'newForm';" |
| "mainForm.parentNode.insertBefore(newForm, mainForm);" |
| "</script>"; |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), GURL(kURL))); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| // Test that we properly autofill forms with repeated fields. |
| // In the wild, the repeated fields are typically either email fields |
| // (duplicated for "confirmation"); or variants that are hot-swapped via |
| // JavaScript, with only one actually visible at any given time. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, AutofillFormWithRepeatedField) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), |
| GURL(std::string(kDataURIPrefix) + |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"firstname\">First name:</label>" |
| " <input type=\"text\" id=\"firstname\"" |
| " onfocus=\"domAutomationController.send(true)\"><br>" |
| "<label for=\"lastname\">Last name:</label>" |
| " <input type=\"text\" id=\"lastname\"><br>" |
| "<label for=\"address1\">Address line 1:</label>" |
| " <input type=\"text\" id=\"address1\"><br>" |
| "<label for=\"address2\">Address line 2:</label>" |
| " <input type=\"text\" id=\"address2\"><br>" |
| "<label for=\"city\">City:</label>" |
| " <input type=\"text\" id=\"city\"><br>" |
| "<label for=\"state\">State:</label>" |
| " <select id=\"state\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br>" |
| "<label for=\"state_freeform\" style=\"display:none\">State:</label>" |
| " <input type=\"text\" id=\"state_freeform\"" |
| " style=\"display:none\"><br>" |
| "<label for=\"zip\">ZIP code:</label>" |
| " <input type=\"text\" id=\"zip\"><br>" |
| "<label for=\"country\">Country:</label>" |
| " <select id=\"country\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br>" |
| "<label for=\"phone\">Phone number:</label>" |
| " <input type=\"text\" id=\"phone\"><br>" |
| "</form>"))); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| ExpectFieldValue("state_freeform", std::string()); |
| } |
| |
| // Test that we properly autofill forms with non-autofillable fields. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| AutofillFormWithNonAutofillableField) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), |
| GURL(std::string(kDataURIPrefix) + |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"firstname\">First name:</label>" |
| " <input type=\"text\" id=\"firstname\"" |
| " onfocus=\"domAutomationController.send(true)\"><br>" |
| "<label for=\"middlename\">Middle name:</label>" |
| " <input type=\"text\" id=\"middlename\" autocomplete=\"off\" /><br>" |
| "<label for=\"lastname\">Last name:</label>" |
| " <input type=\"text\" id=\"lastname\"><br>" |
| "<label for=\"address1\">Address line 1:</label>" |
| " <input type=\"text\" id=\"address1\"><br>" |
| "<label for=\"address2\">Address line 2:</label>" |
| " <input type=\"text\" id=\"address2\"><br>" |
| "<label for=\"city\">City:</label>" |
| " <input type=\"text\" id=\"city\"><br>" |
| "<label for=\"state\">State:</label>" |
| " <select id=\"state\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br>" |
| "<label for=\"zip\">ZIP code:</label>" |
| " <input type=\"text\" id=\"zip\"><br>" |
| "<label for=\"country\">Country:</label>" |
| " <select id=\"country\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br>" |
| "<label for=\"phone\">Phone number:</label>" |
| " <input type=\"text\" id=\"phone\"><br>" |
| "</form>"))); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| // Test that we can Autofill dynamically generated forms. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, DynamicFormFill) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), |
| GURL(std::string(kDataURIPrefix) + |
| "<form id=\"form\" action=\"http://www.example.com/\"" |
| " method=\"POST\"></form>" |
| "<script>" |
| "function AddElement(name, label) {" |
| " var form = document.getElementById('form');" |
| "" |
| " var label_text = document.createTextNode(label);" |
| " var label_element = document.createElement('label');" |
| " label_element.setAttribute('for', name);" |
| " label_element.appendChild(label_text);" |
| " form.appendChild(label_element);" |
| "" |
| " if (name === 'state' || name === 'country') {" |
| " var select_element = document.createElement('select');" |
| " select_element.setAttribute('id', name);" |
| " select_element.setAttribute('name', name);" |
| "" |
| " /* Add an empty selected option. */" |
| " var default_option = new Option('--', '', true);" |
| " select_element.appendChild(default_option);" |
| "" |
| " /* Add the other options. */" |
| " if (name == 'state') {" |
| " var option1 = new Option('California', 'CA');" |
| " select_element.appendChild(option1);" |
| " var option2 = new Option('Texas', 'TX');" |
| " select_element.appendChild(option2);" |
| " } else {" |
| " var option1 = new Option('Canada', 'CA');" |
| " select_element.appendChild(option1);" |
| " var option2 = new Option('United States', 'US');" |
| " select_element.appendChild(option2);" |
| " }" |
| "" |
| " form.appendChild(select_element);" |
| " } else {" |
| " var input_element = document.createElement('input');" |
| " input_element.setAttribute('id', name);" |
| " input_element.setAttribute('name', name);" |
| "" |
| " /* Add the onfocus listener to the 'firstname' field. */" |
| " if (name === 'firstname') {" |
| " input_element.onfocus = function() {" |
| " domAutomationController.send(true);" |
| " };" |
| " }" |
| "" |
| " form.appendChild(input_element);" |
| " }" |
| "" |
| " form.appendChild(document.createElement('br'));" |
| "};" |
| "" |
| "function BuildForm() {" |
| " var elements = [" |
| " ['firstname', 'First name:']," |
| " ['lastname', 'Last name:']," |
| " ['address1', 'Address line 1:']," |
| " ['address2', 'Address line 2:']," |
| " ['city', 'City:']," |
| " ['state', 'State:']," |
| " ['zip', 'ZIP code:']," |
| " ['country', 'Country:']," |
| " ['phone', 'Phone number:']," |
| " ];" |
| "" |
| " for (var i = 0; i < elements.length; i++) {" |
| " var name = elements[i][0];" |
| " var label = elements[i][1];" |
| " AddElement(name, label);" |
| " }" |
| "};" |
| "</script>"))); |
| |
| // Dynamically construct the form. |
| ASSERT_TRUE(content::ExecuteScript(GetWebContents(), "BuildForm();")); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| // Test that form filling works after reloading the current page. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, AutofillAfterReload) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // Reload the page. |
| content::WebContents* web_contents = GetWebContents(); |
| web_contents->GetController().Reload(content::ReloadType::NORMAL, false); |
| content::WaitForLoadStop(web_contents); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| } |
| |
| // Test that filling a form sends all the expected events to the different |
| // fields being filled. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, AutofillEvents) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestEventFormString))); |
| |
| // Invoke Autofill. |
| TryBasicFormFill(); |
| |
| // Checks that all the events were fired for the input field. |
| bool input_focus_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(inputfocus);", |
| &input_focus_triggered)); |
| EXPECT_TRUE(input_focus_triggered); |
| bool input_keydown_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(inputkeydown);", |
| &input_keydown_triggered)); |
| EXPECT_TRUE(input_keydown_triggered); |
| bool input_input_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(inputinput);", |
| &input_input_triggered)); |
| EXPECT_TRUE(input_input_triggered); |
| bool input_change_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(inputchange);", |
| &input_change_triggered)); |
| EXPECT_TRUE(input_change_triggered); |
| bool input_keyup_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(inputkeyup);", |
| &input_keyup_triggered)); |
| EXPECT_TRUE(input_keyup_triggered); |
| bool input_blur_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(inputblur);", |
| &input_blur_triggered)); |
| EXPECT_TRUE(input_blur_triggered); |
| |
| // Checks that all the events were fired for the textarea field. |
| bool text_focus_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(textfocus);", |
| &text_focus_triggered)); |
| EXPECT_TRUE(text_focus_triggered); |
| bool text_keydown_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(textkeydown);", |
| &text_keydown_triggered)); |
| EXPECT_TRUE(text_keydown_triggered); |
| bool text_input_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(textinput);", |
| &text_input_triggered)); |
| EXPECT_TRUE(text_input_triggered); |
| bool text_change_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(textchange);", |
| &text_change_triggered)); |
| EXPECT_TRUE(text_change_triggered); |
| bool text_keyup_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(textkeyup);", |
| &text_keyup_triggered)); |
| EXPECT_TRUE(text_keyup_triggered); |
| bool text_blur_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(textblur);", |
| &text_blur_triggered)); |
| EXPECT_TRUE(text_blur_triggered); |
| |
| // Checks that all the events were fired for the select field. |
| bool select_focus_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(selectfocus);", |
| &select_focus_triggered)); |
| EXPECT_TRUE(select_focus_triggered); |
| bool select_input_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(selectinput);", |
| &select_input_triggered)); |
| EXPECT_TRUE(select_input_triggered); |
| bool select_change_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(selectchange);", |
| &select_change_triggered)); |
| EXPECT_TRUE(select_change_triggered); |
| bool select_blur_triggered; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "domAutomationController.send(selectblur);", |
| &select_blur_triggered)); |
| EXPECT_TRUE(select_blur_triggered); |
| } |
| |
| // Test fails on Linux ASAN, see http://crbug.com/532737 |
| #if defined(ADDRESS_SANITIZER) |
| #define MAYBE_AutofillAfterTranslate DISABLED_AutofillAfterTranslate |
| #else |
| #define MAYBE_AutofillAfterTranslate AutofillAfterTranslate |
| #endif // ADDRESS_SANITIZER |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, MAYBE_AutofillAfterTranslate) { |
| ASSERT_TRUE(TranslateService::IsTranslateBubbleEnabled()); |
| |
| translate::TranslateManager::SetIgnoreMissingKeyForTesting(true); |
| |
| CreateTestProfile(); |
| |
| GURL url(std::string(kDataURIPrefix) + |
| "<form action=\"http://www.example.com/\" method=\"POST\">" |
| "<label for=\"fn\">なまえ</label>" |
| " <input type=\"text\" id=\"fn\"" |
| " onfocus=\"domAutomationController.send(true)\"" |
| "><br>" |
| "<label for=\"ln\">みょうじ</label>" |
| " <input type=\"text\" id=\"ln\"><br>" |
| "<label for=\"a1\">Address line 1:</label>" |
| " <input type=\"text\" id=\"a1\"><br>" |
| "<label for=\"a2\">Address line 2:</label>" |
| " <input type=\"text\" id=\"a2\"><br>" |
| "<label for=\"ci\">City:</label>" |
| " <input type=\"text\" id=\"ci\"><br>" |
| "<label for=\"st\">State:</label>" |
| " <select id=\"st\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">California</option>" |
| " <option value=\"TX\">Texas</option>" |
| " </select><br>" |
| "<label for=\"z\">ZIP code:</label>" |
| " <input type=\"text\" id=\"z\"><br>" |
| "<label for=\"co\">Country:</label>" |
| " <select id=\"co\">" |
| " <option value=\"\" selected=\"yes\">--</option>" |
| " <option value=\"CA\">Canada</option>" |
| " <option value=\"US\">United States</option>" |
| " </select><br>" |
| "<label for=\"ph\">Phone number:</label>" |
| " <input type=\"text\" id=\"ph\"><br>" |
| "</form>" |
| // Add additional Japanese characters to ensure the translate bar |
| // will appear. |
| "我々は重要な、興味深いものになるが、時折状況が発生するため苦労や痛みは" |
| "彼にいくつかの素晴らしいを調達することができます。それから、いくつかの利"); |
| |
| // Set up an observer to be able to wait for the bubble to be shown. |
| content::Source<content::WebContents> source(GetWebContents()); |
| content::WindowedNotificationObserver language_detected_signal( |
| chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED, source); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| ui_test_utils::NavigateToURL(browser(), url)); |
| |
| // Wait for the translate bubble to appear. |
| language_detected_signal.Wait(); |
| |
| // Verify current translate step. |
| const TranslateBubbleModel* model = |
| translate::test_utils::GetCurrentModel(browser()); |
| ASSERT_NE(nullptr, model); |
| EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, |
| model->GetViewState()); |
| |
| translate::test_utils::PressTranslate(browser()); |
| |
| // Wait for translation. |
| content::WindowedNotificationObserver translation_observer( |
| chrome::NOTIFICATION_PAGE_TRANSLATED, |
| content::NotificationService::AllSources()); |
| |
| // Simulate the translate script being retrieved. |
| // Pass fake google.translate lib as the translate script. |
| SimulateURLFetch(); |
| |
| // Simulate the render notifying the translation has been done. |
| translation_observer.Wait(); |
| |
| TryBasicFormFill(); |
| } |
| |
| // Test phone fields parse correctly from a given profile. |
| // The high level key presses execute the following: Select the first text |
| // field, invoke the autofill popup list, select the first profile within the |
| // list, and commit to the profile to populate the form. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, ComparePhoneNumbers) { |
| AutofillProfile profile; |
| profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Bob")); |
| profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith")); |
| profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 H St.")); |
| profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("San Jose")); |
| profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA")); |
| profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("95110")); |
| profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1-408-555-4567")); |
| SetTestProfile(browser(), profile); |
| |
| GURL url = embedded_test_server()->GetURL("/autofill/form_phones.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| PopulateForm("NAME_FIRST1"); |
| |
| ExpectFieldValue("NAME_FIRST1", "Bob"); |
| ExpectFieldValue("NAME_LAST1", "Smith"); |
| ExpectFieldValue("ADDRESS_HOME_LINE1", "1234 H St."); |
| ExpectFieldValue("ADDRESS_HOME_CITY", "San Jose"); |
| ExpectFieldValue("ADDRESS_HOME_STATE", "CA"); |
| ExpectFieldValue("ADDRESS_HOME_ZIP", "95110"); |
| ExpectFieldValue("PHONE_HOME_WHOLE_NUMBER", "14085554567"); |
| |
| PopulateForm("NAME_FIRST2"); |
| ExpectFieldValue("NAME_FIRST2", "Bob"); |
| ExpectFieldValue("NAME_LAST2", "Smith"); |
| ExpectFieldValue("PHONE_HOME_CITY_CODE-1", "408"); |
| ExpectFieldValue("PHONE_HOME_NUMBER", "5554567"); |
| |
| PopulateForm("NAME_FIRST3"); |
| ExpectFieldValue("NAME_FIRST3", "Bob"); |
| ExpectFieldValue("NAME_LAST3", "Smith"); |
| ExpectFieldValue("PHONE_HOME_CITY_CODE-2", "408"); |
| ExpectFieldValue("PHONE_HOME_NUMBER_3-1", "555"); |
| ExpectFieldValue("PHONE_HOME_NUMBER_4-1", "4567"); |
| ExpectFieldValue("PHONE_HOME_EXT-1", std::string()); |
| |
| PopulateForm("NAME_FIRST4"); |
| ExpectFieldValue("NAME_FIRST4", "Bob"); |
| ExpectFieldValue("NAME_LAST4", "Smith"); |
| ExpectFieldValue("PHONE_HOME_COUNTRY_CODE-1", "1"); |
| ExpectFieldValue("PHONE_HOME_CITY_CODE-3", "408"); |
| ExpectFieldValue("PHONE_HOME_NUMBER_3-2", "555"); |
| ExpectFieldValue("PHONE_HOME_NUMBER_4-2", "4567"); |
| ExpectFieldValue("PHONE_HOME_EXT-2", std::string()); |
| } |
| |
| // Test that Autofill does not fill in read-only fields. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, NoAutofillForReadOnlyFields) { |
| std::string addr_line1("1234 H St."); |
| |
| AutofillProfile profile; |
| profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Bob")); |
| profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith")); |
| profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("bsmith@gmail.com")); |
| profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16(addr_line1)); |
| profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("San Jose")); |
| profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA")); |
| profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("95110")); |
| profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Company X")); |
| profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("408-871-4567")); |
| SetTestProfile(browser(), profile); |
| |
| GURL url = |
| embedded_test_server()->GetURL("/autofill/read_only_field_test.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| PopulateForm("firstname"); |
| |
| ExpectFieldValue("email", std::string()); |
| ExpectFieldValue("address", addr_line1); |
| } |
| |
| // Test form is fillable from a profile after form was reset. |
| // Steps: |
| // 1. Fill form using a saved profile. |
| // 2. Reset the form. |
| // 3. Fill form using a saved profile. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, FormFillableOnReset) { |
| CreateTestProfile(); |
| |
| GURL url = |
| embedded_test_server()->GetURL("/autofill/autofill_test_form.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| PopulateForm("NAME_FIRST"); |
| |
| ASSERT_TRUE(content::ExecuteScript( |
| GetWebContents(), "document.getElementById('testform').reset()")); |
| |
| PopulateForm("NAME_FIRST"); |
| |
| ExpectFieldValue("NAME_FIRST", "Milton"); |
| ExpectFieldValue("NAME_LAST", "Waddams"); |
| ExpectFieldValue("EMAIL_ADDRESS", "red.swingline@initech.com"); |
| ExpectFieldValue("ADDRESS_HOME_LINE1", "4120 Freidrich Lane"); |
| ExpectFieldValue("ADDRESS_HOME_CITY", "Austin"); |
| ExpectFieldValue("ADDRESS_HOME_STATE", "Texas"); |
| ExpectFieldValue("ADDRESS_HOME_ZIP", "78744"); |
| ExpectFieldValue("ADDRESS_HOME_COUNTRY", "United States"); |
| ExpectFieldValue("PHONE_HOME_WHOLE_NUMBER", "15125551234"); |
| } |
| |
| // Test Autofill distinguishes a middle initial in a name. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| DistinguishMiddleInitialWithinName) { |
| CreateTestProfile(); |
| |
| GURL url = |
| embedded_test_server()->GetURL("/autofill/autofill_middleinit_form.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| PopulateForm("NAME_FIRST"); |
| |
| ExpectFieldValue("NAME_MIDDLE", "C"); |
| } |
| |
| // Test forms with multiple email addresses are filled properly. |
| // Entire form should be filled with one user gesture. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| MultipleEmailFilledByOneUserGesture) { |
| std::string email("bsmith@gmail.com"); |
| |
| AutofillProfile profile; |
| profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Bob")); |
| profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith")); |
| profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16(email)); |
| profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("4088714567")); |
| SetTestProfile(browser(), profile); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "/autofill/autofill_confirmemail_form.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| PopulateForm("NAME_FIRST"); |
| |
| ExpectFieldValue("EMAIL_CONFIRM", email); |
| // TODO(isherman): verify entire form. |
| } |
| |
| // Test latency time on form submit with lots of stored Autofill profiles. |
| // This test verifies when a profile is selected from the Autofill dictionary |
| // that consists of thousands of profiles, the form does not hang after being |
| // submitted. |
| // Flakily times out creating 1500 profiles: http://crbug.com/281527 |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| DISABLED_FormFillLatencyAfterSubmit) { |
| std::vector<std::string> cities; |
| cities.push_back("San Jose"); |
| cities.push_back("San Francisco"); |
| cities.push_back("Sacramento"); |
| cities.push_back("Los Angeles"); |
| |
| std::vector<std::string> streets; |
| streets.push_back("St"); |
| streets.push_back("Ave"); |
| streets.push_back("Ln"); |
| streets.push_back("Ct"); |
| |
| const int kNumProfiles = 1500; |
| std::vector<AutofillProfile> profiles; |
| for (int i = 0; i < kNumProfiles; i++) { |
| AutofillProfile profile; |
| base::string16 name(base::IntToString16(i)); |
| base::string16 email(name + ASCIIToUTF16("@example.com")); |
| base::string16 street = ASCIIToUTF16( |
| base::IntToString(base::RandInt(0, 10000)) + " " + |
| streets[base::RandInt(0, streets.size() - 1)]); |
| base::string16 city = |
| ASCIIToUTF16(cities[base::RandInt(0, cities.size() - 1)]); |
| base::string16 zip(base::IntToString16(base::RandInt(0, 10000))); |
| profile.SetRawInfo(NAME_FIRST, name); |
| profile.SetRawInfo(EMAIL_ADDRESS, email); |
| profile.SetRawInfo(ADDRESS_HOME_LINE1, street); |
| profile.SetRawInfo(ADDRESS_HOME_CITY, city); |
| profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA")); |
| profile.SetRawInfo(ADDRESS_HOME_ZIP, zip); |
| profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US")); |
| profiles.push_back(profile); |
| } |
| SetTestProfiles(browser(), &profiles); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "/autofill/latency_after_submit_test.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| PopulateForm("NAME_FIRST"); |
| |
| content::WindowedNotificationObserver load_stop_observer( |
| content::NOTIFICATION_LOAD_STOP, |
| content::Source<content::NavigationController>( |
| &GetWebContents()->GetController())); |
| |
| ASSERT_TRUE(content::ExecuteScript( |
| GetWebContents(), "document.getElementById('testform').submit();")); |
| // This will ensure the test didn't hang. |
| load_stop_observer.Wait(); |
| } |
| |
| // Test that Chrome doesn't crash when autocomplete is disabled while the user |
| // is interacting with the form. This is a regression test for |
| // http://crbug.com/160476 |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, |
| DisableAutocompleteWhileFilling) { |
| CreateTestProfile(); |
| |
| // Load the test page. |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
| browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); |
| |
| // Invoke Autofill: Start filling the first name field with "M" and wait for |
| // the popup to be shown. |
| FocusFirstNameField(); |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| |
| // Now that the popup with suggestions is showing, disable autocomplete for |
| // the active field. |
| ASSERT_TRUE(content::ExecuteScript( |
| GetWebContents(), |
| "document.querySelector('input').autocomplete = 'off';")); |
| |
| // Press the down arrow to select the suggestion and attempt to preview the |
| // autofilled form. |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| } |
| |
| // Test that dynamic forms don't get filled when the feature is disabled. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, DynamicChangingFormFill) { |
| // Explicitly disable the filling of dynamic forms. |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndDisableFeature( |
| features::kAutofillRequireSecureCreditCardContext); |
| |
| CreateTestProfile(); |
| |
| GURL url = |
| embedded_test_server()->GetURL("/autofill/dynamic_form_disabled.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_FALSE(has_refilled); |
| |
| // Make sure that the new form was not filled. |
| ExpectFieldValue("firstname_form1", ""); |
| ExpectFieldValue("address_form1", ""); |
| ExpectFieldValue("state_form1", "CA"); // Default value. |
| ExpectFieldValue("city_form1", ""); |
| ExpectFieldValue("company_form1", ""); |
| ExpectFieldValue("email_form1", ""); |
| ExpectFieldValue("phone_form1", ""); |
| } |
| |
| // Test that we can Autofill forms where some fields name change during the |
| // fill. |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, FieldsChangeName) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "/autofill/field_changing_name_during_fill.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the fill to happen. |
| bool has_filled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetWebContents(), |
| "hasFilled()", &has_filled)); |
| ASSERT_TRUE(has_filled); |
| |
| // Make sure the form was filled correctly. |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("address", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| class AutofillCreditCardInteractiveTest |
| : public AutofillInteractiveTestBase, |
| public testing::WithParamInterface<bool> { |
| protected: |
| AutofillCreditCardInteractiveTest() |
| : AutofillInteractiveTestBase(GetParam()) {} |
| ~AutofillCreditCardInteractiveTest() override = default; |
| |
| void SetUp() override { |
| scoped_feature_list_.InitWithFeatures( |
| {}, {features::kAutofillRequireSecureCreditCardContext}); |
| AutofillInteractiveTestBase::SetUp(); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| // HTTPS server only serves a valid cert for localhost, so this is needed to |
| // load pages from "a.com" without an interstitial. |
| command_line->AppendSwitch(switches::kIgnoreCertificateErrors); |
| } |
| |
| // After autofilling the credit card, there is a delayed task of recording its |
| // use on the db. If we reenable the services, the config would be deleted and |
| // we won't be able to encrypt the cc number. There will be a crash while |
| // encrypting the cc number. |
| void TearDownOnMainThread() override {} |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| DISALLOW_COPY_AND_ASSIGN(AutofillCreditCardInteractiveTest); |
| }; |
| |
| // Test that credit card autofill works. |
| IN_PROC_BROWSER_TEST_P(AutofillCreditCardInteractiveTest, FillLocalCreditCard) { |
| CreateTestCreditCart(); |
| |
| // Navigate to the page. |
| GURL url = https_server()->GetURL("a.com", |
| "/autofill/autofill_creditcard_form.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| // Trigger the autofill. |
| FocusFieldByName("CREDIT_CARD_NAME_FULL"); |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| ExpectFieldValue("CREDIT_CARD_NAME_FULL", "Milton Waddams"); |
| ExpectFieldValue("CREDIT_CARD_NUMBER", "4111111111111111"); |
| ExpectFieldValue("CREDIT_CARD_EXP_MONTH", "09"); |
| ExpectFieldValue("CREDIT_CARD_EXP_4_DIGIT_YEAR", "2999"); |
| } |
| |
| // Test params: |
| // - bool popup_views_enabled_: whether feature AutofillExpandedPopupViews |
| // is enabled. |
| // - bool restrict_unowned_fields_: whether autofill of unowned fields is |
| // restricted to checkout related pages. |
| class AutofillRestrictUnownedFieldsTest |
| : public AutofillInteractiveTestBase, |
| public testing::WithParamInterface<std::tuple<bool, bool>> { |
| protected: |
| AutofillRestrictUnownedFieldsTest() |
| : AutofillInteractiveTestBase(std::get<0>(GetParam())), |
| restrict_unowned_fields_(std::get<1>(GetParam())) { |
| std::vector<base::Feature> enabled; |
| std::vector<base::Feature> disabled = { |
| features::kAutofillEnforceMinRequiredFieldsForHeuristics, |
| features::kAutofillEnforceMinRequiredFieldsForQuery, |
| features::kAutofillEnforceMinRequiredFieldsForUpload}; |
| (restrict_unowned_fields_ ? enabled : disabled) |
| .push_back(features::kAutofillRestrictUnownedFieldsToFormlessCheckout); |
| scoped_feature_list_.InitWithFeatures(enabled, disabled); |
| } |
| |
| const bool restrict_unowned_fields_; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| // Test that we do not fill formless non-checkout forms when we enable the |
| // formless form restrictions. |
| IN_PROC_BROWSER_TEST_P(AutofillRestrictUnownedFieldsTest, NoAutocomplete) { |
| SCOPED_TRACE(base::StringPrintf("restrict_unowned_fields_ = %d", |
| restrict_unowned_fields_)); |
| base::HistogramTester histogram; |
| |
| CreateTestProfile(); |
| |
| GURL url = |
| embedded_test_server()->GetURL("/autofill/formless_no_autocomplete.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| // Of unowned forms are restricted, then there are no forms detected. |
| if (restrict_unowned_fields_) { |
| SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); |
| // We should only have samples saying that some elements were filtered. |
| auto buckets = |
| histogram.GetAllSamples("Autofill.UnownedFieldsWereFiltered"); |
| ASSERT_EQ(1u, buckets.size()); |
| EXPECT_EQ(1, buckets[0].min); // The "true" bucket. |
| |
| ASSERT_EQ(0U, GetAutofillManager()->NumFormsDetected()); |
| return; |
| } |
| |
| // If we reach this point, then unowned forms are not restricted. There |
| // should a form we can trigger fill on (using the firstname field) |
| ASSERT_FALSE(restrict_unowned_fields_); |
| ASSERT_EQ(1U, GetAutofillManager()->NumFormsDetected()); |
| TriggerFormFill("firstname"); |
| |
| // Wait for the fill to happen. |
| bool has_filled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetWebContents(), |
| "hasFilled()", &has_filled)); |
| EXPECT_EQ(has_filled, !restrict_unowned_fields_); |
| |
| SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); |
| |
| // If only some form fields are tagged with autocomplete types, then the |
| // number of input elements will not match the number of fields when autofill |
| // triees to preview or fill. |
| histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields", |
| !restrict_unowned_fields_, 2); |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("address", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| // Test that we do not fill formless non-checkout forms when we enable the |
| // formless form restrictions. This test differes from the NoAutocomplete |
| // version of the the test in that at least one of the fields has an |
| // autocomplete attribute, so autofill will always be aware of the existence |
| // of the form. |
| IN_PROC_BROWSER_TEST_P(AutofillRestrictUnownedFieldsTest, SomeAutocomplete) { |
| SCOPED_TRACE(base::StringPrintf("restrict_unowned_fields_ = %d", |
| restrict_unowned_fields_)); |
| CreateTestProfile(); |
| |
| base::HistogramTester histogram; |
| |
| GURL url = embedded_test_server()->GetURL( |
| "/autofill/formless_some_autocomplete.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| ASSERT_EQ(1U, GetAutofillManager()->NumFormsDetected()); |
| TriggerFormFill("firstname"); |
| |
| // Wait for the fill to happen. |
| bool has_filled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetWebContents(), |
| "hasFilled()", &has_filled)); |
| EXPECT_EQ(has_filled, !restrict_unowned_fields_); |
| |
| SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); |
| |
| // If only some form fields are tagged with autocomplete types, then the |
| // number of input elements will not match the number of fields when autofill |
| // triees to preview or fill. |
| histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields", |
| !restrict_unowned_fields_, 2); |
| |
| // http://crbug.com/841784 |
| // Formless fields with autocomplete attributes don't work because the |
| // extracted form and the form to be previewed/filled end up with a mismatched |
| // number of fields and early abort. |
| // This is fixed when !restrict_unowned_fields_ |
| if (restrict_unowned_fields_) { |
| // We should only have samples saying that some elements were filtered. |
| auto buckets = |
| histogram.GetAllSamples("Autofill.UnownedFieldsWereFiltered"); |
| ASSERT_EQ(1u, buckets.size()); |
| EXPECT_EQ(1, buckets[0].min); // The "true" bucket. |
| |
| ExpectFieldValue("firstname", "M"); |
| ExpectFieldValue("address", ""); |
| ExpectFieldValue("state", "--"); |
| ExpectFieldValue("city", ""); |
| ExpectFieldValue("company", ""); |
| ExpectFieldValue("email", ""); |
| ExpectFieldValue("phone", ""); |
| } else { |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("address", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| } |
| |
| // Test that we do not fill formless non-checkout forms when we enable the |
| // formless form restrictions. |
| IN_PROC_BROWSER_TEST_P(AutofillRestrictUnownedFieldsTest, AllAutocomplete) { |
| SCOPED_TRACE(base::StringPrintf("restrict_unowned_fields_ = %d", |
| restrict_unowned_fields_)); |
| CreateTestProfile(); |
| |
| base::HistogramTester histogram; |
| |
| GURL url = embedded_test_server()->GetURL( |
| "/autofill/formless_all_autocomplete.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| ASSERT_EQ(1U, GetAutofillManager()->NumFormsDetected()); |
| TriggerFormFill("firstname"); |
| |
| // Wait for the fill to happen. |
| bool has_filled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetWebContents(), |
| "hasFilled()", &has_filled)); |
| EXPECT_TRUE(has_filled); |
| |
| SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); |
| |
| // If all form fields are tagged with autocomplete types, we make them all |
| // available to be filled. |
| histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields", true, 2); |
| |
| if (restrict_unowned_fields_) { |
| // We should only have samples saying that no elements were filtered. |
| auto buckets = |
| histogram.GetAllSamples("Autofill.UnownedFieldsWereFiltered"); |
| ASSERT_EQ(1u, buckets.size()); |
| EXPECT_EQ(0, buckets[0].min); // The "false" bucket. |
| } |
| |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("address", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| // An extension of the test fixture for tests with site isolation. |
| // |
| // Test params: |
| // - bool popup_views_enabled: whether feature AutofillExpandedPopupViews |
| // is enabled for testing. |
| class AutofillInteractiveIsolationTest |
| : public AutofillInteractiveTestBase, |
| public testing::WithParamInterface<bool> { |
| protected: |
| AutofillInteractiveIsolationTest() |
| : AutofillInteractiveTestBase(GetParam()) {} |
| ~AutofillInteractiveIsolationTest() override = default; |
| |
| void SendKeyToPopupAndWait(ui::DomKey key, |
| content::RenderWidgetHost* widget) { |
| ui::KeyboardCode key_code = ui::NonPrintableDomKeyToKeyboardCode(key); |
| ui::DomCode code = ui::UsLayoutKeyboardCodeToDomCode(key_code); |
| AutofillInteractiveTestBase::SendKeyToPopupAndWait(key, code, key_code, |
| widget); |
| } |
| |
| bool IsPopupShown() { |
| return !!static_cast<ChromeAutofillClient*>( |
| ContentAutofillDriverFactory::FromWebContents(GetWebContents()) |
| ->DriverForFrame(GetWebContents()->GetMainFrame()) |
| ->autofill_manager() |
| ->client()) |
| ->popup_controller_for_testing(); |
| } |
| |
| private: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| AutofillInteractiveTestBase::SetUpCommandLine(command_line); |
| // Append --site-per-process flag. |
| content::IsolateAllSitesForTesting(command_line); |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveIsolationTest, SimpleCrossSiteFill) { |
| CreateTestProfile(); |
| |
| // Main frame is on a.com, iframe is on b.com. |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/cross_origin_iframe.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| GURL iframe_url = embedded_test_server()->GetURL( |
| "b.com", "/autofill/autofill_test_form.html"); |
| EXPECT_TRUE( |
| content::NavigateIframeToURL(GetWebContents(), "crossFrame", iframe_url)); |
| |
| // Let |test_delegate()| also observe autofill events in the iframe. |
| content::RenderFrameHost* cross_frame = |
| RenderFrameHostForName(GetWebContents(), "crossFrame"); |
| ASSERT_TRUE(cross_frame); |
| ContentAutofillDriver* cross_driver = |
| ContentAutofillDriverFactory::FromWebContents(GetWebContents()) |
| ->DriverForFrame(cross_frame); |
| ASSERT_TRUE(cross_driver); |
| cross_driver->autofill_manager()->SetTestDelegate(test_delegate()); |
| |
| // Focus the form in the iframe and simulate choosing a suggestion via |
| // keyboard. |
| std::string script_focus("document.getElementById('NAME_FIRST').focus();"); |
| ASSERT_TRUE(content::ExecuteScript(cross_frame, script_focus)); |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| content::RenderWidgetHost* widget = |
| cross_frame->GetView()->GetRenderWidgetHost(); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN, widget); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER, widget); |
| |
| // Check that the suggestion was filled. |
| std::string value; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| cross_frame, |
| "window.domAutomationController.send(" |
| " document.getElementById('NAME_FIRST').value);", |
| &value)); |
| EXPECT_EQ("Milton", value); |
| } |
| |
| // This test verifies that credit card (payment card list) popup works when the |
| // form is inside an OOPIF. |
| // Flaky on Windows http://crbug.com/728488 |
| #if defined(OS_WIN) |
| #define MAYBE_CrossSitePaymentForms DISABLED_CrossSitePaymentForms |
| #else |
| #define MAYBE_CrossSitePaymentForms CrossSitePaymentForms |
| #endif |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, MAYBE_CrossSitePaymentForms) { |
| CreateTestCreditCart(); |
| // Main frame is on a.com, iframe is on b.com. |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/cross_origin_iframe.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| GURL iframe_url = embedded_test_server()->GetURL( |
| "b.com", "/autofill/autofill_creditcard_form.html"); |
| EXPECT_TRUE( |
| content::NavigateIframeToURL(GetWebContents(), "crossFrame", iframe_url)); |
| |
| // Let |test_delegate()| also observe autofill events in the iframe. |
| content::RenderFrameHost* cross_frame = |
| RenderFrameHostForName(GetWebContents(), "crossFrame"); |
| ASSERT_TRUE(cross_frame); |
| ContentAutofillDriver* cross_driver = |
| ContentAutofillDriverFactory::FromWebContents(GetWebContents()) |
| ->DriverForFrame(cross_frame); |
| ASSERT_TRUE(cross_driver); |
| cross_driver->autofill_manager()->SetTestDelegate(test_delegate()); |
| |
| // Focus the form in the iframe and simulate choosing a suggestion via |
| // keyboard. |
| std::string script_focus( |
| "window.focus();" |
| "document.getElementById('CREDIT_CARD_NUMBER').focus();"); |
| ASSERT_TRUE(content::ExecuteScript(cross_frame, script_focus)); |
| |
| // Send an arrow dow keypress in order to trigger the autofill popup. |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(AutofillInteractiveIsolationTest, |
| DeletingFrameUnderSuggestion) { |
| CreateTestProfile(); |
| |
| // Main frame is on a.com, iframe is on b.com. |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/cross_origin_iframe.html"); |
| ui_test_utils::NavigateToURL(browser(), url); |
| GURL iframe_url = embedded_test_server()->GetURL( |
| "b.com", "/autofill/autofill_test_form.html"); |
| EXPECT_TRUE( |
| content::NavigateIframeToURL(GetWebContents(), "crossFrame", iframe_url)); |
| |
| // Let |test_delegate()| also observe autofill events in the iframe. |
| content::RenderFrameHost* cross_frame = |
| RenderFrameHostForName(GetWebContents(), "crossFrame"); |
| ASSERT_TRUE(cross_frame); |
| ContentAutofillDriver* cross_driver = |
| ContentAutofillDriverFactory::FromWebContents(GetWebContents()) |
| ->DriverForFrame(cross_frame); |
| ASSERT_TRUE(cross_driver); |
| cross_driver->autofill_manager()->SetTestDelegate(test_delegate()); |
| |
| // Focus the form in the iframe and simulate choosing a suggestion via |
| // keyboard. |
| std::string script_focus("document.getElementById('NAME_FIRST').focus();"); |
| ASSERT_TRUE(content::ExecuteScript(cross_frame, script_focus)); |
| SendKeyToPageAndWait(ui::DomKey::ARROW_DOWN); |
| content::RenderWidgetHost* widget = |
| cross_frame->GetView()->GetRenderWidgetHost(); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN, widget); |
| // Do not accept the suggestion yet, to keep the pop-up shown. |
| EXPECT_TRUE(IsPopupShown()); |
| |
| // Delete the iframe. |
| std::string script_delete = |
| "document.body.removeChild(document.getElementById('crossFrame'));"; |
| ASSERT_TRUE(content::ExecuteScript(GetWebContents(), script_delete)); |
| |
| // The popup should have disappeared with the iframe. |
| EXPECT_FALSE(IsPopupShown()); |
| } |
| |
| // Test params: |
| // - bool popup_views_enabled: whether feature AutofillExpandedPopupViews |
| // is enabled for testing. |
| class AutofillDynamicFormInteractiveTest |
| : public AutofillInteractiveTestBase, |
| public testing::WithParamInterface<bool> { |
| protected: |
| AutofillDynamicFormInteractiveTest() |
| : AutofillInteractiveTestBase(GetParam()) { |
| // Setup that the test expects a re-fill to happen. |
| test_delegate()->SetIsExpectingDynamicRefill(true); |
| } |
| ~AutofillDynamicFormInteractiveTest() override = default; |
| |
| // AutofillInteractiveTestBase: |
| void SetUp() override { |
| // Explicitly enable the filling of dynamic forms and disabled the |
| // requirement for a secure context to fill credit cards. |
| scoped_feature_list_.InitWithFeatures( |
| {features::kAutofillDynamicForms}, |
| {features::kAutofillRequireSecureCreditCardContext, |
| features::kAutofillRestrictUnownedFieldsToFormlessCheckout}); |
| |
| AutofillInteractiveTestBase::SetUp(); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| // HTTPS server only serves a valid cert for localhost, so this is needed to |
| // load pages from "a.com" without an interstitial. |
| command_line->AppendSwitch(switches::kIgnoreCertificateErrors); |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutofillDynamicFormInteractiveTest); |
| }; |
| |
| // Test that we can Autofill dynamically generated forms. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill) { |
| CreateTestProfile(); |
| |
| GURL url = |
| embedded_test_server()->GetURL("a.com", "/autofill/dynamic_form.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname_form1", "Milton"); |
| ExpectFieldValue("address_form1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state_form1", "TX"); |
| ExpectFieldValue("city_form1", "Austin"); |
| ExpectFieldValue("company_form1", "Initech"); |
| ExpectFieldValue("email_form1", "red.swingline@initech.com"); |
| ExpectFieldValue("phone_form1", "15125551234"); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| TwoDynamicChangingFormsFill) { |
| // Setup that the test expects a re-fill to happen. |
| test_delegate()->SetIsExpectingDynamicRefill(true); |
| |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL("a.com", |
| "/autofill/two_dynamic_forms.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname_form1"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled('firstname_form1')", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname_form1", "Milton"); |
| ExpectFieldValue("address_form1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state_form1", "TX"); |
| ExpectFieldValue("city_form1", "Austin"); |
| ExpectFieldValue("company_form1", "Initech"); |
| ExpectFieldValue("email_form1", "red.swingline@initech.com"); |
| ExpectFieldValue("phone_form1", "15125551234"); |
| |
| TriggerFormFill("firstname_form2"); |
| |
| // Wait for the re-fill to happen. |
| has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled('firstname_form2')", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname_form2", "Milton"); |
| ExpectFieldValue("address_form2", "4120 Freidrich Lane"); |
| ExpectFieldValue("state_form2", "TX"); |
| ExpectFieldValue("city_form2", "Austin"); |
| ExpectFieldValue("company_form2", "Initech"); |
| ExpectFieldValue("email_form2", "red.swingline@initech.com"); |
| ExpectFieldValue("phone_form2", "15125551234"); |
| } |
| |
| // Test that forms that dynamically change a second time do not get filled. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_SecondChange) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/double_dynamic_form.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for two dynamic changes to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_FALSE(has_refilled); |
| |
| // Make sure the new form was not filled. |
| ExpectFieldValue("firstname_form2", ""); |
| ExpectFieldValue("address_form2", ""); |
| ExpectFieldValue("state_form2", "CA"); // Default value. |
| ExpectFieldValue("city_form2", ""); |
| ExpectFieldValue("company_form2", ""); |
| ExpectFieldValue("email_form2", ""); |
| ExpectFieldValue("phone_form2", ""); |
| } |
| |
| // Test that forms that dynamically change after a second do not get filled. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_AfterDelay) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/dynamic_form_after_delay.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the dynamic change to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_FALSE(has_refilled); |
| |
| // Make sure that the new form was not filled. |
| ExpectFieldValue("firstname_form1", ""); |
| ExpectFieldValue("address_form1", ""); |
| ExpectFieldValue("state_form1", "CA"); // Default value. |
| ExpectFieldValue("city_form1", ""); |
| ExpectFieldValue("company_form1", ""); |
| ExpectFieldValue("email_form1", ""); |
| ExpectFieldValue("phone_form1", ""); |
| } |
| |
| // Test that only field of a type group that was filled initially get refilled. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_AddsNewFieldTypeGroups) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/dynamic_form_new_field_types.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the dynamic change to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // The fields present in the initial fill should be filled. |
| ExpectFieldValue("firstname_form1", "Milton"); |
| ExpectFieldValue("address_form1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state_form1", "TX"); |
| ExpectFieldValue("city_form1", "Austin"); |
| // Fields from group that were not present in the initial fill should not be |
| // filled |
| ExpectFieldValue("company_form1", ""); |
| // Fields that were present but hidden in the initial fill should not be |
| // filled. |
| ExpectFieldValue("email_form1", ""); |
| // The phone should be filled even if it's a different format than the initial |
| // fill. |
| ExpectFieldValue("phone_form1", "5125551234"); |
| } |
| |
| // Test that credit card fields are never re-filled. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_NotForCreditCard) { |
| CreateTestCreditCart(); |
| |
| // Navigate to the page. |
| GURL url = https_server()->GetURL("a.com", |
| "/autofill/dynamic_form_credit_card.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| // Trigger the initial fill. |
| FocusFieldByName("cc-name"); |
| SendKeyToPageAndWait(ui::DomKey::FromCharacter('M'), ui::DomCode::US_M, |
| ui::VKEY_M); |
| SendKeyToPopupAndWait(ui::DomKey::ARROW_DOWN); |
| SendKeyToPopupAndWait(ui::DomKey::ENTER); |
| |
| // Wait for the dynamic change to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_FALSE(has_refilled); |
| |
| // There should be no values in the fields. |
| ExpectFieldValue("cc-name", ""); |
| ExpectFieldValue("cc-num", ""); |
| ExpectFieldValue("cc-exp-month", "01"); // Default value. |
| ExpectFieldValue("cc-exp-year", "2010"); // Default value. |
| ExpectFieldValue("cc-csc", ""); |
| } |
| |
| // Test that we can Autofill dynamically changing selects that have options |
| // added and removed. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_SelectUpdated) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/dynamic_form_select_options_change.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| // Test that we can Autofill dynamically changing selects that have options |
| // added and removed only once. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_DoubleSelectUpdated) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/dynamic_form_double_select_options_change.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_FALSE(has_refilled); |
| |
| // The fields that were initially filled and not reset should still be filled. |
| ExpectFieldValue("firstname", ""); // That field value was reset dynamically. |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "CA"); // Default value. |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| // Test that we can Autofill dynamically generated forms with no name if the |
| // NameForAutofill of the first field matches. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_FormWithoutName) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/dynamic_form_no_name.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname_form1", "Milton"); |
| ExpectFieldValue("address_form1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state_form1", "TX"); |
| ExpectFieldValue("city_form1", "Austin"); |
| ExpectFieldValue("company_form1", "Initech"); |
| ExpectFieldValue("email_form1", "red.swingline@initech.com"); |
| ExpectFieldValue("phone_form1", "15125551234"); |
| } |
| |
| // Test that we can Autofill dynamically changing selects that have options |
| // added and removed for forms with no names if the NameForAutofill of the first |
| // field matches. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_SelectUpdated_FormWithoutName) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", |
| "/autofill/dynamic_form_with_no_name_select_options_change.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| // Test that we can Autofill dynamically generated synthetic forms if the |
| // NameForAutofill of the first field matches. |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_SyntheticForm) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/dynamic_synthetic_form.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname_syntheticform1", "Milton"); |
| ExpectFieldValue("address_syntheticform1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state_syntheticform1", "TX"); |
| ExpectFieldValue("city_syntheticform1", "Austin"); |
| ExpectFieldValue("company_syntheticform1", "Initech"); |
| ExpectFieldValue("email_syntheticform1", "red.swingline@initech.com"); |
| ExpectFieldValue("phone_syntheticform1", "15125551234"); |
| } |
| |
| // Test that we can Autofill dynamically synthetic forms when the select options |
| // change if the NameForAutofill of the first field matches |
| IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, |
| DynamicChangingFormFill_SelectUpdated_SyntheticForm) { |
| CreateTestProfile(); |
| |
| GURL url = embedded_test_server()->GetURL( |
| "a.com", "/autofill/dynamic_synthetic_form_select_options_change.html"); |
| ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| TriggerFormFill("firstname"); |
| |
| // Wait for the re-fill to happen. |
| bool has_refilled = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| GetWebContents(), "hasRefilled()", &has_refilled)); |
| ASSERT_TRUE(has_refilled); |
| |
| // Make sure the new form was filled correctly. |
| ExpectFieldValue("firstname", "Milton"); |
| ExpectFieldValue("address1", "4120 Freidrich Lane"); |
| ExpectFieldValue("state", "TX"); |
| ExpectFieldValue("city", "Austin"); |
| ExpectFieldValue("company", "Initech"); |
| ExpectFieldValue("email", "red.swingline@initech.com"); |
| ExpectFieldValue("phone", "15125551234"); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(All, AutofillInteractiveTest, testing::Bool()); |
| INSTANTIATE_TEST_CASE_P(All, |
| AutofillCreditCardInteractiveTest, |
| testing::Bool()); |
| |
| INSTANTIATE_TEST_CASE_P(All, |
| AutofillSingleClickTest, |
| testing::Combine(testing::Bool(), testing::Bool())); |
| |
| INSTANTIATE_TEST_CASE_P(All, AutofillInteractiveIsolationTest, testing::Bool()); |
| |
| INSTANTIATE_TEST_CASE_P(All, |
| AutofillDynamicFormInteractiveTest, |
| testing::Bool()); |
| |
| INSTANTIATE_TEST_CASE_P(All, |
| AutofillRestrictUnownedFieldsTest, |
| testing::Combine(testing::Bool(), testing::Bool())); |
| } // namespace autofill |