1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <optional>
#include "base/test/scoped_feature_list.h"
#include "base/win/scoped_variant.h"
#include "build/build_config.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/accessibility/uia_accessibility_event_waiter.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/test_autofill_manager_injector.h"
#include "components/autofill/core/browser/foundations/browser_autofill_manager.h"
#include "components/autofill/core/browser/foundations/test_autofill_manager_waiter.h"
#include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/accessibility_notification_waiter.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/scoped_accessibility_mode_override.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_tree_manager_map.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "url/gurl.h"
namespace autofill {
class AutofillAccessibilityWinBrowserTest : public InProcessBrowserTest {
public:
AutofillAccessibilityWinBrowserTest() = default;
AutofillAccessibilityWinBrowserTest(
const AutofillAccessibilityWinBrowserTest&) = delete;
AutofillAccessibilityWinBrowserTest& operator=(
const AutofillAccessibilityWinBrowserTest&) = delete;
protected:
class TestAutofillManager : public BrowserAutofillManager {
public:
explicit TestAutofillManager(ContentAutofillDriver* driver)
: BrowserAutofillManager(driver) {}
testing::AssertionResult WaitForFormsSeen(int min_num_awaited_calls) {
return forms_seen_waiter_.Wait(min_num_awaited_calls);
}
private:
TestAutofillManagerWaiter forms_seen_waiter_{
*this,
{AutofillManagerEvent::kFormsSeen}};
};
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
scoped_accessibility_mode_.emplace(GetWebContents(), ui::kAXModeComplete);
}
void TearDownOnMainThread() override { scoped_accessibility_mode_.reset(); }
content::WebContents* GetWebContents() const {
return browser()->tab_strip_model()->GetActiveWebContents();
}
HWND GetWebPageHwnd() const {
return browser()
->window()
->GetNativeWindow()
->GetHost()
->GetAcceleratedWidget();
}
TestAutofillManager* GetAutofillManager() {
return autofill_manager_injector_[GetWebContents()];
}
void NavigateToAndWaitForForm(const GURL& url) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
ASSERT_TRUE(GetAutofillManager()->WaitForFormsSeen(1));
}
// Show drop down based on the element id.
void ShowDropdown(const std::string& field_id) {
std::string js("document.getElementById('" + field_id + "').focus();");
ASSERT_TRUE(ExecJs(GetWebContents(), js));
SendKeyToPage(GetWebContents(), ui::DomKey::ARROW_DOWN);
}
void SendKeyToPage(content::WebContents* web_contents, const ui::DomKey key) {
ui::KeyboardCode key_code = ui::NonPrintableDomKeyToKeyboardCode(key);
ui::DomCode code = ui::UsLayoutKeyboardCodeToDomCode(key_code);
SimulateKeyPress(web_contents, key, code, key_code, false, false, false,
false);
}
private:
base::test::ScopedFeatureList scoped_feature_list_{::features::kUiaProvider};
test::AutofillBrowserTestEnvironment autofill_test_environment_;
TestAutofillManagerInjector<TestAutofillManager> autofill_manager_injector_;
std::optional<content::ScopedAccessibilityModeOverride>
scoped_accessibility_mode_;
};
// The test is flaky on Windows. See https://crbug.com/1221273
#if BUILDFLAG(IS_WIN)
#define MAYBE_AutofillPopupControllerFor DISABLED_AutofillPopupControllerFor
#else
#define MAYBE_AutofillPopupControllerFor AutofillPopupControllerFor
#endif
IN_PROC_BROWSER_TEST_F(AutofillAccessibilityWinBrowserTest,
MAYBE_AutofillPopupControllerFor) {
content::AccessibilityNotificationWaiter waiter(
GetWebContents(), ax::mojom::Event::kLoadComplete);
NavigateToAndWaitForForm(
embedded_test_server()->GetURL("/accessibility/input_datalist.html"));
ASSERT_TRUE(waiter.WaitForNotification());
base::win::ScopedVariant result_variant;
content::FindAccessibilityNodeCriteria find_criteria;
find_criteria.role = ax::mojom::Role::kTextFieldWithComboBox;
// The autofill popup of the form input element has not shown yet. The form
// input element is the controller for the checkbox as indicated by the form
// input element's |aria-controls| attribute.
content::UiaGetPropertyValueVtArrayVtUnknownValidate(
UIA_ControllerForPropertyId,
FindAccessibilityNode(GetWebContents(), find_criteria), {"checkbox"});
UiaAccessibilityWaiterInfo info = {
GetWebPageHwnd(), base::ASCIIToWide("combobox"),
base::ASCIIToWide("input"), ax::mojom::Event::kControlsChanged};
std::unique_ptr<UiaAccessibilityEventWaiter> control_waiter =
std::make_unique<UiaAccessibilityEventWaiter>(info);
// Show popup and wait for UIA_ControllerForPropertyId event.
ShowDropdown("datalist");
control_waiter->Wait();
// The focus should remain on the input element.
EXPECT_EQ(content::GetFocusedAccessibilityNodeInfo(GetWebContents()).role,
ax::mojom::Role::kTextFieldWithComboBox);
// The autofill popup of the form input element is showing. The form input
// element is the controller for the checkbox and autofill popup as
// indicated by the form input element's |aria-controls| attribute and the
// existing popup.
content::UiaGetPropertyValueVtArrayVtUnknownValidate(
UIA_ControllerForPropertyId,
FindAccessibilityNode(GetWebContents(), find_criteria),
{"checkbox", "Autofill"});
control_waiter = std::make_unique<UiaAccessibilityEventWaiter>(info);
// Hide popup and wait for UIA_ControllerForPropertyId event.
SendKeyToPage(GetWebContents(), ui::DomKey::TAB);
control_waiter->Wait();
// The autofill popup of the form input element is hidden. The form
// input element is the controller for the checkbox as indicated by the form
// input element's |aria-controls| attribute.
content::UiaGetPropertyValueVtArrayVtUnknownValidate(
UIA_ControllerForPropertyId,
FindAccessibilityNode(GetWebContents(), find_criteria), {"checkbox"});
}
} // namespace autofill
|