blob: fea6c30f5683bf02744877221553f967028cb703 [file] [log] [blame]
// 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/autofill_test_utils.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
#include "components/autofill/core/browser/test_autofill_manager_waiter.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, "en-US") {}
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(), ui::kAXModeComplete, 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