blob: 1a9cb7b9ae50ae6b1b5986ebd39c3c1d307496e7 [file] [log] [blame]
// Copyright 2019 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 "ui/accessibility/platform/ax_platform_node_win.h"
#include "base/win/scoped_variant.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_com_win.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/accessibility_browser_test_utils.h"
#include "net/base/escape.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
using Microsoft::WRL::ComPtr;
namespace content {
class AXPlatformNodeWinBrowserTest : public ContentBrowserTest {
protected:
void LoadInitialAccessibilityTreeFromUrl(
const GURL& url,
ui::AXMode accessibility_mode = ui::kAXModeComplete) {
AccessibilityNotificationWaiter waiter(shell()->web_contents(),
accessibility_mode,
ax::mojom::Event::kLoadComplete);
NavigateToURL(shell(), url);
waiter.WaitForNotification();
}
void LoadInitialAccessibilityTreeFromHtmlFilePath(
const std::string& html_file_path,
ui::AXMode accessibility_mode = ui::kAXModeComplete) {
if (!embedded_test_server()->Started())
ASSERT_TRUE(embedded_test_server()->Start());
ASSERT_TRUE(embedded_test_server()->Started());
LoadInitialAccessibilityTreeFromUrl(
embedded_test_server()->GetURL(html_file_path), accessibility_mode);
}
void LoadInitialAccessibilityTreeFromHtml(
const std::string& html,
ui::AXMode accessibility_mode = ui::kAXModeComplete) {
LoadInitialAccessibilityTreeFromUrl(
GURL("data:text/html," + net::EscapeQueryParamValue(html, false)),
accessibility_mode);
}
BrowserAccessibilityManager* GetManagerAndAssertNonNull() {
auto GetManagerAndAssertNonNull =
[this](BrowserAccessibilityManager** result) {
WebContentsImpl* web_contents_impl =
static_cast<WebContentsImpl*>(shell()->web_contents());
ASSERT_NE(nullptr, web_contents_impl);
BrowserAccessibilityManager* browser_accessibility_manager =
web_contents_impl->GetRootBrowserAccessibilityManager();
ASSERT_NE(nullptr, browser_accessibility_manager);
*result = browser_accessibility_manager;
};
BrowserAccessibilityManager* browser_accessibility_manager;
GetManagerAndAssertNonNull(&browser_accessibility_manager);
return browser_accessibility_manager;
}
BrowserAccessibility* GetRootAndAssertNonNull() {
auto GetRootAndAssertNonNull = [this](BrowserAccessibility** result) {
BrowserAccessibility* root_browser_accessibility =
GetManagerAndAssertNonNull()->GetRoot();
ASSERT_NE(nullptr, result);
*result = root_browser_accessibility;
};
BrowserAccessibility* root_browser_accessibility;
GetRootAndAssertNonNull(&root_browser_accessibility);
return root_browser_accessibility;
}
BrowserAccessibility* FindNode(ax::mojom::Role role,
const std::string& name_or_value) {
return FindNodeInSubtree(*GetRootAndAssertNonNull(), role, name_or_value);
}
void UIAGetPropertyValueFlowsFromBrowserTestTemplate(
const BrowserAccessibility* target_browser_accessibility,
const std::vector<std::string>& expected_names) {
ASSERT_NE(nullptr, target_browser_accessibility);
auto* target_browser_accessibility_com_win =
ToBrowserAccessibilityWin(target_browser_accessibility)->GetCOM();
ASSERT_NE(nullptr, target_browser_accessibility_com_win);
base::win::ScopedVariant flows_from_variant;
target_browser_accessibility_com_win->GetPropertyValue(
UIA_FlowsFromPropertyId, flows_from_variant.Receive());
ASSERT_EQ(VT_ARRAY | VT_UNKNOWN, flows_from_variant.type());
ASSERT_EQ(1u, SafeArrayGetDim(V_ARRAY(flows_from_variant.ptr())));
LONG lower_bound, upper_bound, size;
ASSERT_HRESULT_SUCCEEDED(
SafeArrayGetLBound(V_ARRAY(flows_from_variant.ptr()), 1, &lower_bound));
ASSERT_HRESULT_SUCCEEDED(
SafeArrayGetUBound(V_ARRAY(flows_from_variant.ptr()), 1, &upper_bound));
size = upper_bound - lower_bound + 1;
ASSERT_EQ(static_cast<LONG>(expected_names.size()), size);
std::vector<std::string> names;
for (LONG i = 0; i < size; ++i) {
CComPtr<IUnknown> unknown_element = nullptr;
ASSERT_HRESULT_SUCCEEDED(SafeArrayGetElement(
V_ARRAY(flows_from_variant.ptr()), &i, &unknown_element));
ASSERT_NE(nullptr, unknown_element);
CComPtr<IRawElementProviderSimple> raw_element_provider_simple = nullptr;
ASSERT_HRESULT_SUCCEEDED(
unknown_element->QueryInterface(&raw_element_provider_simple));
ASSERT_NE(nullptr, raw_element_provider_simple);
base::win::ScopedVariant name;
ASSERT_HRESULT_SUCCEEDED(raw_element_provider_simple->GetPropertyValue(
UIA_NamePropertyId, name.Receive()));
ASSERT_EQ(VT_BSTR, name.type());
names.push_back(base::UTF16ToUTF8(
std::wstring(V_BSTR(name.ptr()), SysStringLen(V_BSTR(name.ptr())))));
}
ASSERT_THAT(names, testing::UnorderedElementsAreArray(expected_names));
}
void UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role expected_role,
content::BrowserAccessibility* (content::BrowserAccessibility::*f)(
uint32_t) const,
uint32_t index_arg,
bool expected_is_modal,
bool expected_is_window_provider_available) {
BrowserAccessibility* root_browser_accessibility =
GetRootAndAssertNonNull();
BrowserAccessibilityComWin* root_browser_accessibility_com_win =
ToBrowserAccessibilityWin(root_browser_accessibility)->GetCOM();
ASSERT_NE(nullptr, root_browser_accessibility_com_win);
BrowserAccessibility* browser_accessibility =
(root_browser_accessibility->*f)(index_arg);
ASSERT_NE(nullptr, browser_accessibility);
ASSERT_EQ(expected_role, browser_accessibility->GetRole());
BrowserAccessibilityComWin* browser_accessibility_com_win =
ToBrowserAccessibilityWin(browser_accessibility)->GetCOM();
ASSERT_NE(nullptr, browser_accessibility_com_win);
ComPtr<IWindowProvider> window_provider = nullptr;
ASSERT_HRESULT_SUCCEEDED(browser_accessibility_com_win->GetPatternProvider(
UIA_WindowPatternId, &window_provider));
if (expected_is_window_provider_available) {
ASSERT_NE(nullptr, window_provider.Get());
BOOL is_modal = FALSE;
ASSERT_HRESULT_SUCCEEDED(window_provider->get_IsModal(&is_modal));
ASSERT_EQ(expected_is_modal, is_modal);
} else {
ASSERT_EQ(nullptr, window_provider.Get());
}
}
private:
BrowserAccessibility* FindNodeInSubtree(BrowserAccessibility& node,
ax::mojom::Role role,
const std::string& name_or_value) {
const auto& name =
node.GetStringAttribute(ax::mojom::StringAttribute::kName);
const auto& value =
node.GetStringAttribute(ax::mojom::StringAttribute::kValue);
if (node.GetRole() == role &&
(name == name_or_value || value == name_or_value)) {
return &node;
}
for (unsigned int i = 0; i < node.PlatformChildCount(); ++i) {
BrowserAccessibility* result =
FindNodeInSubtree(*node.PlatformGetChild(i), role, name_or_value);
if (result)
return result;
}
return nullptr;
}
};
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAGetPropertyValueFlowsFromNone) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/aria/aria-label.html");
UIAGetPropertyValueFlowsFromBrowserTestTemplate(
FindNode(ax::mojom::Role::kCheckBox, "aria label"), {});
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAGetPropertyValueFlowsFromSingle) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/aria/aria-flowto.html");
UIAGetPropertyValueFlowsFromBrowserTestTemplate(
FindNode(ax::mojom::Role::kFooter, "next"), {"current"});
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAGetPropertyValueFlowsFromMultiple) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/aria/aria-flowto-multiple.html");
UIAGetPropertyValueFlowsFromBrowserTestTemplate(
FindNode(ax::mojom::Role::kGenericContainer, "b3"), {"a3", "c3"});
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDialog) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<dialog open>Example Text</dialog>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kDialog, &BrowserAccessibility::PlatformGetChild, 0,
false, true);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDialogAriaModalFalse) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<dialog open aria-modal="false">Example Text</dialog>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kDialog, &BrowserAccessibility::PlatformGetChild, 0,
false, true);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDialogAriaModalTrue) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<dialog open aria-modal="true">Example Text</dialog>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kDialog, &BrowserAccessibility::PlatformGetChild, 0,
true, true);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDiv) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div>Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kGenericContainer,
&BrowserAccessibility::PlatformGetChild, 0, false, false);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivAriaModalFalse) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div aria-modal="false">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kGenericContainer,
&BrowserAccessibility::PlatformGetChild, 0, false, false);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivAriaModalTrue) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div aria-modal="true">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kGenericContainer,
&BrowserAccessibility::PlatformGetChild, 0, false, false);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivDialog) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div role="dialog">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kDialog, &BrowserAccessibility::PlatformGetChild, 0,
false, true);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivDialogAriaModalFalse) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div role="dialog" aria-modal="false">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kDialog, &BrowserAccessibility::PlatformGetChild, 0,
false, true);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivDialogAriaModalTrue) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div role="dialog" aria-modal="true">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kDialog, &BrowserAccessibility::PlatformGetChild, 0,
true, true);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivAlertDialog) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div role="alertdialog">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kAlertDialog, &BrowserAccessibility::PlatformGetChild, 0,
false, true);
}
IN_PROC_BROWSER_TEST_F(
AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivAlertDialogAriaModalFalse) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div role="alertdialog" aria-modal="false">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kAlertDialog, &BrowserAccessibility::PlatformGetChild, 0,
false, true);
}
IN_PROC_BROWSER_TEST_F(
AXPlatformNodeWinBrowserTest,
UIAIWindowProviderGetIsModalOnDivAlertDialogAriaModalTrue) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div role="alertdialog" aria-modal="true">Example Text</div>
</body>
</html>
)HTML"));
UIAIWindowProviderGetIsModalBrowserTestTemplate(
ax::mojom::Role::kAlertDialog, &BrowserAccessibility::PlatformGetChild, 0,
true, true);
}
} // namespace content