#include <stddef.h>
#include <stdint.h>
#include <string>
#include <unordered_set>
#include <vector>
#include "base/command_line.h"
#include "base/functional/callback_helpers.h"
#include "base/strings/escape.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/common/isolated_world_ids.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.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/features.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/platform/browser_accessibility.h"
#include "ui/accessibility/platform/browser_accessibility_manager.h"
#include "ui/base/buildflags.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/atl.h"
#include "base/win/scoped_com_initializer.h"
#include "ui/base/win/atl_module.h"
#endif
ElementsAre;
Pair;
#if defined(NDEBUG) && !defined(ADDRESS_SANITIZER) && \
!defined(LEAK_SANITIZER) && !defined(MEMORY_SANITIZER) && \
!defined(THREAD_SANITIZER) && !defined(UNDEFINED_SANITIZER) && \
!BUILDFLAG(IS_ANDROID)
#define IS_FAST_BUILD
constexpr int kDelayForDeferredUpdatesAfterPageLoad = 150;
#endif
namespace content {
class CrossPlatformAccessibilityBrowserTest : public ContentBrowserTest { … };
void CrossPlatformAccessibilityBrowserTest::SetUp() { … }
void CrossPlatformAccessibilityBrowserTest::ChooseFeatures(
std::vector<base::test::FeatureRef>* enabled_features,
std::vector<base::test::FeatureRef>* disabled_features) { … }
void CrossPlatformAccessibilityBrowserTest::SetUpOnMainThread() { … }
std::string CrossPlatformAccessibilityBrowserTest::GetAttr(
const ui::AXNode* node,
const ax::mojom::StringAttribute attr) { … }
int CrossPlatformAccessibilityBrowserTest::GetIntAttr(
const ui::AXNode* node,
const ax::mojom::IntAttribute attr) { … }
bool CrossPlatformAccessibilityBrowserTest::GetBoolAttr(
const ui::AXNode* node,
const ax::mojom::BoolAttribute attr) { … }
namespace {
ui::BrowserAccessibility* FindNodeByRole(ui::BrowserAccessibility* root,
ax::mojom::Role role) { … }
}
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
WebpageAccessibility) { … }
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
ReparentingANodeShouldReuseSameNativeWrapper) { … }
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
UnselectedEditableTextAccessibility) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
SelectedEditableTextAccessibility) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
MultipleInheritanceAccessibility2) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
IframeAccessibility) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
EnsureLocationChangesSendLocationUpdatesOnly) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
PlatformIframeAccessibility) { … }
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
AXNodePositionTreeBoundary) { … }
#endif
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigationSkipsCompositeItems) { … }
#endif
#if !BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
SelectSizeChangeWithOpenedPopupDoesNotCrash) { … }
#endif
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC) && \
!(BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK))
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GetBoundsRectIframes) { … }
#endif
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC) && \
!(BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK))
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GetBoundsRectWithScroll) { … }
#endif
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
SelectWithOptgroupActiveDescendant) { … }
#endif
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
SelectListWithOptgroupActiveDescendant) { … }
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
PlatformIterator) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
DuplicateChildrenAccessibility) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest, WritableElement) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
AriaSortDirection) { … }
#if !BUILDFLAG(IS_FUCHSIA)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
LocalizedLandmarkType) { … }
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#define MAYBE_LocalizedRoleDescription …
#else
#define MAYBE_LocalizedRoleDescription …
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
MAYBE_LocalizedRoleDescription) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GetStyleNameAttributeAsLocalizedString) { … }
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
TooltipStringAttributeMutuallyExclusiveOfNameFromTitle) { … }
IN_PROC_BROWSER_TEST_F(
CrossPlatformAccessibilityBrowserTest,
PlaceholderStringAttributeMutuallyExclusiveOfNameFromPlaceholder) { … }
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GetBoundsRectUnclippedRootFrameFromIFrame) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GetBoundsRectUnclippedFrameFromIFrame) { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_FUCHSIA)
#define MAYBE_ControlsIdsForDateTimePopup …
#else
#define MAYBE_ControlsIdsForDateTimePopup …
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
MAYBE_ControlsIdsForDateTimePopup) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
ControlsIdsForColorPopup) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
TextFragmentAnchor) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest, GeneratedText) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
FocusFiresJavascriptOnfocus) { … }
IN_PROC_BROWSER_TEST_F(
CrossPlatformAccessibilityBrowserTest,
DISABLED_IFrameContentHadFocus_ThenRootDocumentGainedFocus) { … }
#endif
#if BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
ImplicitRootScroller) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/implicit-root-scroller.html");
ui::BrowserAccessibilityManager* manager = GetManager();
const ui::BrowserAccessibility* heading = FindNodeByRole(
manager->GetBrowserAccessibilityRoot(), ax::mojom::Role::kHeading);
ui::AXNodeID root_scroller_id = manager->GetTreeData().root_scroller_id;
ui::BrowserAccessibility* root_scroller =
manager->GetFromID(root_scroller_id);
ASSERT_TRUE(root_scroller);
EXPECT_NE(root_scroller_id, manager->GetBrowserAccessibilityRoot()->GetId());
manager->SetUseRootScrollOffsetsWhenComputingBoundsForTesting(true);
gfx::Rect bounds = heading->GetUnclippedRootFrameBoundsRect();
EXPECT_LT(bounds.y(), 0);
manager->SetUseRootScrollOffsetsWhenComputingBoundsForTesting(false);
bounds = heading->GetUnclippedRootFrameBoundsRect();
EXPECT_GT(bounds.y(), 0);
}
#endif
#if defined(IS_FAST_BUILD)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
#define MAYBE_NonInteractiveChangesAreBatched …
#else
#define MAYBE_NonInteractiveChangesAreBatched …
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
MAYBE_NonInteractiveChangesAreBatched) {
LoadInitialAccessibilityTreeFromHtml(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div id="foo">
</div>
<script>
const startTime = performance.now();
const fooElem = document.getElementById('foo');
function addChild() {
const newChild = document.createElement('div');
newChild.innerHTML = '<button>x</button>';
fooElem.appendChild(newChild);
if (performance.now() - startTime < 1000) {
requestAnimationFrame(addChild);
} else {
document.close();
}
}
addChild();
</script>
</body>
</html>)HTML");
base::ElapsedTimer timer;
int num_batches = 0;
{
AccessibilityNotificationWaiter waiter(shell()->web_contents(),
ui::kAXModeComplete,
ax::mojom::Event::kLocationChanged);
while (timer.Elapsed().InMilliseconds() < 1000) {
std::ignore = waiter.WaitForNotificationWithTimeout(
base::Milliseconds(1000) - timer.Elapsed());
++num_batches;
}
}
EXPECT_GT(num_batches, 1);
EXPECT_LE(num_batches, 1000 / kDelayForDeferredUpdatesAfterPageLoad + 1);
}
#endif
#if defined(IS_FAST_BUILD)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
#define MAYBE_DocumentSelectionChangesAreNotBatched …
#else
#define MAYBE_DocumentSelectionChangesAreNotBatched …
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
MAYBE_DocumentSelectionChangesAreNotBatched) {
LoadInitialAccessibilityTreeFromHtml(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div id="foo">
</div>
<script>
const startTime = performance.now();
const fooElem = document.getElementById('foo');
function addChild() {
const newChild = document.createElement('div');
newChild.innerHTML = '<button>x</button>';
fooElem.appendChild(newChild);
window.getSelection().selectAllChildren(newChild);
if (performance.now() - startTime < 1000) {
requestAnimationFrame(addChild);
} else {
document.close();
}
}
addChild();
</script>
</body>
</html>)HTML");
base::ElapsedTimer timer;
int num_batches = 0;
AccessibilityNotificationWaiter waiter(
shell()->web_contents(), ui::kAXModeComplete,
ax::mojom::Event::kDocumentSelectionChanged);
while (timer.Elapsed().InMilliseconds() < 1000) {
std::ignore = waiter.WaitForNotificationWithTimeout(
base::Milliseconds(1000) - timer.Elapsed());
++num_batches;
}
EXPECT_GT(num_batches, 1000 / kDelayForDeferredUpdatesAfterPageLoad);
}
#endif
#if defined(IS_FAST_BUILD)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
#define MAYBE_ActiveDescendantChangesAreNotBatched …
#else
#define MAYBE_ActiveDescendantChangesAreNotBatched …
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
MAYBE_ActiveDescendantChangesAreNotBatched) {
LoadInitialAccessibilityTreeFromHtml(R"HTML(
<!DOCTYPE html>
<html>
<body>
<div id="foo" tabindex="0" autofocus>
</div>
<script>
const startTime = performance.now();
const fooElem = document.getElementById('foo');
let count = 0;
function addChild() {
const newChild = document.createElement('div');
++count;
newChild.innerHTML = '<button id=' + count + '>x</button>';
fooElem.appendChild(newChild);
fooElem.setAttribute('aria-activedescendant', count);
if (performance.now() - startTime < 1000) {
requestAnimationFrame(addChild);
} else {
document.close();
}
}
addChild();
</script>
</body>
</html>)HTML");
base::ElapsedTimer timer;
int num_batches = 0;
{
AccessibilityNotificationWaiter waiter(
shell()->web_contents(), ui::kAXModeComplete,
ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED);
while (timer.Elapsed().InMilliseconds() < 1000) {
std::ignore = waiter.WaitForNotificationWithTimeout(
base::Milliseconds(1000) - timer.Elapsed());
++num_batches;
}
}
EXPECT_GT(num_batches, 1000 / kDelayForDeferredUpdatesAfterPageLoad);
}
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
AccessibilityAddClickListener) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateInIframe) { … }
IN_PROC_BROWSER_TEST_F(
CrossPlatformAccessibilityBrowserTest,
SingleSelectionContainerSelectionFollowsFocusWithoutActiveDescendant) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
SingleSelectionContainerFocusSelectsActiveDescendant) { … }
IN_PROC_BROWSER_TEST_F(
CrossPlatformAccessibilityBrowserTest,
SingleSelectionContainerSelectionFollowsFocusNotSupported) { … }
#if BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK))
#define MAYBE_FlexBoxBoundingBoxUpdatesOnWindowResize …
#else
#define MAYBE_FlexBoxBoundingBoxUpdatesOnWindowResize …
#endif
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
MAYBE_FlexBoxBoundingBoxUpdatesOnWindowResize) { … }
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
TestNotificationTextDeletedInTextfield) { … }
#if BUILDFLAG(HAS_PLATFORM_ACCESSIBILITY_SUPPORT)
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
IdDeletedOnNodeRemoval) { … }
#endif
class AriaNotifyCrossPlatformAccessibilityBrowserTest
: public CrossPlatformAccessibilityBrowserTest { … };
IN_PROC_BROWSER_TEST_F(AriaNotifyCrossPlatformAccessibilityBrowserTest,
TestSingleAriaNotification) { … }
IN_PROC_BROWSER_TEST_F(AriaNotifyCrossPlatformAccessibilityBrowserTest,
TestConsecutiveCallsToAriaNotify) { … }
IN_PROC_BROWSER_TEST_F(AriaNotifyCrossPlatformAccessibilityBrowserTest,
TestConsecutiveAriaNotifications) { … }
}