summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/tests/browser')
-rw-r--r--accessible/tests/browser/atk/browser_role.js2
-rw-r--r--accessible/tests/browser/atk/browser_table.js2
-rw-r--r--accessible/tests/browser/bounds/browser_accessible_moved.js8
-rw-r--r--accessible/tests/browser/bounds/browser_caret_rect.js2
-rw-r--r--accessible/tests/browser/bounds/browser_test_display_contents.js6
-rw-r--r--accessible/tests/browser/bounds/browser_test_iframe_transform.js4
-rw-r--r--accessible/tests/browser/bounds/browser_test_simple_transform.js6
-rw-r--r--accessible/tests/browser/bounds/browser_test_zoom.js6
-rw-r--r--accessible/tests/browser/bounds/browser_zero_area.js8
-rw-r--r--accessible/tests/browser/browser_shutdown_acc_reference.js2
-rw-r--r--accessible/tests/browser/browser_shutdown_doc_acc_reference.js2
-rw-r--r--accessible/tests/browser/browser_shutdown_multi_acc_reference_doc.js2
-rw-r--r--accessible/tests/browser/browser_shutdown_multi_acc_reference_obj.js2
-rw-r--r--accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_doc.js4
-rw-r--r--accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_obj.js4
-rw-r--r--accessible/tests/browser/browser_shutdown_multi_reference.js2
-rw-r--r--accessible/tests/browser/browser_shutdown_parent_own_reference.js2
-rw-r--r--accessible/tests/browser/browser_shutdown_proxy_acc_reference.js2
-rw-r--r--accessible/tests/browser/browser_shutdown_proxy_doc_acc_reference.js4
-rw-r--r--accessible/tests/browser/browser_shutdown_remote_own_reference.js2
-rw-r--r--accessible/tests/browser/e10s/browser.toml5
-rw-r--r--accessible/tests/browser/e10s/browser_aria_activedescendant.js485
-rw-r--r--accessible/tests/browser/e10s/browser_caching_attributes.js2
-rw-r--r--accessible/tests/browser/e10s/browser_caching_large_update.js97
-rw-r--r--accessible/tests/browser/e10s/browser_caching_name.js2
-rw-r--r--accessible/tests/browser/e10s/browser_caching_relations_002.js109
-rw-r--r--accessible/tests/browser/e10s/browser_caching_states.js157
-rw-r--r--accessible/tests/browser/e10s/browser_caching_table.js2
-rw-r--r--accessible/tests/browser/e10s/browser_caching_text_bounds.js14
-rw-r--r--accessible/tests/browser/e10s/browser_file_input.js2
-rw-r--r--accessible/tests/browser/e10s/browser_treeupdate_select_dropdown.js2
-rw-r--r--accessible/tests/browser/events/browser_test_docload.js2
-rw-r--r--accessible/tests/browser/events/browser_test_focus_browserui.js2
-rw-r--r--accessible/tests/browser/events/browser_test_focus_dialog.js2
-rw-r--r--accessible/tests/browser/events/browser_test_focus_urlbar.js4
-rw-r--r--accessible/tests/browser/events/browser_test_scrolling.js49
-rw-r--r--accessible/tests/browser/mac/browser_app.js38
-rw-r--r--accessible/tests/browser/mac/browser_bounds.js56
-rw-r--r--accessible/tests/browser/mac/browser_live_regions.js2
-rw-r--r--accessible/tests/browser/mac/browser_menulist.js2
-rw-r--r--accessible/tests/browser/mac/browser_roles_elements.js4
-rw-r--r--accessible/tests/browser/mac/browser_rotor.js8
-rw-r--r--accessible/tests/browser/mac/browser_text_leaf.js6
-rw-r--r--accessible/tests/browser/mac/browser_text_selection.js2
-rw-r--r--accessible/tests/browser/mac/browser_toggle_radio_check.js2
-rw-r--r--accessible/tests/browser/mac/browser_webarea.js10
-rw-r--r--accessible/tests/browser/scroll/browser_test_scroll_bounds.js14
-rw-r--r--accessible/tests/browser/scroll/browser_test_scroll_substring.js5
-rw-r--r--accessible/tests/browser/selectable/browser_test_select.js2
-rw-r--r--accessible/tests/browser/shared-head.js6
-rw-r--r--accessible/tests/browser/text/browser_text_paragraph_boundary.js2
-rw-r--r--accessible/tests/browser/text/head.js2
-rw-r--r--accessible/tests/browser/tree/browser_aria_owns.js2
-rw-r--r--accessible/tests/browser/tree/browser_browser_element.js2
-rw-r--r--accessible/tests/browser/tree/browser_lazy_tabs.js2
-rw-r--r--accessible/tests/browser/tree/browser_test_nsIAccessibleDocument_URL.js4
-rw-r--r--accessible/tests/browser/windows/a11y_setup.py126
-rw-r--r--accessible/tests/browser/windows/ia2/browser.toml2
-rw-r--r--accessible/tests/browser/windows/ia2/browser_osPicker.js51
-rw-r--r--accessible/tests/browser/windows/ia2/browser_role.js2
-rw-r--r--accessible/tests/browser/windows/uia/browser.toml2
-rw-r--r--accessible/tests/browser/windows/uia/browser_controlType.js4
-rw-r--r--accessible/tests/browser/windows/uia/browser_elementFromPoint.js4
-rw-r--r--accessible/tests/browser/windows/uia/browser_tree.js104
-rw-r--r--accessible/tests/browser/windows/uia/head.js37
65 files changed, 1320 insertions, 191 deletions
diff --git a/accessible/tests/browser/atk/browser_role.js b/accessible/tests/browser/atk/browser_role.js
index 7b870b3337..47cc5ef28f 100644
--- a/accessible/tests/browser/atk/browser_role.js
+++ b/accessible/tests/browser/atk/browser_role.js
@@ -11,7 +11,7 @@ addAccessibleTask(
`
<p id="p">p</p>
`,
- async function (browser, docAcc) {
+ async function () {
let role = await runPython(`
global doc
doc = getDoc()
diff --git a/accessible/tests/browser/atk/browser_table.js b/accessible/tests/browser/atk/browser_table.js
index 98b3270465..55452709e8 100644
--- a/accessible/tests/browser/atk/browser_table.js
+++ b/accessible/tests/browser/atk/browser_table.js
@@ -20,7 +20,7 @@ addAccessibleTask(
</tr>
</table>
`,
- async function (browser, docAcc) {
+ async function () {
let result = await runPython(`
global doc
doc = getDoc()
diff --git a/accessible/tests/browser/bounds/browser_accessible_moved.js b/accessible/tests/browser/bounds/browser_accessible_moved.js
index 307c680000..a62f7ad8d0 100644
--- a/accessible/tests/browser/bounds/browser_accessible_moved.js
+++ b/accessible/tests/browser/bounds/browser_accessible_moved.js
@@ -12,10 +12,10 @@ function assertBoundsNonZero(acc) {
let width = {};
let height = {};
acc.getBounds(x, y, width, height);
- ok(x.value > 0, "x is non-0");
- ok(y.value > 0, "y is non-0");
- ok(width.value > 0, "width is non-0");
- ok(height.value > 0, "height is non-0");
+ Assert.greater(x.value, 0, "x is non-0");
+ Assert.greater(y.value, 0, "y is non-0");
+ Assert.greater(width.value, 0, "width is non-0");
+ Assert.greater(height.value, 0, "height is non-0");
}
/**
diff --git a/accessible/tests/browser/bounds/browser_caret_rect.js b/accessible/tests/browser/bounds/browser_caret_rect.js
index ac0ee3aa50..9f5cac33a5 100644
--- a/accessible/tests/browser/bounds/browser_caret_rect.js
+++ b/accessible/tests/browser/bounds/browser_caret_rect.js
@@ -46,7 +46,7 @@ async function testCaretRect(browser, docAcc, id, offset) {
);
const [caretX, caretY, caretW, caretH] = await getCaretRect(browser, id);
if (atEnd) {
- ok(caretX > charX.value, "Caret x after last character x");
+ Assert.greater(caretX, charX.value, "Caret x after last character x");
} else {
is(caretX, charX.value, "Caret x same as character x");
}
diff --git a/accessible/tests/browser/bounds/browser_test_display_contents.js b/accessible/tests/browser/bounds/browser_test_display_contents.js
index db1bfce178..4111ac5a81 100644
--- a/accessible/tests/browser/bounds/browser_test_display_contents.js
+++ b/accessible/tests/browser/bounds/browser_test_display_contents.js
@@ -16,7 +16,11 @@ async function testContentBounds(browser, acc) {
is(x, expectedX, "Wrong x coordinate of " + prettyAccName);
is(y, expectedY, "Wrong y coordinate of " + prettyAccName);
is(width, expectedWidth, "Wrong width of " + prettyAccName);
- ok(height >= expectedHeight, "Wrong height of " + prettyAccName);
+ Assert.greaterOrEqual(
+ height,
+ expectedHeight,
+ "Wrong height of " + prettyAccName
+ );
}
async function runTests(browser, accDoc) {
diff --git a/accessible/tests/browser/bounds/browser_test_iframe_transform.js b/accessible/tests/browser/bounds/browser_test_iframe_transform.js
index a44ab75faf..015d466da9 100644
--- a/accessible/tests/browser/bounds/browser_test_iframe_transform.js
+++ b/accessible/tests/browser/bounds/browser_test_iframe_transform.js
@@ -68,7 +68,7 @@ function testBoundsWithOffset(browser, iframeDocAcc, id, domElmBounds, offset) {
addAccessibleTask(
`<div id='${ELEM_ID}'>hello world</div>`,
- async function (browser, iframeDocAcc, contentDocAcc) {
+ async function (browser, iframeDocAcc) {
ok(iframeDocAcc, "IFRAME document accessible is present");
await testBoundsWithContent(iframeDocAcc, ELEM_ID, browser);
@@ -143,7 +143,7 @@ addAccessibleTask(
*/
addAccessibleTask(
`<div id="div" style="width: 30px; height: 30px"></div>`,
- async function (browser, accDoc, foo) {
+ async function (browser, accDoc) {
const docWidth = () => {
let width = {};
accDoc.getBounds({}, {}, width, {});
diff --git a/accessible/tests/browser/bounds/browser_test_simple_transform.js b/accessible/tests/browser/bounds/browser_test_simple_transform.js
index 7197968b40..b5cb983e72 100644
--- a/accessible/tests/browser/bounds/browser_test_simple_transform.js
+++ b/accessible/tests/browser/bounds/browser_test_simple_transform.js
@@ -9,7 +9,7 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
// test basic translation
addAccessibleTask(
`<p id="translate">hello world</p>`,
- async function (browser, iframeDocAcc, contentDocAcc) {
+ async function (browser, iframeDocAcc) {
ok(iframeDocAcc, "IFRAME document accessible is present");
await testBoundsWithContent(iframeDocAcc, "translate", browser);
@@ -42,7 +42,7 @@ addAccessibleTask(
// test basic rotation
addAccessibleTask(
`<p id="rotate">hello world</p>`,
- async function (browser, iframeDocAcc, contentDocAcc) {
+ async function (browser, iframeDocAcc) {
ok(iframeDocAcc, "IFRAME document accessible is present");
await testBoundsWithContent(iframeDocAcc, "rotate", browser);
@@ -60,7 +60,7 @@ addAccessibleTask(
// test basic scale
addAccessibleTask(
`<p id="scale">hello world</p>`,
- async function (browser, iframeDocAcc, contentDocAcc) {
+ async function (browser, iframeDocAcc) {
ok(iframeDocAcc, "IFRAME document accessible is present");
await testBoundsWithContent(iframeDocAcc, "scale", browser);
diff --git a/accessible/tests/browser/bounds/browser_test_zoom.js b/accessible/tests/browser/bounds/browser_test_zoom.js
index ac84e485a4..1af84d61d8 100644
--- a/accessible/tests/browser/bounds/browser_test_zoom.js
+++ b/accessible/tests/browser/bounds/browser_test_zoom.js
@@ -16,7 +16,11 @@ async function testContentBounds(browser, acc) {
is(x, expectedX, "Wrong x coordinate of " + prettyAccName);
is(y, expectedY, "Wrong y coordinate of " + prettyAccName);
is(width, expectedWidth, "Wrong width of " + prettyAccName);
- ok(height >= expectedHeight, "Wrong height of " + prettyAccName);
+ Assert.greaterOrEqual(
+ height,
+ expectedHeight,
+ "Wrong height of " + prettyAccName
+ );
}
async function runTests(browser, accDoc) {
diff --git a/accessible/tests/browser/bounds/browser_zero_area.js b/accessible/tests/browser/bounds/browser_zero_area.js
index c0f9db2673..80954fbd1a 100644
--- a/accessible/tests/browser/bounds/browser_zero_area.js
+++ b/accessible/tests/browser/bounds/browser_zero_area.js
@@ -67,10 +67,10 @@ addAccessibleTask(
const radio = findAccessibleChildByID(accDoc, "radio");
const contentDPR = await getContentDPR(browser);
const [x, y, width, height] = getBounds(radio, contentDPR);
- ok(x < 0, "X coordinate should be negative");
- ok(y > 0, "Y coordinate should be positive");
- ok(width > 0, "Width should be positive");
- ok(height > 0, "Height should be positive");
+ Assert.less(x, 0, "X coordinate should be negative");
+ Assert.greater(y, 0, "Y coordinate should be positive");
+ Assert.greater(width, 0, "Width should be positive");
+ Assert.greater(height, 0, "Height should be positive");
// Note: the exact values of x, y, width, and height
// are inconsistent with the DOM element values of those
// fields, so we don't check our bounds against them with
diff --git a/accessible/tests/browser/browser_shutdown_acc_reference.js b/accessible/tests/browser/browser_shutdown_acc_reference.js
index 1768095f94..975eab55a0 100644
--- a/accessible/tests/browser/browser_shutdown_acc_reference.js
+++ b/accessible/tests/browser/browser_shutdown_acc_reference.js
@@ -36,7 +36,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_doc_acc_reference.js b/accessible/tests/browser/browser_shutdown_doc_acc_reference.js
index 8f7bf6d423..7d999d7d13 100644
--- a/accessible/tests/browser/browser_shutdown_doc_acc_reference.js
+++ b/accessible/tests/browser/browser_shutdown_doc_acc_reference.js
@@ -28,7 +28,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_multi_acc_reference_doc.js b/accessible/tests/browser/browser_shutdown_multi_acc_reference_doc.js
index 273fc7175d..1200e02116 100644
--- a/accessible/tests/browser/browser_shutdown_multi_acc_reference_doc.js
+++ b/accessible/tests/browser/browser_shutdown_multi_acc_reference_doc.js
@@ -39,7 +39,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_multi_acc_reference_obj.js b/accessible/tests/browser/browser_shutdown_multi_acc_reference_obj.js
index af21b3dc4c..346aa9b6c4 100644
--- a/accessible/tests/browser/browser_shutdown_multi_acc_reference_obj.js
+++ b/accessible/tests/browser/browser_shutdown_multi_acc_reference_obj.js
@@ -39,7 +39,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_doc.js b/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_doc.js
index e4091c5216..84429cf077 100644
--- a/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_doc.js
+++ b/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_doc.js
@@ -30,7 +30,7 @@ add_task(async function () {
<body id="body"><div id="div"></div></body>
</html>`,
},
- async function (browser) {
+ async function () {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
@@ -46,7 +46,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_obj.js b/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_obj.js
index f6eca362b0..b7356f3e6f 100644
--- a/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_obj.js
+++ b/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_obj.js
@@ -30,7 +30,7 @@ add_task(async function () {
<body id="body"><div id="div"></div></body>
</html>`,
},
- async function (browser) {
+ async function () {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
@@ -46,7 +46,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_multi_reference.js b/accessible/tests/browser/browser_shutdown_multi_reference.js
index a92f6faf61..49ee822afa 100644
--- a/accessible/tests/browser/browser_shutdown_multi_reference.js
+++ b/accessible/tests/browser/browser_shutdown_multi_reference.js
@@ -31,7 +31,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_parent_own_reference.js b/accessible/tests/browser/browser_shutdown_parent_own_reference.js
index 472e977626..ffbe33f137 100644
--- a/accessible/tests/browser/browser_shutdown_parent_own_reference.js
+++ b/accessible/tests/browser/browser_shutdown_parent_own_reference.js
@@ -61,7 +61,7 @@ add_task(async function () {
shutdownAccService(browser);
await contentA11yShutdownObserver;
const contentA11yShutdown = new Promise((resolve, reject) =>
- contentA11yShutdownPromise.then(flag =>
+ contentA11yShutdownPromise.then(() =>
contentCanShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_proxy_acc_reference.js b/accessible/tests/browser/browser_shutdown_proxy_acc_reference.js
index 7144cff019..47fa47da53 100644
--- a/accessible/tests/browser/browser_shutdown_proxy_acc_reference.js
+++ b/accessible/tests/browser/browser_shutdown_proxy_acc_reference.js
@@ -41,7 +41,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_proxy_doc_acc_reference.js b/accessible/tests/browser/browser_shutdown_proxy_doc_acc_reference.js
index 6d4ad71f1e..72a424b21f 100644
--- a/accessible/tests/browser/browser_shutdown_proxy_doc_acc_reference.js
+++ b/accessible/tests/browser/browser_shutdown_proxy_doc_acc_reference.js
@@ -30,7 +30,7 @@ add_task(async function () {
<body id="body"></body>
</html>`,
},
- async function (browser) {
+ async function () {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
@@ -43,7 +43,7 @@ add_task(async function () {
const [a11yShutdownObserver, a11yShutdownPromise] = shutdownAccService();
await a11yShutdownObserver;
const a11yShutdown = new Promise((resolve, reject) =>
- a11yShutdownPromise.then(flag =>
+ a11yShutdownPromise.then(() =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/browser_shutdown_remote_own_reference.js b/accessible/tests/browser/browser_shutdown_remote_own_reference.js
index a30d191b53..83c68689b7 100644
--- a/accessible/tests/browser/browser_shutdown_remote_own_reference.js
+++ b/accessible/tests/browser/browser_shutdown_remote_own_reference.js
@@ -108,7 +108,7 @@ add_task(async function () {
const [contentA11yShutdownObserver, contentA11yShutdownPromise] =
shutdownAccService(browser);
const contentA11yShutdown = new Promise((resolve, reject) =>
- contentA11yShutdownPromise.then(flag =>
+ contentA11yShutdownPromise.then(() =>
contentCanShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
diff --git a/accessible/tests/browser/e10s/browser.toml b/accessible/tests/browser/e10s/browser.toml
index dfac6b5219..914f839993 100644
--- a/accessible/tests/browser/e10s/browser.toml
+++ b/accessible/tests/browser/e10s/browser.toml
@@ -18,9 +18,12 @@ support-files = [
]
prefs = [
"javascript.options.asyncstack_capture_debuggee_only=false",
- "dom.element.popover.enabled=true"
+ "dom.element.popover.enabled=true",
+ "accessibility.ARIAElementReflection.enabled=true"
]
+["browser_aria_activedescendant.js"]
+
# Caching tests
["browser_caching_actions.js"]
diff --git a/accessible/tests/browser/e10s/browser_aria_activedescendant.js b/accessible/tests/browser/e10s/browser_aria_activedescendant.js
new file mode 100644
index 0000000000..f58c5aab39
--- /dev/null
+++ b/accessible/tests/browser/e10s/browser_aria_activedescendant.js
@@ -0,0 +1,485 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* import-globals-from ../../mochitest/role.js */
+/* import-globals-from ../../mochitest/states.js */
+loadScripts(
+ { name: "role.js", dir: MOCHITESTS_DIR },
+ { name: "states.js", dir: MOCHITESTS_DIR }
+);
+
+async function synthFocus(browser, container, item) {
+ let focusPromise = waitForEvent(EVENT_FOCUS, item);
+ await invokeContentTask(browser, [container], _container => {
+ let elm = (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document)(_container);
+ elm.focus();
+ });
+ await focusPromise;
+}
+
+async function changeARIAActiveDescendant(
+ browser,
+ container,
+ itemId,
+ prevItemId,
+ elementReflection
+) {
+ let expectedEvents = [[EVENT_FOCUS, itemId]];
+
+ if (prevItemId) {
+ info("A state change of the previous item precedes the new one.");
+ expectedEvents.push(
+ stateChangeEventArgs(prevItemId, EXT_STATE_ACTIVE, false, true)
+ );
+ }
+
+ expectedEvents.push(
+ stateChangeEventArgs(itemId, EXT_STATE_ACTIVE, true, true)
+ );
+
+ let expectedPromise = waitForEvents(expectedEvents);
+ await invokeContentTask(
+ browser,
+ [container, itemId, elementReflection],
+ (_container, _itemId, _elementReflection) => {
+ let getElm = (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document);
+ let elm = getElm(_container);
+ if (_elementReflection) {
+ elm.ariaActiveDescendantElement = getElm(_itemId);
+ } else {
+ elm.setAttribute("aria-activedescendant", _itemId);
+ }
+ }
+ );
+
+ await expectedPromise;
+}
+
+async function clearARIAActiveDescendant(
+ browser,
+ container,
+ prevItemId,
+ defaultId,
+ elementReflection
+) {
+ let expectedEvents = [[EVENT_FOCUS, defaultId || container]];
+ if (prevItemId) {
+ expectedEvents.push(
+ stateChangeEventArgs(prevItemId, EXT_STATE_ACTIVE, false, true)
+ );
+ }
+
+ if (defaultId) {
+ expectedEvents.push(
+ stateChangeEventArgs(defaultId, EXT_STATE_ACTIVE, true, true)
+ );
+ }
+
+ let expectedPromise = waitForEvents(expectedEvents);
+ await invokeContentTask(
+ browser,
+ [container, elementReflection],
+ (_container, _elementReflection) => {
+ let elm = (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document)(_container);
+ if (_elementReflection) {
+ elm.ariaActiveDescendantElement = null;
+ } else {
+ elm.removeAttribute("aria-activedescendant");
+ }
+ }
+ );
+
+ await expectedPromise;
+}
+
+async function insertItemNFocus(
+ browser,
+ container,
+ newItemID,
+ prevItemId,
+ elementReflection
+) {
+ let expectedEvents = [
+ [EVENT_SHOW, newItemID],
+ [EVENT_FOCUS, newItemID],
+ ];
+
+ if (prevItemId) {
+ info("A state change of the previous item precedes the new one.");
+ expectedEvents.push(
+ stateChangeEventArgs(prevItemId, EXT_STATE_ACTIVE, false, true)
+ );
+ }
+
+ expectedEvents.push(
+ stateChangeEventArgs(newItemID, EXT_STATE_ACTIVE, true, true)
+ );
+
+ let expectedPromise = waitForEvents(expectedEvents);
+
+ await invokeContentTask(
+ browser,
+ [container, newItemID, elementReflection],
+ (_container, _newItemID, _elementReflection) => {
+ let elm = (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document)(_container);
+ let itemElm = content.document.createElement("div");
+ itemElm.setAttribute("id", _newItemID);
+ itemElm.setAttribute("role", "listitem");
+ itemElm.textContent = _newItemID;
+ elm.appendChild(itemElm);
+ if (_elementReflection) {
+ elm.ariaActiveDescendantElement = itemElm;
+ } else {
+ elm.setAttribute("aria-activedescendant", _newItemID);
+ }
+ }
+ );
+
+ await expectedPromise;
+}
+
+async function moveARIAActiveDescendantID(browser, fromID, toID) {
+ let expectedEvents = [
+ [EVENT_FOCUS, toID],
+ stateChangeEventArgs(toID, EXT_STATE_ACTIVE, true, true),
+ ];
+
+ let expectedPromise = waitForEvents(expectedEvents);
+ await invokeContentTask(browser, [fromID, toID], (_fromID, _toID) => {
+ let orig = (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document)(_toID);
+ if (orig) {
+ orig.id = "";
+ }
+ (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document)(_fromID).id = _toID;
+ });
+ await expectedPromise;
+}
+
+async function changeARIAActiveDescendantInvalid(
+ browser,
+ container,
+ invalidID = "invalid",
+ prevItemId = null
+) {
+ let expectedEvents = [[EVENT_FOCUS, container]];
+ if (prevItemId) {
+ expectedEvents.push(
+ stateChangeEventArgs(prevItemId, EXT_STATE_ACTIVE, false, true)
+ );
+ }
+
+ let expectedPromise = waitForEvents(expectedEvents);
+ await invokeContentTask(
+ browser,
+ [container, invalidID],
+ (_container, _invalidID) => {
+ let elm = (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document)(_container);
+ elm.setAttribute("aria-activedescendant", _invalidID);
+ }
+ );
+
+ await expectedPromise;
+}
+
+const LISTBOX_MARKUP = `
+<div role="listbox" aria-activedescendant="item1" id="listbox" tabindex="1"
+aria-owns="item3">
+<div role="listitem" id="item1">item1</div>
+<div role="listitem" id="item2">item2</div>
+<div role="listitem" id="roaming" data-id="roaming">roaming</div>
+<div role="listitem" id="roaming2" data-id="roaming2">roaming2</div>
+</div>
+<div role="listitem" id="item3">item3</div>
+<div role="combobox" id="combobox">
+<input id="combobox_entry">
+<ul>
+ <li role="option" id="combobox_option1">option1</li>
+ <li role="option" id="combobox_option2">option2</li>
+</ul>
+</div>`;
+
+async function basicListboxTest(browser, elementReflection) {
+ await synthFocus(browser, "listbox", "item1");
+ await changeARIAActiveDescendant(
+ browser,
+ "listbox",
+ "item2",
+ "item1",
+ elementReflection
+ );
+ await changeARIAActiveDescendant(
+ browser,
+ "listbox",
+ "item3",
+ "item2",
+ elementReflection
+ );
+
+ info("Focus out of listbox");
+ await synthFocus(browser, "combobox_entry", "combobox_entry");
+ await changeARIAActiveDescendant(
+ browser,
+ "combobox",
+ "combobox_option2",
+ null,
+ elementReflection
+ );
+ await changeARIAActiveDescendant(
+ browser,
+ "combobox",
+ "combobox_option1",
+ null,
+ elementReflection
+ );
+
+ info("Focus back in listbox");
+ await synthFocus(browser, "listbox", "item3");
+ await insertItemNFocus(
+ browser,
+ "listbox",
+ "item4",
+ "item3",
+ elementReflection
+ );
+
+ await clearARIAActiveDescendant(
+ browser,
+ "listbox",
+ "item4",
+ null,
+ elementReflection
+ );
+ await changeARIAActiveDescendant(
+ browser,
+ "listbox",
+ "item1",
+ null,
+ elementReflection
+ );
+}
+
+addAccessibleTask(
+ LISTBOX_MARKUP,
+ async function (browser, docAcc) {
+ info("Test aria-activedescendant content attribute");
+ await basicListboxTest(browser, false);
+
+ await changeARIAActiveDescendantInvalid(
+ browser,
+ "listbox",
+ "invalid",
+ "item1"
+ );
+
+ await changeARIAActiveDescendant(browser, "listbox", "roaming");
+ await moveARIAActiveDescendantID(browser, "roaming2", "roaming");
+ await changeARIAActiveDescendantInvalid(
+ browser,
+ "listbox",
+ "roaming3",
+ "roaming"
+ );
+ await moveARIAActiveDescendantID(browser, "roaming", "roaming3");
+ },
+ { topLevel: true, chrome: true }
+);
+
+addAccessibleTask(
+ LISTBOX_MARKUP,
+ async function (browser, docAcc) {
+ info("Test ariaActiveDescendantElement element reflection");
+ await basicListboxTest(browser, true);
+ },
+ { topLevel: true, chrome: true }
+);
+
+addAccessibleTask(
+ `
+<input id="activedesc_nondesc_input" aria-activedescendant="activedesc_nondesc_option">
+<div role="listbox">
+ <div role="option" id="activedesc_nondesc_option">option</div>
+</div>`,
+ async function (browser, docAcc) {
+ info("Test aria-activedescendant non-descendant");
+ await synthFocus(
+ browser,
+ "activedesc_nondesc_input",
+ "activedesc_nondesc_option"
+ );
+ },
+ { topLevel: true, chrome: true }
+);
+
+addAccessibleTask(
+ `
+<div id="shadow"></div>
+<script>
+ let host = document.getElementById("shadow");
+ let shadow = host.attachShadow({mode: "open"});
+ let listbox = document.createElement("div");
+ listbox.id = "shadowListbox";
+ listbox.setAttribute("role", "listbox");
+ listbox.setAttribute("tabindex", "0");
+ shadow.appendChild(listbox);
+ let item = document.createElement("div");
+ item.id = "shadowItem1";
+ item.setAttribute("role", "option");
+ listbox.appendChild(item);
+ listbox.setAttribute("aria-activedescendant", "shadowItem1");
+ item = document.createElement("div");
+ item.id = "shadowItem2";
+ item.setAttribute("role", "option");
+ listbox.appendChild(item);
+</script>`,
+ async function (browser, docAcc) {
+ info("Test aria-activedescendant in shadow root");
+ // We want to retrieve elements using their IDs inside the shadow root, so
+ // we define a custom get element by ID method that our utility functions
+ // above call into if it exists.
+ await invokeContentTask(browser, [], () => {
+ content.document._testGetElementById = id =>
+ content.document.getElementById("shadow").shadowRoot.getElementById(id);
+ });
+
+ await synthFocus(browser, "shadowListbox", "shadowItem1");
+ await changeARIAActiveDescendant(
+ browser,
+ "shadowListbox",
+ "shadowItem2",
+ "shadowItem1"
+ );
+ info("Do it again with element reflection");
+ await changeARIAActiveDescendant(
+ browser,
+ "shadowListbox",
+ "shadowItem1",
+ "shadowItem2",
+ true
+ );
+ },
+ { topLevel: true, chrome: true }
+);
+
+addAccessibleTask(
+ `
+<div id="comboboxWithHiddenList" tabindex="0" role="combobox" aria-owns="hiddenList">
+</div>
+<div id="hiddenList" hidden role="listbox">
+ <div id="hiddenListOption" role="option"></div>
+</div>`,
+ async function (browser, docAcc) {
+ info("Test simultaneous insertion, relocation and aria-activedescendant");
+ await synthFocus(
+ browser,
+ "comboboxWithHiddenList",
+ "comboboxWithHiddenList"
+ );
+
+ testStates(
+ findAccessibleChildByID(docAcc, "comboboxWithHiddenList"),
+ STATE_FOCUSED
+ );
+ let evtProm = Promise.all([
+ waitForEvent(EVENT_FOCUS, "hiddenListOption"),
+ waitForStateChange("hiddenListOption", EXT_STATE_ACTIVE, true, true),
+ ]);
+ await invokeContentTask(browser, [], () => {
+ info("hiddenList is owned, so unhiding causes insertion and relocation.");
+ (
+ content.document._testGetElementById || content.document.getElementById
+ ).bind(content.document)("hiddenList").hidden = false;
+ content.document
+ .getElementById("comboboxWithHiddenList")
+ .setAttribute("aria-activedescendant", "hiddenListOption");
+ });
+ await evtProm;
+ testStates(
+ findAccessibleChildByID(docAcc, "hiddenListOption"),
+ STATE_FOCUSED
+ );
+ },
+ { topLevel: true, chrome: true }
+);
+
+addAccessibleTask(
+ `
+<custom-listbox id="custom-listbox1">
+ <div role="listitem" id="l1_1"></div>
+ <div role="listitem" id="l1_2"></div>
+ <div role="listitem" id="l1_3"></div>
+</custom-listbox>
+
+<custom-listbox id="custom-listbox2" aria-activedescendant="l2_1">
+ <div role="listitem" id="l2_1"></div>
+ <div role="listitem" id="l2_2"></div>
+ <div role="listitem" id="l2_3"></div>
+</custom-listbox>
+
+<script>
+customElements.define("custom-listbox",
+ class extends HTMLElement {
+ constructor() {
+ super();
+ this.tabIndex = "0"
+ this._internals = this.attachInternals();
+ this._internals.role = "listbox";
+ this._internals.ariaActiveDescendantElement = this.lastElementChild;
+ }
+ get internals() {
+ return this._internals;
+ }
+ }
+);
+</script>`,
+ async function (browser, docAcc) {
+ await synthFocus(browser, "custom-listbox1", "l1_3");
+
+ let evtProm = Promise.all([
+ waitForEvent(EVENT_FOCUS, "l1_2"),
+ waitForStateChange("l1_3", EXT_STATE_ACTIVE, false, true),
+ waitForStateChange("l1_2", EXT_STATE_ACTIVE, true, true),
+ ]);
+
+ await invokeContentTask(browser, [], () => {
+ content.document.getElementById(
+ "custom-listbox1"
+ ).internals.ariaActiveDescendantElement =
+ content.document.getElementById("l1_2");
+ });
+
+ await evtProm;
+
+ evtProm = Promise.all([
+ waitForEvent(EVENT_FOCUS, "custom-listbox1"),
+ waitForStateChange("l1_2", EXT_STATE_ACTIVE, false, true),
+ ]);
+
+ await invokeContentTask(browser, [], () => {
+ content.document.getElementById(
+ "custom-listbox1"
+ ).internals.ariaActiveDescendantElement = null;
+ });
+
+ await evtProm;
+
+ await synthFocus(browser, "custom-listbox2", "l2_1");
+ await clearARIAActiveDescendant(browser, "custom-listbox2", "l2_1", "l2_3");
+ }
+);
diff --git a/accessible/tests/browser/e10s/browser_caching_attributes.js b/accessible/tests/browser/e10s/browser_caching_attributes.js
index 139015061f..7a1f90ec13 100644
--- a/accessible/tests/browser/e10s/browser_caching_attributes.js
+++ b/accessible/tests/browser/e10s/browser_caching_attributes.js
@@ -733,7 +733,7 @@ addAccessibleTask(
*/
addAccessibleTask(
`<div id="popover" popover>popover</div>`,
- async function testIspopup(browser, docAcc) {
+ async function testIspopup(browser) {
info("Showing popover");
let shown = waitForEvent(EVENT_SHOW, "popover");
await invokeContentTask(browser, [], () => {
diff --git a/accessible/tests/browser/e10s/browser_caching_large_update.js b/accessible/tests/browser/e10s/browser_caching_large_update.js
index ccf8a86921..9a36ac7326 100644
--- a/accessible/tests/browser/e10s/browser_caching_large_update.js
+++ b/accessible/tests/browser/e10s/browser_caching_large_update.js
@@ -8,59 +8,56 @@
* Test a large update which adds many thousands of Accessibles with a
* lot of content in each.
*/
-addAccessibleTask(
- `<main id="main" hidden></main>`,
- async function (browser, docAcc) {
- let shown = waitForEvent(EVENT_SHOW, "main");
- await invokeContentTask(browser, [], () => {
- // Make a long string.
- let text = "";
- for (let i = 0; i < 100; ++i) {
- text += "a";
- }
- // Create lots of nodes which include the long string.
- const contMain = content.document.getElementById("main");
- // 15000 children of main.
- for (let w = 0; w < 15000; ++w) {
- // Each of those goes 9 deep.
- let parent = contMain;
- for (let d = 0; d < 10; ++d) {
- const div = content.document.createElement("div");
- div.setAttribute("aria-label", `${w} ${d} ${text}`);
- parent.append(div);
- parent = div;
- }
- }
- contMain.hidden = false;
- });
- const main = (await shown).accessible;
- is(main.childCount, 15000, "main has correct number of children");
-
- // We don't want to output passes for every check, since that would output
- // hundreds of thousands of lines, which slows the test to a crawl. Instead,
- // output any failures and keep track of overall success/failure.
- let treeOk = true;
- function check(val, msg) {
- if (!val) {
- ok(false, msg);
- treeOk = false;
- }
+addAccessibleTask(`<main id="main" hidden></main>`, async function (browser) {
+ let shown = waitForEvent(EVENT_SHOW, "main");
+ await invokeContentTask(browser, [], () => {
+ // Make a long string.
+ let text = "";
+ for (let i = 0; i < 100; ++i) {
+ text += "a";
}
-
- info("Checking tree");
+ // Create lots of nodes which include the long string.
+ const contMain = content.document.getElementById("main");
+ // 15000 children of main.
for (let w = 0; w < 15000; ++w) {
- let acc = main.getChildAt(w);
- let parent = main;
+ // Each of those goes 9 deep.
+ let parent = contMain;
for (let d = 0; d < 10; ++d) {
- check(acc, `Got child ${w} depth ${d}`);
- const name = `${w} ${d}`;
- check(acc.name.startsWith(name + " "), `${name}: correct name`);
- check(acc.parent == parent, `${name}: correct parent`);
- parent = acc;
- acc = acc.firstChild;
+ const div = content.document.createElement("div");
+ div.setAttribute("aria-label", `${w} ${d} ${text}`);
+ parent.append(div);
+ parent = div;
}
}
- // check() sets treeOk to false for any failure.
- ok(treeOk, "Tree is correct");
+ contMain.hidden = false;
+ });
+ const main = (await shown).accessible;
+ is(main.childCount, 15000, "main has correct number of children");
+
+ // We don't want to output passes for every check, since that would output
+ // hundreds of thousands of lines, which slows the test to a crawl. Instead,
+ // output any failures and keep track of overall success/failure.
+ let treeOk = true;
+ function check(val, msg) {
+ if (!val) {
+ ok(false, msg);
+ treeOk = false;
+ }
+ }
+
+ info("Checking tree");
+ for (let w = 0; w < 15000; ++w) {
+ let acc = main.getChildAt(w);
+ let parent = main;
+ for (let d = 0; d < 10; ++d) {
+ check(acc, `Got child ${w} depth ${d}`);
+ const name = `${w} ${d}`;
+ check(acc.name.startsWith(name + " "), `${name}: correct name`);
+ check(acc.parent == parent, `${name}: correct parent`);
+ parent = acc;
+ acc = acc.firstChild;
+ }
}
-);
+ // check() sets treeOk to false for any failure.
+ ok(treeOk, "Tree is correct");
+});
diff --git a/accessible/tests/browser/e10s/browser_caching_name.js b/accessible/tests/browser/e10s/browser_caching_name.js
index 55f506b85a..383d268d7d 100644
--- a/accessible/tests/browser/e10s/browser_caching_name.js
+++ b/accessible/tests/browser/e10s/browser_caching_name.js
@@ -477,7 +477,7 @@ markupTests.forEach(({ id, ruleset, markup, expected }) =>
markup,
async function (browser, accDoc) {
const observer = {
- observe(subject, topic, data) {
+ observe(subject) {
const event = subject.QueryInterface(nsIAccessibleEvent);
console.log(eventToString(event));
},
diff --git a/accessible/tests/browser/e10s/browser_caching_relations_002.js b/accessible/tests/browser/e10s/browser_caching_relations_002.js
index 072656eb5e..61d92ba4ac 100644
--- a/accessible/tests/browser/e10s/browser_caching_relations_002.js
+++ b/accessible/tests/browser/e10s/browser_caching_relations_002.js
@@ -293,7 +293,7 @@ addAccessibleTask(
);
/**
- * Test details relations on popovers and their invokers.
+ * Test details relations for the popovertarget content attribute.
*/
addAccessibleTask(
`
@@ -304,7 +304,7 @@ addAccessibleTask(
<div id="popover" popover>popover</div>
<div id="details">details</div>
`,
- async function testPopover(browser, docAcc) {
+ async function testPopoverContent(browser, docAcc) {
// The popover is hidden, so nothing should be referring to it.
const hide = findAccessibleChildByID(docAcc, "hide");
await testCachedRelation(hide, RELATION_DETAILS, []);
@@ -330,7 +330,7 @@ addAccessibleTask(
await testCachedRelation(toggleSibling, RELATION_DETAILS, []);
await testCachedRelation(popover, RELATION_DETAILS_FOR, toggle1);
- info("Setting toggle2 popovertargetaction");
+ info("Setting toggle2 popovertarget");
await invokeSetAttribute(browser, "toggle2", "popovertarget", "popover");
await testCachedRelation(toggle2, RELATION_DETAILS, popover);
await testCachedRelation(popover, RELATION_DETAILS_FOR, [toggle1, toggle2]);
@@ -364,3 +364,106 @@ addAccessibleTask(
},
{ chrome: false, topLevel: true }
);
+
+/**
+ * Test details relations for the popoverTargetElement WebIDL attribute.
+ */
+addAccessibleTask(
+ `
+<button id="toggle1">toggle1</button>
+<button id="toggle2">toggle2</button>
+between
+<div id="popover1" popover>popover1</div>
+<button id="toggle3">toggle3</button>
+<div id="shadowHost"><template shadowrootmode="open">
+ <button id="toggle4">toggle4</button>
+ between
+ <div id="popover2" popover>popover2</div>
+ <button id="toggle5">toggle5</button>
+</template></div>
+<script>
+ const toggle1 = document.getElementById("toggle1");
+ const popover1 = document.getElementById("popover1");
+ toggle1.popoverTargetElement = popover1;
+ const toggle3 = document.getElementById("toggle3");
+ const shadow = document.getElementById("shadowHost").shadowRoot;
+ const toggle4 = shadow.getElementById("toggle4");
+ const popover2 = shadow.getElementById("popover2");
+ toggle3.popoverTargetElement = popover2;
+ toggle4.popoverTargetElement = popover2;
+ const toggle5 = shadow.getElementById("toggle5");
+ toggle5.popoverTargetElement = popover1;
+</script>
+ `,
+ async function testPopoverIdl(browser, docAcc) {
+ // No popover is showing, so there shouldn't be any details relations.
+ const toggle1 = findAccessibleChildByID(docAcc, "toggle1");
+ await testCachedRelation(toggle1, RELATION_DETAILS, []);
+ const toggle2 = findAccessibleChildByID(docAcc, "toggle2");
+ await testCachedRelation(toggle2, RELATION_DETAILS, []);
+ const toggle3 = findAccessibleChildByID(docAcc, "toggle3");
+ await testCachedRelation(toggle3, RELATION_DETAILS, []);
+ const toggle4 = findAccessibleChildByID(docAcc, "toggle4");
+ await testCachedRelation(toggle4, RELATION_DETAILS, []);
+ const toggle5 = findAccessibleChildByID(docAcc, "toggle5");
+ await testCachedRelation(toggle5, RELATION_DETAILS, []);
+
+ info("Showing popover1");
+ let shown = waitForEvent(EVENT_SHOW, "popover1");
+ toggle1.doAction(0);
+ const popover1 = (await shown).accessible;
+ await testCachedRelation(toggle1, RELATION_DETAILS, popover1);
+ // toggle5 is inside the shadow DOM and popover1 is outside, so the target
+ // is valid.
+ await testCachedRelation(toggle5, RELATION_DETAILS, popover1);
+ await testCachedRelation(popover1, RELATION_DETAILS_FOR, [
+ toggle1,
+ toggle5,
+ ]);
+ info("Setting toggle2's popover target to popover1");
+ await invokeContentTask(browser, [], () => {
+ const toggle2Dom = content.document.getElementById("toggle2");
+ const popover1Dom = content.document.getElementById("popover1");
+ toggle2Dom.popoverTargetElement = popover1Dom;
+ });
+ await testCachedRelation(toggle2, RELATION_DETAILS, popover1);
+ await testCachedRelation(popover1, RELATION_DETAILS_FOR, [
+ toggle1,
+ toggle2,
+ toggle5,
+ ]);
+ info("Clearing toggle2's popover target");
+ await invokeContentTask(browser, [], () => {
+ const toggle2Dom = content.document.getElementById("toggle2");
+ toggle2Dom.popoverTargetElement = null;
+ });
+ await testCachedRelation(toggle2, RELATION_DETAILS, []);
+ await testCachedRelation(popover1, RELATION_DETAILS_FOR, [
+ toggle1,
+ toggle5,
+ ]);
+ info("Hiding popover1");
+ let hidden = waitForEvent(EVENT_HIDE, popover1);
+ toggle1.doAction(0);
+ await hidden;
+ await testCachedRelation(toggle1, RELATION_DETAILS, []);
+ await testCachedRelation(toggle2, RELATION_DETAILS, []);
+ await testCachedRelation(toggle5, RELATION_DETAILS, []);
+
+ info("Showing popover2");
+ shown = waitForEvent(EVENT_SHOW, "popover2");
+ toggle4.doAction(0);
+ const popover2 = (await shown).accessible;
+ // toggle4 is in the same shadow DOM as popover2.
+ await testCachedRelation(toggle4, RELATION_DETAILS, popover2);
+ // toggle3 is outside popover2's shadow DOM, so the target isn't valid.
+ await testCachedRelation(toggle3, RELATION_DETAILS, []);
+ await testCachedRelation(popover2, RELATION_DETAILS_FOR, [toggle4]);
+ info("Hiding popover2");
+ hidden = waitForEvent(EVENT_HIDE, popover2);
+ toggle4.doAction(0);
+ await hidden;
+ await testCachedRelation(toggle4, RELATION_DETAILS, []);
+ },
+ { chrome: true, topLevel: true }
+);
diff --git a/accessible/tests/browser/e10s/browser_caching_states.js b/accessible/tests/browser/e10s/browser_caching_states.js
index 37f8c46966..7292228f25 100644
--- a/accessible/tests/browser/e10s/browser_caching_states.js
+++ b/accessible/tests/browser/e10s/browser_caching_states.js
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
+requestLongerTimeout(2);
/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
@@ -484,7 +485,7 @@ addAccessibleTask(
);
/**
- * Test caching of the expanded state for popover target element.
+ * Test caching of the expanded state for the popovertarget content attribute.
*/
addAccessibleTask(
`
@@ -550,3 +551,157 @@ addAccessibleTask(
},
{ chrome: true, topLevel: true, remoteIframe: true }
);
+
+/**
+ * Test caching of the expanded state for the popoverTargetElement WebIDL
+ * attribute.
+ */
+addAccessibleTask(
+ `
+<button id="toggle1">toggle</button>
+<div id="popover1" popover>popover1</div>
+<button id="toggle2">toggle2</button>
+<button id="toggle3">toggle3</button>
+<div id="shadowHost"><template shadowrootmode="open">
+ <button id="toggle4">toggle4</button>
+ <div id="popover2" popover>popover2</div>
+ <button id="toggle5">toggle5</button>
+</template></div>
+<script>
+ const toggle1 = document.getElementById("toggle1");
+ const popover1 = document.getElementById("popover1");
+ toggle1.popoverTargetElement = popover1;
+ const toggle3 = document.getElementById("toggle3");
+ const shadow = document.getElementById("shadowHost").shadowRoot;
+ const toggle4 = shadow.getElementById("toggle4");
+ const popover2 = shadow.getElementById("popover2");
+ toggle3.popoverTargetElement = popover2;
+ toggle4.popoverTargetElement = popover2;
+ const toggle5 = shadow.getElementById("toggle5");
+ toggle5.popoverTargetElement = popover1;
+</script>
+ `,
+ async function (browser, docAcc) {
+ const toggle1 = findAccessibleChildByID(docAcc, "toggle1");
+ // toggle1's popover target is set and connected to the document.
+ testStates(toggle1, STATE_COLLAPSED);
+
+ const toggle2 = findAccessibleChildByID(docAcc, "toggle2");
+ // toggle2's popover target isn't set yet.
+ testStates(
+ toggle2,
+ 0,
+ 0,
+ STATE_EXPANDED | STATE_COLLAPSED,
+ EXT_STATE_EXPANDABLE
+ );
+ info("Setting toggle2's popoverTargetElement");
+ let changed = waitForStateChange(toggle2, EXT_STATE_EXPANDABLE, true, true);
+ await invokeContentTask(browser, [], () => {
+ const toggle2Dom = content.document.getElementById("toggle2");
+ const popover1 = content.document.getElementById("popover1");
+ toggle2Dom.popoverTargetElement = popover1;
+ });
+ await changed;
+ testStates(toggle2, STATE_COLLAPSED);
+
+ const toggle5 = findAccessibleChildByID(docAcc, "toggle5");
+ // toggle5 is inside the shadow DOM and popover1 is outside, so the target
+ // is valid.
+ testStates(toggle5, STATE_COLLAPSED);
+
+ // Changes to the popover should fire events on all invokers.
+ const changeEvents = [
+ [EVENT_STATE_CHANGE, toggle1],
+ [EVENT_STATE_CHANGE, toggle2],
+ [EVENT_STATE_CHANGE, toggle5],
+ ];
+ info("Showing popover1");
+ changed = waitForEvents(changeEvents);
+ toggle1.doAction(0);
+ await changed;
+ testStates(toggle1, STATE_EXPANDED);
+ testStates(toggle2, STATE_EXPANDED);
+
+ info("Hiding popover1");
+ changed = waitForEvents(changeEvents);
+ toggle1.doAction(0);
+ await changed;
+ testStates(toggle1, STATE_COLLAPSED);
+ testStates(toggle2, STATE_COLLAPSED);
+
+ info("Clearing toggle1's popover target");
+ changed = waitForStateChange(toggle1, EXT_STATE_EXPANDABLE, false, true);
+ await invokeContentTask(browser, [], () => {
+ const toggle1Dom = content.document.getElementById("toggle1");
+ toggle1Dom.popoverTargetElement = null;
+ });
+ await changed;
+ testStates(
+ toggle1,
+ 0,
+ 0,
+ STATE_EXPANDED | STATE_COLLAPSED,
+ EXT_STATE_EXPANDABLE
+ );
+
+ info("Setting toggle2's popover target to a disconnected node");
+ changed = waitForStateChange(toggle2, EXT_STATE_EXPANDABLE, false, true);
+ await invokeContentTask(browser, [], () => {
+ const toggle2Dom = content.document.getElementById("toggle2");
+ const popover3 = content.document.createElement("div");
+ popover3.popover = "auto";
+ popover3.textContent = "popover3";
+ // We don't append popover3 anywhere, so it is disconnected.
+ toggle2Dom.popoverTargetElement = popover3;
+ });
+ await changed;
+ testStates(
+ toggle2,
+ 0,
+ 0,
+ STATE_EXPANDED | STATE_COLLAPSED,
+ EXT_STATE_EXPANDABLE
+ );
+
+ const toggle3 = findAccessibleChildByID(docAcc, "toggle3");
+ // toggle3 is outside popover2's shadow DOM, so the target isn't valid.
+ testStates(
+ toggle3,
+ 0,
+ 0,
+ STATE_EXPANDED | STATE_COLLAPSED,
+ EXT_STATE_EXPANDABLE
+ );
+ const toggle4 = findAccessibleChildByID(docAcc, "toggle4");
+ // toggle4 is in the same shadow DOM as popover2.
+ testStates(toggle4, STATE_COLLAPSED);
+ },
+ { chrome: true, topLevel: true }
+);
+
+/**
+ * Test the mixed state of indeterminate HTML checkboxes.
+ */
+addAccessibleTask(
+ `<input type="checkbox" id="checkbox">`,
+ async function testHTMLCheckboxMixed(browser, docAcc) {
+ const checkbox = findAccessibleChildByID(docAcc, "checkbox");
+ testStates(checkbox, 0, 0, STATE_MIXED);
+ info("Setting indeterminate on checkbox");
+ let changed = waitForStateChange(checkbox, STATE_MIXED, true);
+ await invokeContentTask(browser, [], () => {
+ content.document.getElementById("checkbox").indeterminate = true;
+ });
+ await changed;
+ testStates(checkbox, STATE_MIXED);
+ info("Clearing indeterminate on checkbox");
+ changed = waitForStateChange(checkbox, STATE_MIXED, false);
+ await invokeContentTask(browser, [], () => {
+ content.document.getElementById("checkbox").indeterminate = false;
+ });
+ await changed;
+ testStates(checkbox, 0, 0, STATE_MIXED);
+ },
+ { chrome: true, topLevel: true, iframe: true, remoteIframe: true }
+);
diff --git a/accessible/tests/browser/e10s/browser_caching_table.js b/accessible/tests/browser/e10s/browser_caching_table.js
index 9c8bcb9616..0329e6411b 100644
--- a/accessible/tests/browser/e10s/browser_caching_table.js
+++ b/accessible/tests/browser/e10s/browser_caching_table.js
@@ -482,7 +482,7 @@ addAccessibleTask(
*/
addAccessibleTask(
`<table><tr id="tr"></tr></table>`,
- async function (browser, docAcc) {
+ async function (browser) {
let reordered = waitForEvent(EVENT_REORDER, "tr");
await invokeContentTask(browser, [], () => {
const iframe = content.document.createElement("iframe");
diff --git a/accessible/tests/browser/e10s/browser_caching_text_bounds.js b/accessible/tests/browser/e10s/browser_caching_text_bounds.js
index 3e37bf7490..486e28df53 100644
--- a/accessible/tests/browser/e10s/browser_caching_text_bounds.js
+++ b/accessible/tests/browser/e10s/browser_caching_text_bounds.js
@@ -138,9 +138,13 @@ async function testLineWithNonRenderedSpace(docAcc, browser, id, length) {
const w = {};
const h = {};
acc.getCharacterExtents(offset, x, y, w, h, COORDTYPE_SCREEN_RELATIVE);
- ok(x.value > prevX, `${id}: offset ${offset} x is larger (${x.value})`);
+ Assert.greater(
+ x.value,
+ prevX,
+ `${id}: offset ${offset} x is larger (${x.value})`
+ );
prevX = x.value;
- ok(w.value > 0, `${id}: offset ${offset} width > 0`);
+ Assert.greater(w.value, 0, `${id}: offset ${offset} width > 0`);
}
}
@@ -566,7 +570,11 @@ c</textarea>
{},
COORDTYPE_SCREEN_RELATIVE
);
- ok(newY.value < oldY.value, "y coordinate smaller after scrolling down");
+ Assert.less(
+ newY.value,
+ oldY.value,
+ "y coordinate smaller after scrolling down"
+ );
},
{ chrome: true, topLevel: true, iframe: !true }
);
diff --git a/accessible/tests/browser/e10s/browser_file_input.js b/accessible/tests/browser/e10s/browser_file_input.js
index 238e48740e..4c68e8e6da 100644
--- a/accessible/tests/browser/e10s/browser_file_input.js
+++ b/accessible/tests/browser/e10s/browser_file_input.js
@@ -34,7 +34,7 @@ addAccessibleTask(
function chooseFile(id) {
return invokeContentTask(browser, [id], contentId => {
const MockFilePicker = content.SpecialPowers.MockFilePicker;
- MockFilePicker.init(content);
+ MockFilePicker.init(content.browsingContext);
MockFilePicker.useBlobFile();
MockFilePicker.returnValue = MockFilePicker.returnOK;
const input = content.document.getElementById(contentId);
diff --git a/accessible/tests/browser/e10s/browser_treeupdate_select_dropdown.js b/accessible/tests/browser/e10s/browser_treeupdate_select_dropdown.js
index a82fc4c04d..8ccbe58751 100644
--- a/accessible/tests/browser/e10s/browser_treeupdate_select_dropdown.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_select_dropdown.js
@@ -24,7 +24,7 @@ const snippet = `
addAccessibleTask(
snippet,
- async function (browser, accDoc) {
+ async function (browser) {
await invokeFocus(browser, "select");
// Expand the select. A dropdown item should get focus.
// Note that the dropdown is rendered in the parent process.
diff --git a/accessible/tests/browser/events/browser_test_docload.js b/accessible/tests/browser/events/browser_test_docload.js
index 78ac77fd8c..12076b3002 100644
--- a/accessible/tests/browser/events/browser_test_docload.js
+++ b/accessible/tests/browser/events/browser_test_docload.js
@@ -30,7 +30,7 @@ function urlChecker(url) {
};
}
-async function runTests(browser, accDoc) {
+async function runTests(browser) {
let onLoadEvents = waitForEvents({
expected: [
[EVENT_REORDER, getAccessible(browser)],
diff --git a/accessible/tests/browser/events/browser_test_focus_browserui.js b/accessible/tests/browser/events/browser_test_focus_browserui.js
index 969d336c74..2f67cb3681 100644
--- a/accessible/tests/browser/events/browser_test_focus_browserui.js
+++ b/accessible/tests/browser/events/browser_test_focus_browserui.js
@@ -11,7 +11,7 @@ loadScripts(
{ name: "role.js", dir: MOCHITESTS_DIR }
);
-async function runTests(browser, accDoc) {
+async function runTests(browser) {
await SpecialPowers.pushPrefEnv({
// If Fission is disabled, the pref is no-op.
set: [["fission.bfcacheInParent", true]],
diff --git a/accessible/tests/browser/events/browser_test_focus_dialog.js b/accessible/tests/browser/events/browser_test_focus_dialog.js
index 71485a678d..03a1b82dc1 100644
--- a/accessible/tests/browser/events/browser_test_focus_dialog.js
+++ b/accessible/tests/browser/events/browser_test_focus_dialog.js
@@ -11,7 +11,7 @@ loadScripts(
{ name: "role.js", dir: MOCHITESTS_DIR }
);
-async function runTests(browser, accDoc) {
+async function runTests(browser) {
let onFocus = waitForEvent(EVENT_FOCUS, "button");
await SpecialPowers.spawn(browser, [], () => {
content.document.getElementById("button").focus();
diff --git a/accessible/tests/browser/events/browser_test_focus_urlbar.js b/accessible/tests/browser/events/browser_test_focus_urlbar.js
index 68b2b07f3c..647b837e9f 100644
--- a/accessible/tests/browser/events/browser_test_focus_urlbar.js
+++ b/accessible/tests/browser/events/browser_test_focus_urlbar.js
@@ -68,10 +68,10 @@ class TipTestProvider extends UrlbarProvider {
get type() {
return UrlbarUtils.PROVIDER_TYPE.PROFILE;
}
- isActive(context) {
+ isActive() {
return true;
}
- isRestricting(context) {
+ isRestricting() {
return true;
}
async startQuery(context, addCallback) {
diff --git a/accessible/tests/browser/events/browser_test_scrolling.js b/accessible/tests/browser/events/browser_test_scrolling.js
index 9678ee767b..d9425721bf 100644
--- a/accessible/tests/browser/events/browser_test_scrolling.js
+++ b/accessible/tests/browser/events/browser_test_scrolling.js
@@ -25,13 +25,15 @@ c</textarea>
});
let [scrollEvent1, scrollEndEvent1] = await onScrolling;
scrollEvent1.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEvent1.maxScrollY >= scrollEvent1.scrollY,
+ Assert.greaterOrEqual(
+ scrollEvent1.maxScrollY,
+ scrollEvent1.scrollY,
"scrollY is within max"
);
scrollEndEvent1.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEndEvent1.maxScrollY >= scrollEndEvent1.scrollY,
+ Assert.greaterOrEqual(
+ scrollEndEvent1.maxScrollY,
+ scrollEndEvent1.scrollY,
"scrollY is within max"
);
@@ -44,13 +46,15 @@ c</textarea>
});
let [scrollEvent2, scrollEndEvent2] = await onScrolling;
scrollEvent2.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEvent2.scrollY > scrollEvent1.scrollY,
+ Assert.greater(
+ scrollEvent2.scrollY,
+ scrollEvent1.scrollY,
`${scrollEvent2.scrollY} > ${scrollEvent1.scrollY}`
);
scrollEndEvent2.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEndEvent2.maxScrollY >= scrollEndEvent2.scrollY,
+ Assert.greaterOrEqual(
+ scrollEndEvent2.maxScrollY,
+ scrollEndEvent2.scrollY,
"scrollY is within max"
);
@@ -63,17 +67,20 @@ c</textarea>
});
let [scrollEvent3, scrollEndEvent3] = await onScrolling;
scrollEvent3.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEvent3.maxScrollX >= scrollEvent3.scrollX,
+ Assert.greaterOrEqual(
+ scrollEvent3.maxScrollX,
+ scrollEvent3.scrollX,
"scrollX is within max"
);
scrollEndEvent3.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEndEvent3.maxScrollX >= scrollEndEvent3.scrollX,
+ Assert.greaterOrEqual(
+ scrollEndEvent3.maxScrollX,
+ scrollEndEvent3.scrollX,
"scrollY is within max"
);
- ok(
- scrollEvent3.scrollX > scrollEvent2.scrollX,
+ Assert.greater(
+ scrollEvent3.scrollX,
+ scrollEvent2.scrollX,
`${scrollEvent3.scrollX} > ${scrollEvent2.scrollX}`
);
@@ -87,13 +94,15 @@ c</textarea>
});
let [scrollEvent4, scrollEndEvent4] = await onScrolling;
scrollEvent4.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEvent4.maxScrollY >= scrollEvent4.scrollY,
+ Assert.greaterOrEqual(
+ scrollEvent4.maxScrollY,
+ scrollEvent4.scrollY,
"scrollY is within max"
);
scrollEndEvent4.QueryInterface(nsIAccessibleScrollingEvent);
- ok(
- scrollEndEvent4.maxScrollY >= scrollEndEvent4.scrollY,
+ Assert.greaterOrEqual(
+ scrollEndEvent4.maxScrollY,
+ scrollEndEvent4.scrollY,
"scrollY is within max"
);
@@ -119,7 +128,7 @@ addAccessibleTask(
<p>b</p>
<p id="c">c</p>
`,
- async function (browser, accDoc) {
+ async function (browser) {
let onScrollingStart = waitForEvent(EVENT_SCROLLING_START, "c");
await SpecialPowers.spawn(browser, [], () => {
content.location.hash = "#c";
@@ -137,7 +146,7 @@ addAccessibleTask(
<h1 style="height: 300%;" id="inside-scrollable">test</h1>
</div>
`,
- async function (browser, accDoc) {
+ async function (browser) {
let onScrollingStart = waitForEvent(
EVENT_SCROLLING_START,
"inside-scrollable"
diff --git a/accessible/tests/browser/mac/browser_app.js b/accessible/tests/browser/mac/browser_app.js
index bedefae440..e7e18b5ddd 100644
--- a/accessible/tests/browser/mac/browser_app.js
+++ b/accessible/tests/browser/mac/browser_app.js
@@ -138,7 +138,7 @@ add_task(async () => {
gBrowser,
url: "about:license",
},
- async browser => {
+ async () => {
let root = await getMacAccessible(document);
let rootChildCount = () => root.getAttributeValue("AXChildren").length;
@@ -206,8 +206,10 @@ add_task(async () => {
is(rootChildCount(), baseRootChildCount + 1, "Root has another child");
// Close popup
+ let hide = waitForMacEvent("AXUIElementDestroyed");
EventUtils.synthesizeKey("KEY_Escape");
await BrowserTestUtils.waitForPopupEvent(identityPopup, "hidden");
+ await hide;
// We're back to the base child count
is(rootChildCount(), baseRootChildCount, "Root has the base child count");
@@ -225,7 +227,7 @@ add_task(async () => {
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
url: "http://example.com",
},
- async browser => {
+ async () => {
let input = await getMacAccessible("urlbar-input");
is(
input.getAttributeValue("AXValue"),
@@ -238,6 +240,38 @@ add_task(async () => {
});
/**
+ * Tests attributed text in nav bar has no invisible AXAttachments
+ */
+add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ url: "http://example.com",
+ },
+ async () => {
+ let root = await getMacAccessible(document);
+ let navBar = await getMacAccessible("nav-bar");
+ let elemRange = root.getParameterizedAttributeValue(
+ "AXTextMarkerRangeForUIElement",
+ navBar
+ );
+ let attributedString = root.getParameterizedAttributeValue(
+ "AXAttributedStringForTextMarkerRange",
+ elemRange
+ );
+ let attachmentRoles = attributedString.map(s =>
+ s.AXAttachment ? s.AXAttachment.getAttributeValue("AXRole") : null
+ );
+ ok(
+ !attachmentRoles.includes("AXMenu"),
+ "Collapsed menu should be embedded in attributed text"
+ );
+ }
+ );
+});
+
+/**
* Test context menu
*/
add_task(async () => {
diff --git a/accessible/tests/browser/mac/browser_bounds.js b/accessible/tests/browser/mac/browser_bounds.js
index 09343d7c9d..bc7939cfe0 100644
--- a/accessible/tests/browser/mac/browser_bounds.js
+++ b/accessible/tests/browser/mac/browser_bounds.js
@@ -21,22 +21,26 @@ addAccessibleTask(
// test them here instead of calling AXFrame directly.
const [helloWidth, helloHeight] = hello.getAttributeValue("AXSize");
const [worldWidth, worldHeight] = world.getAttributeValue("AXSize");
- ok(helloWidth > 0, "Hello has a positive width");
- ok(helloHeight > 0, "Hello has a positive height");
- ok(worldWidth > 0, "World has a positive width");
- ok(worldHeight > 0, "World has a positive height");
- ok(helloHeight < worldHeight, "Hello has a smaller height than world");
- ok(helloWidth < worldWidth, "Hello has a smaller width than world");
+ Assert.greater(helloWidth, 0, "Hello has a positive width");
+ Assert.greater(helloHeight, 0, "Hello has a positive height");
+ Assert.greater(worldWidth, 0, "World has a positive width");
+ Assert.greater(worldHeight, 0, "World has a positive height");
+ Assert.less(
+ helloHeight,
+ worldHeight,
+ "Hello has a smaller height than world"
+ );
+ Assert.less(helloWidth, worldWidth, "Hello has a smaller width than world");
// Note: these are mac screen coords, so our origin is bottom left
const [helloX, helloY] = hello.getAttributeValue("AXPosition");
const [worldX, worldY] = world.getAttributeValue("AXPosition");
- ok(helloX > 0, "Hello has a positive X");
- ok(helloY > 0, "Hello has a positive Y");
- ok(worldX > 0, "World has a positive X");
- ok(worldY > 0, "World has a positive Y");
- ok(helloY > worldY, "Hello has a larger Y than world");
- ok(helloX == worldX, "Hello and world have the same X");
+ Assert.greater(helloX, 0, "Hello has a positive X");
+ Assert.greater(helloY, 0, "Hello has a positive Y");
+ Assert.greater(worldX, 0, "World has a positive X");
+ Assert.greater(worldY, 0, "World has a positive Y");
+ Assert.greater(helloY, worldY, "Hello has a larger Y than world");
+ Assert.equal(helloX, worldX, "Hello and world have the same X");
}
);
@@ -57,21 +61,25 @@ addAccessibleTask(
// test them here instead of calling AXFrame directly.
const [helloWidth, helloHeight] = hello.getAttributeValue("AXSize");
const [worldWidth, worldHeight] = world.getAttributeValue("AXSize");
- ok(helloWidth > 0, "Hello has a positive width");
- ok(helloHeight > 0, "Hello has a positive height");
- ok(worldWidth > 0, "World has a positive width");
- ok(worldHeight > 0, "World has a positive height");
- ok(helloHeight < worldHeight, "Hello has a smaller height than world");
- ok(helloWidth < worldWidth, "Hello has a smaller width than world");
+ Assert.greater(helloWidth, 0, "Hello has a positive width");
+ Assert.greater(helloHeight, 0, "Hello has a positive height");
+ Assert.greater(worldWidth, 0, "World has a positive width");
+ Assert.greater(worldHeight, 0, "World has a positive height");
+ Assert.less(
+ helloHeight,
+ worldHeight,
+ "Hello has a smaller height than world"
+ );
+ Assert.less(helloWidth, worldWidth, "Hello has a smaller width than world");
// Note: these are mac screen coords, so our origin is bottom left
const [helloX, helloY] = hello.getAttributeValue("AXPosition");
const [worldX, worldY] = world.getAttributeValue("AXPosition");
- ok(helloX < 0, "Hello has a negative X");
- ok(helloY > 0, "Hello has a positive Y");
- ok(worldX < 0, "World has a negative X");
- ok(worldY > 0, "World has a positive Y");
- ok(helloY > worldY, "Hello has a larger Y than world");
- ok(helloX == worldX, "Hello and world have the same X");
+ Assert.less(helloX, 0, "Hello has a negative X");
+ Assert.greater(helloY, 0, "Hello has a positive Y");
+ Assert.less(worldX, 0, "World has a negative X");
+ Assert.greater(worldY, 0, "World has a positive Y");
+ Assert.greater(helloY, worldY, "Hello has a larger Y than world");
+ Assert.equal(helloX, worldX, "Hello and world have the same X");
}
);
diff --git a/accessible/tests/browser/mac/browser_live_regions.js b/accessible/tests/browser/mac/browser_live_regions.js
index 10a03120f8..aa07f003df 100644
--- a/accessible/tests/browser/mac/browser_live_regions.js
+++ b/accessible/tests/browser/mac/browser_live_regions.js
@@ -131,7 +131,7 @@ addAccessibleTask(
<button id="button" aria-label="Start"></button>
</div>
`,
- async (browser, accDoc) => {
+ async browser => {
let liveRegionChanged = waitForMacEvent("AXLiveRegionChanged", "live");
await SpecialPowers.spawn(browser, [], () => {
content.document.getElementById("time").textContent = "4:56pm";
diff --git a/accessible/tests/browser/mac/browser_menulist.js b/accessible/tests/browser/mac/browser_menulist.js
index b26a0be782..3b0fe8b210 100644
--- a/accessible/tests/browser/mac/browser_menulist.js
+++ b/accessible/tests/browser/mac/browser_menulist.js
@@ -74,7 +74,7 @@ addAccessibleTask(
"First menu item is selected"
);
// focus the second item, and verify it is selected
- event = waitForMacEvent("AXFocusedUIElementChanged", (iface, data) => {
+ event = waitForMacEvent("AXFocusedUIElementChanged", iface => {
try {
return iface.getAttributeValue("AXTitle") == "100%";
} catch (e) {
diff --git a/accessible/tests/browser/mac/browser_roles_elements.js b/accessible/tests/browser/mac/browser_roles_elements.js
index 791598fed6..b6049e7afd 100644
--- a/accessible/tests/browser/mac/browser_roles_elements.js
+++ b/accessible/tests/browser/mac/browser_roles_elements.js
@@ -47,6 +47,7 @@ addAccessibleTask(
<div id="complementary" role="complementary"></div>
<div id="contentinfo" role="contentinfo"></div>
<div id="form" role="form"></div>
+ <div id="form_label" aria-label="form" role="form"></div>
<div id="main" role="main"></div>
<div id="navigation" role="navigation"></div>
<div id="search" role="search"></div>
@@ -149,7 +150,8 @@ addAccessibleTask(
"AXLandmarkComplementary"
);
testRoleAndSubRole(accDoc, "contentinfo", null, "AXLandmarkContentInfo");
- testRoleAndSubRole(accDoc, "form", null, "AXLandmarkForm");
+ testRoleAndSubRole(accDoc, "form", null, "AXApplicationGroup");
+ testRoleAndSubRole(accDoc, "form_label", null, "AXLandmarkForm");
testRoleAndSubRole(accDoc, "main", null, "AXLandmarkMain");
testRoleAndSubRole(accDoc, "navigation", null, "AXLandmarkNavigation");
testRoleAndSubRole(accDoc, "search", null, "AXLandmarkSearch");
diff --git a/accessible/tests/browser/mac/browser_rotor.js b/accessible/tests/browser/mac/browser_rotor.js
index 3f13506757..87ac40592d 100644
--- a/accessible/tests/browser/mac/browser_rotor.js
+++ b/accessible/tests/browser/mac/browser_rotor.js
@@ -269,7 +269,7 @@ addAccessibleTask(
"AXUIElementCountForSearchPredicate",
NSDictionary(searchPred)
);
- is(4, tableCount, "Found four tables");
+ is(tableCount, 3, "Found three tables");
const tables = webArea.getParameterizedAttributeValue(
"AXUIElementsForSearchPredicate",
@@ -278,7 +278,6 @@ addAccessibleTask(
const shapes = getNativeInterface(accDoc, "shapes");
const food = getNativeInterface(accDoc, "food");
const ariaTable = getNativeInterface(accDoc, "ariaTable");
- const grid = getNativeInterface(accDoc, "grid");
is(
shapes.getAttributeValue("AXColumnCount"),
@@ -295,11 +294,6 @@ addAccessibleTask(
tables[2].getAttributeValue("AXColumnCount"),
"Found correct third table"
);
- is(
- grid.getAttributeValue("AXColumnCount"),
- tables[3].getAttributeValue("AXColumnCount"),
- "Found correct fourth table"
- );
}
);
diff --git a/accessible/tests/browser/mac/browser_text_leaf.js b/accessible/tests/browser/mac/browser_text_leaf.js
index 21deed6212..c65e8c6ebe 100644
--- a/accessible/tests/browser/mac/browser_text_leaf.js
+++ b/accessible/tests/browser/mac/browser_text_leaf.js
@@ -77,7 +77,11 @@ addAccessibleTask(
NSRange(3, 8)
);
- ok(smallBounds.size[0] < largeBounds.size[0], "longer range is wider");
+ Assert.less(
+ smallBounds.size[0],
+ largeBounds.size[0],
+ "longer range is wider"
+ );
},
{ chrome: true, iframe: true, remoteIframe: true }
);
diff --git a/accessible/tests/browser/mac/browser_text_selection.js b/accessible/tests/browser/mac/browser_text_selection.js
index a914adba8e..7e2145631c 100644
--- a/accessible/tests/browser/mac/browser_text_selection.js
+++ b/accessible/tests/browser/mac/browser_text_selection.js
@@ -82,7 +82,7 @@ addAccessibleTask(
Hello <a href="#" id="link">World</a>,
I <a href="#" style="user-select: none;" id="unselectable_link">love</a>
<button id="button">you</button></p>`,
- async (browser, accDoc) => {
+ async browser => {
// Set up an AXSelectedTextChanged listener here. It will get resolved
// on the first non-root event it encounters, so if we test its data at the end
// of this test it will show us the first text-selectable object that was focused,
diff --git a/accessible/tests/browser/mac/browser_toggle_radio_check.js b/accessible/tests/browser/mac/browser_toggle_radio_check.js
index 1695d73b0d..f9094ac3d7 100644
--- a/accessible/tests/browser/mac/browser_toggle_radio_check.js
+++ b/accessible/tests/browser/mac/browser_toggle_radio_check.js
@@ -128,7 +128,7 @@ addAccessibleTask(
// Changing from checked to mixed fires two events. Make sure we wait until
// the second so we're asserting based on the latest state.
- evt = waitForMacEvent("AXValueChanged", (iface, data) => {
+ evt = waitForMacEvent("AXValueChanged", iface => {
return (
iface.getAttributeValue("AXDOMIdentifier") == "checkbox" &&
iface.getAttributeValue("AXValue") == 2
diff --git a/accessible/tests/browser/mac/browser_webarea.js b/accessible/tests/browser/mac/browser_webarea.js
index ac6122de14..4872c58845 100644
--- a/accessible/tests/browser/mac/browser_webarea.js
+++ b/accessible/tests/browser/mac/browser_webarea.js
@@ -8,8 +8,8 @@
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
// Test web area role and AXLoadComplete event
-addAccessibleTask(``, async (browser, accDoc) => {
- let evt = waitForMacEvent("AXLoadComplete", (iface, data) => {
+addAccessibleTask(``, async browser => {
+ let evt = waitForMacEvent("AXLoadComplete", iface => {
return iface.getAttributeValue("AXDescription") == "webarea test";
});
await SpecialPowers.spawn(browser, [], () => {
@@ -29,16 +29,16 @@ addAccessibleTask(``, async (browser, accDoc) => {
});
// Test iframe web area role and AXLayoutComplete event
-addAccessibleTask(`<title>webarea test</title>`, async (browser, accDoc) => {
+addAccessibleTask(`<title>webarea test</title>`, async browser => {
// If the iframe loads before the top level document finishes loading, we'll
// get both an AXLayoutComplete event for the iframe and an AXLoadComplete
// event for the document. Otherwise, if the iframe loads after the
// document, we'll get one AXLoadComplete event.
let eventPromise = Promise.race([
- waitForMacEvent("AXLayoutComplete", (iface, data) => {
+ waitForMacEvent("AXLayoutComplete", iface => {
return iface.getAttributeValue("AXDescription") == "iframe document";
}),
- waitForMacEvent("AXLoadComplete", (iface, data) => {
+ waitForMacEvent("AXLoadComplete", iface => {
return iface.getAttributeValue("AXDescription") == "webarea test";
}),
]);
diff --git a/accessible/tests/browser/scroll/browser_test_scroll_bounds.js b/accessible/tests/browser/scroll/browser_test_scroll_bounds.js
index 31de002cda..33a99266db 100644
--- a/accessible/tests/browser/scroll/browser_test_scroll_bounds.js
+++ b/accessible/tests/browser/scroll/browser_test_scroll_bounds.js
@@ -238,7 +238,11 @@ addAccessibleTask(
newTopBounds[0],
"x of non-fixed element remains accurate."
);
- ok(newTopBounds[1] < 0, "y coordinate shows item scrolled off page");
+ Assert.less(
+ newTopBounds[1],
+ 0,
+ "y coordinate shows item scrolled off page"
+ );
is(
origTopBounds[2],
newTopBounds[2],
@@ -254,7 +258,11 @@ addAccessibleTask(
newDBounds[0],
"x of non-fixed container element remains accurate."
);
- ok(newDBounds[1] < 0, "y coordinate shows container scrolled off page");
+ Assert.less(
+ newDBounds[1],
+ 0,
+ "y coordinate shows container scrolled off page"
+ );
// Removing the position styling on this acc causes it to be bound by
// its parent's bounding box, which alters its width as a block element.
// We don't particularly care about width in this test, so skip it.
@@ -481,7 +489,7 @@ addAccessibleTask(
newBounds[0],
`x coord of non-sticky element remains accurate.`
);
- ok(newBounds[1] < 0, "y coordinate shows item scrolled off page");
+ Assert.less(newBounds[1], 0, "y coordinate shows item scrolled off page");
// Removing the position styling on this acc causes it to be bound by
// its parent's bounding box, which alters its width as a block element.
diff --git a/accessible/tests/browser/scroll/browser_test_scroll_substring.js b/accessible/tests/browser/scroll/browser_test_scroll_substring.js
index e8426d00ca..031b8a5124 100644
--- a/accessible/tests/browser/scroll/browser_test_scroll_substring.js
+++ b/accessible/tests/browser/scroll/browser_test_scroll_substring.js
@@ -45,8 +45,9 @@ The only thing I found in the fridge was a dead dove in a bag.
text.getCharacterExtents(7, {}, objY, {}, {}, COORDTYPE_SCREEN_RELATIVE);
return objY.value;
};
- ok(
- containerHeight < getCharY(),
+ Assert.less(
+ containerHeight,
+ getCharY(),
"Character is outside of container bounds"
);
text.scrollSubstringTo(7, 8, SCROLL_TYPE_TOP_EDGE);
diff --git a/accessible/tests/browser/selectable/browser_test_select.js b/accessible/tests/browser/selectable/browser_test_select.js
index f86a371d81..6a51fd4f3b 100644
--- a/accessible/tests/browser/selectable/browser_test_select.js
+++ b/accessible/tests/browser/selectable/browser_test_select.js
@@ -313,7 +313,7 @@ addAccessibleTask(
</select>
</form>
`,
- async function (browser, docAcc) {
+ async function (browser) {
let selected = waitForEvent(EVENT_SELECTION_WITHIN, "select");
await invokeContentTask(browser, [], () => {
const form = content.document.getElementById("form");
diff --git a/accessible/tests/browser/shared-head.js b/accessible/tests/browser/shared-head.js
index fe87a77765..c238a5a7a0 100644
--- a/accessible/tests/browser/shared-head.js
+++ b/accessible/tests/browser/shared-head.js
@@ -830,7 +830,7 @@ const CACHE_WAIT_TIMEOUT_MS = 5000;
* be used to record a pass or fail in the test.
*/
function untilCacheCondition(conditionFunc, argsFunc) {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
let args = argsFunc();
if (conditionFunc(...args)) {
resolve(args);
@@ -838,7 +838,7 @@ function untilCacheCondition(conditionFunc, argsFunc) {
}
let cacheObserver = {
- observe(subject) {
+ observe() {
args = argsFunc();
if (conditionFunc(...args)) {
clearTimeout(this.timer);
@@ -945,7 +945,7 @@ function runPython(code) {
"ws://mochi.test:8888/browser/accessible/tests/browser/python_runner"
);
if (gPythonSocket.readyState != WebSocket.OPEN) {
- gPythonSocket.onopen = evt => {
+ gPythonSocket.onopen = () => {
gPythonSocket.send(code);
gPythonSocket.onopen = null;
};
diff --git a/accessible/tests/browser/text/browser_text_paragraph_boundary.js b/accessible/tests/browser/text/browser_text_paragraph_boundary.js
index 04e64520e8..b206829398 100644
--- a/accessible/tests/browser/text/browser_text_paragraph_boundary.js
+++ b/accessible/tests/browser/text/browser_text_paragraph_boundary.js
@@ -8,7 +8,7 @@
// boundary on an Accessible which has remote ProxyAccessible descendants.
addAccessibleTask(
`test`,
- async function testParagraphBoundaryWithRemoteDescendants(browser, accDoc) {
+ async function testParagraphBoundaryWithRemoteDescendants() {
const root = getRootAccessible(document).QueryInterface(
Ci.nsIAccessibleText
);
diff --git a/accessible/tests/browser/text/head.js b/accessible/tests/browser/text/head.js
index fa4b095892..72195ddbb0 100644
--- a/accessible/tests/browser/text/head.js
+++ b/accessible/tests/browser/text/head.js
@@ -142,7 +142,7 @@ function testBoundarySequence(
// Editable text
async function waitForCopy(browser) {
- await BrowserTestUtils.waitForContentEvent(browser, "copy", false, evt => {
+ await BrowserTestUtils.waitForContentEvent(browser, "copy", false, () => {
return true;
});
diff --git a/accessible/tests/browser/tree/browser_aria_owns.js b/accessible/tests/browser/tree/browser_aria_owns.js
index 0ca55ed357..904597cc66 100644
--- a/accessible/tests/browser/tree/browser_aria_owns.js
+++ b/accessible/tests/browser/tree/browser_aria_owns.js
@@ -176,7 +176,7 @@ addAccessibleTask(
addAccessibleTask(
`
<select id="container" aria-owns="boom" multiple></select>`,
- async function (browser, accDoc) {
+ async function () {
ok(true, "Did not crash");
}
);
diff --git a/accessible/tests/browser/tree/browser_browser_element.js b/accessible/tests/browser/tree/browser_browser_element.js
index 82be24d93c..d6ece6676e 100644
--- a/accessible/tests/browser/tree/browser_browser_element.js
+++ b/accessible/tests/browser/tree/browser_browser_element.js
@@ -8,7 +8,7 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
// Test that the tree is correct for browser elements containing remote
// documents.
-addAccessibleTask(`test`, async function (browser, docAcc) {
+addAccessibleTask(`test`, async function (browser) {
// testAccessibleTree also verifies childCount, indexInParent and parent.
testAccessibleTree(browser, {
INTERNAL_FRAME: [{ DOCUMENT: [{ TEXT_LEAF: [] }] }],
diff --git a/accessible/tests/browser/tree/browser_lazy_tabs.js b/accessible/tests/browser/tree/browser_lazy_tabs.js
index f7aa9bdeb2..46e10d0bac 100644
--- a/accessible/tests/browser/tree/browser_lazy_tabs.js
+++ b/accessible/tests/browser/tree/browser_lazy_tabs.js
@@ -5,7 +5,7 @@
// Test that lazy background tabs aren't unintentionally loaded when building
// the a11y tree (bug 1700708).
-addAccessibleTask(``, async function (browser, accDoc) {
+addAccessibleTask(``, async function () {
await SpecialPowers.pushPrefEnv({
set: [["browser.sessionstore.restore_on_demand", true]],
});
diff --git a/accessible/tests/browser/tree/browser_test_nsIAccessibleDocument_URL.js b/accessible/tests/browser/tree/browser_test_nsIAccessibleDocument_URL.js
index 623f2640f0..e6b55d0fd3 100644
--- a/accessible/tests/browser/tree/browser_test_nsIAccessibleDocument_URL.js
+++ b/accessible/tests/browser/tree/browser_test_nsIAccessibleDocument_URL.js
@@ -25,7 +25,7 @@ async function promiseEventDocumentLoadComplete(expectedURL) {
add_task(async function testInDataURI() {
const kURL = "data:text/html,Some text";
const waitForDocumentLoadComplete = promiseEventDocumentLoadComplete("");
- await BrowserTestUtils.withNewTab(kURL, async browser => {
+ await BrowserTestUtils.withNewTab(kURL, async () => {
is(
(await waitForDocumentLoadComplete).URL,
"",
@@ -44,7 +44,7 @@ add_task(async function testInHTTPSURIContainingPrivateThings() {
"https://example.com/browser/toolkit/content/tests/browser/file_empty.html?query=some#ref";
const waitForDocumentLoadComplete =
promiseEventDocumentLoadComplete(kURLWithoutUserPass);
- await BrowserTestUtils.withNewTab(kURL, async browser => {
+ await BrowserTestUtils.withNewTab(kURL, async () => {
is(
(await waitForDocumentLoadComplete).URL,
kURLWithoutUserPass,
diff --git a/accessible/tests/browser/windows/a11y_setup.py b/accessible/tests/browser/windows/a11y_setup.py
index d6dc19f0fb..726eea07a4 100644
--- a/accessible/tests/browser/windows/a11y_setup.py
+++ b/accessible/tests/browser/windows/a11y_setup.py
@@ -9,19 +9,28 @@ import ctypes
import os
from ctypes import POINTER, byref
from ctypes.wintypes import BOOL, HWND, LPARAM, POINT # noqa: F401
+from dataclasses import dataclass
+import comtypes.automation
import comtypes.client
import psutil
from comtypes import COMError, IServiceProvider
+CHILDID_SELF = 0
+COWAIT_DEFAULT = 0
+EVENT_OBJECT_FOCUS = 0x8005
+GA_ROOT = 2
+NAVRELATION_EMBEDS = 0x1009
+OBJID_CLIENT = -4
+RPC_S_CALLPENDING = -2147417835
+WINEVENT_OUTOFCONTEXT = 0
+WM_CLOSE = 0x0010
+
user32 = ctypes.windll.user32
oleacc = ctypes.oledll.oleacc
oleaccMod = comtypes.client.GetModule("oleacc.dll")
IAccessible = oleaccMod.IAccessible
del oleaccMod
-OBJID_CLIENT = -4
-CHILDID_SELF = 0
-NAVRELATION_EMBEDS = 0x1009
# This is the path if running locally.
ia2Tlb = os.path.join(
os.getcwd(),
@@ -65,6 +74,13 @@ def AccessibleObjectFromWindow(hwnd, objectID=OBJID_CLIENT):
return p
+def getWindowClass(hwnd):
+ MAX_CHARS = 257
+ buffer = ctypes.create_unicode_buffer(MAX_CHARS)
+ user32.GetClassNameW(hwnd, buffer, MAX_CHARS)
+ return buffer.value
+
+
def getFirefoxHwnd():
"""Search all top level windows for the Firefox instance being
tested.
@@ -78,9 +94,7 @@ def getFirefoxHwnd():
@ctypes.WINFUNCTYPE(BOOL, HWND, LPARAM)
def callback(hwnd, lParam):
- name = ctypes.create_unicode_buffer(100)
- user32.GetClassNameW(hwnd, name, 100)
- if name.value != "MozillaWindowClass":
+ if getWindowClass(hwnd) != "MozillaWindowClass":
return True
pid = ctypes.wintypes.DWORD()
user32.GetWindowThreadProcessId(hwnd, byref(pid))
@@ -127,6 +141,106 @@ def findIa2ByDomId(root, id):
return descendant
+@dataclass
+class WinEvent:
+ event: int
+ hwnd: int
+ objectId: int
+ childId: int
+
+ def getIa2(self):
+ acc = ctypes.POINTER(IAccessible)()
+ child = comtypes.automation.VARIANT()
+ ctypes.oledll.oleacc.AccessibleObjectFromEvent(
+ self.hwnd,
+ self.objectId,
+ self.childId,
+ ctypes.byref(acc),
+ ctypes.byref(child),
+ )
+ if child.value != CHILDID_SELF:
+ # This isn't an IAccessible2 object.
+ return None
+ return toIa2(acc)
+
+
+class WaitForWinEvent:
+ """Wait for a win event, usually for IAccessible2.
+ This should be used as follows:
+ 1. Create an instance to wait for the desired event.
+ 2. Perform the action that should fire the event.
+ 3. Call wait() on the instance you created in 1) to wait for the event.
+ """
+
+ def __init__(self, eventId, match):
+ """event is the event id to wait for.
+ match is either None to match any object, an str containing the DOM id
+ of the desired object, or a function taking a WinEvent which should
+ return True if this is the requested event.
+ """
+ self._matched = None
+ # A kernel event used to signal when we get the desired event.
+ self._signal = ctypes.windll.kernel32.CreateEventW(None, True, False, None)
+
+ # We define this as a nested function because it has to be a static
+ # function, but we need a reference to self.
+ @ctypes.WINFUNCTYPE(
+ None,
+ ctypes.wintypes.HANDLE,
+ ctypes.wintypes.DWORD,
+ ctypes.wintypes.HWND,
+ ctypes.wintypes.LONG,
+ ctypes.wintypes.LONG,
+ ctypes.wintypes.DWORD,
+ ctypes.wintypes.DWORD,
+ )
+ def winEventProc(hook, eventId, hwnd, objectId, childId, thread, time):
+ event = WinEvent(eventId, hwnd, objectId, childId)
+ if isinstance(match, str):
+ try:
+ ia2 = event.getIa2()
+ if f"id:{match};" in ia2.attributes:
+ self._matched = event
+ except (comtypes.COMError, TypeError):
+ pass
+ elif callable(match):
+ try:
+ if match(event):
+ self._matched = event
+ except Exception as e:
+ self._matched = e
+ if self._matched:
+ ctypes.windll.kernel32.SetEvent(self._signal)
+
+ self._hook = user32.SetWinEventHook(
+ eventId, eventId, None, winEventProc, 0, 0, WINEVENT_OUTOFCONTEXT
+ )
+ # Hold a reference to winEventProc so it doesn't get destroyed.
+ self._proc = winEventProc
+
+ def wait(self):
+ """Wait for and return the desired WinEvent."""
+ # Pump Windows messages until we get the desired event, which will be
+ # signalled using a kernel event.
+ handles = (ctypes.c_void_p * 1)(self._signal)
+ index = ctypes.wintypes.DWORD()
+ TIMEOUT = 10000
+ try:
+ ctypes.oledll.ole32.CoWaitForMultipleHandles(
+ COWAIT_DEFAULT, TIMEOUT, 1, handles, ctypes.byref(index)
+ )
+ except WindowsError as e:
+ if e.winerror == RPC_S_CALLPENDING:
+ raise TimeoutError("Timeout before desired event received")
+ raise
+ finally:
+ user32.UnhookWinEvent(self._hook)
+ self._proc = None
+ if isinstance(self._matched, Exception):
+ raise self._matched from self._matched
+ return self._matched
+
+
def getDocUia():
"""Get the IUIAutomationElement for the document being tested."""
# We start with IAccessible2 because there's no efficient way to
diff --git a/accessible/tests/browser/windows/ia2/browser.toml b/accessible/tests/browser/windows/ia2/browser.toml
index d72b5f8a2d..d6226b73cc 100644
--- a/accessible/tests/browser/windows/ia2/browser.toml
+++ b/accessible/tests/browser/windows/ia2/browser.toml
@@ -6,4 +6,6 @@ skip-if = [
]
support-files = ["head.js"]
+["browser_osPicker.js"]
+
["browser_role.js"]
diff --git a/accessible/tests/browser/windows/ia2/browser_osPicker.js b/accessible/tests/browser/windows/ia2/browser_osPicker.js
new file mode 100644
index 0000000000..b14f2d0a5f
--- /dev/null
+++ b/accessible/tests/browser/windows/ia2/browser_osPicker.js
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+addAccessibleTask(
+ `<input id="file" type="file">`,
+ async function (browser, docAcc) {
+ info("Focusing file input");
+ await runPython(`
+ global focused
+ focused = WaitForWinEvent(EVENT_OBJECT_FOCUS, "file")
+ `);
+ const file = findAccessibleChildByID(docAcc, "file");
+ file.takeFocus();
+ await runPython(`
+ focused.wait()
+ `);
+ ok(true, "file input got focus");
+ info("Opening file picker");
+ await runPython(`
+ global focused
+ focused = WaitForWinEvent(
+ EVENT_OBJECT_FOCUS,
+ lambda evt: getWindowClass(evt.hwnd) == "Edit"
+ )
+ `);
+ file.doAction(0);
+ await runPython(`
+ global event
+ event = focused.wait()
+ `);
+ ok(true, "Picker got focus");
+ info("Dismissing picker");
+ await runPython(`
+ # If the picker is dismissed too quickly, it seems to re-enable the root
+ # window before we do. This sleep isn't ideal, but it's more likely to
+ # reproduce the case that our root window gets focus before it is enabled.
+ # See bug 1883568 for further details.
+ import time
+ time.sleep(1)
+ focused = WaitForWinEvent(EVENT_OBJECT_FOCUS, "file")
+ # Sending key presses to the picker is unreliable, so use WM_CLOSE.
+ pickerRoot = user32.GetAncestor(event.hwnd, GA_ROOT)
+ user32.SendMessageW(pickerRoot, WM_CLOSE, 0, 0)
+ focused.wait()
+ `);
+ ok(true, "file input got focus");
+ }
+);
diff --git a/accessible/tests/browser/windows/ia2/browser_role.js b/accessible/tests/browser/windows/ia2/browser_role.js
index 08e44c280f..89b560ab49 100644
--- a/accessible/tests/browser/windows/ia2/browser_role.js
+++ b/accessible/tests/browser/windows/ia2/browser_role.js
@@ -12,7 +12,7 @@ addAccessibleTask(
`
<p id="p">p</p>
`,
- async function (browser, docAcc) {
+ async function () {
let role = await runPython(`
global doc
doc = getDocIa2()
diff --git a/accessible/tests/browser/windows/uia/browser.toml b/accessible/tests/browser/windows/uia/browser.toml
index f7974d69c7..d1513c1822 100644
--- a/accessible/tests/browser/windows/uia/browser.toml
+++ b/accessible/tests/browser/windows/uia/browser.toml
@@ -9,3 +9,5 @@ support-files = ["head.js"]
["browser_controlType.js"]
["browser_elementFromPoint.js"]
+
+["browser_tree.js"]
diff --git a/accessible/tests/browser/windows/uia/browser_controlType.js b/accessible/tests/browser/windows/uia/browser_controlType.js
index 16db892581..3bb994f437 100644
--- a/accessible/tests/browser/windows/uia/browser_controlType.js
+++ b/accessible/tests/browser/windows/uia/browser_controlType.js
@@ -9,11 +9,11 @@ const UIA_ButtonControlTypeId = 50000;
const UIA_DocumentControlTypeId = 50030;
/* eslint-enable camelcase */
-addAccessibleTask(
+addUiaTask(
`
<button id="button">button</button>
`,
- async function (browser, docAcc) {
+ async function () {
let controlType = await runPython(`
global doc
doc = getDocUia()
diff --git a/accessible/tests/browser/windows/uia/browser_elementFromPoint.js b/accessible/tests/browser/windows/uia/browser_elementFromPoint.js
index e2fda4ab30..acf6fe91c7 100644
--- a/accessible/tests/browser/windows/uia/browser_elementFromPoint.js
+++ b/accessible/tests/browser/windows/uia/browser_elementFromPoint.js
@@ -4,12 +4,12 @@
"use strict";
-addAccessibleTask(
+addUiaTask(
`
<button id="button">button</p>
<a id="a" href="#">a</a>
`,
- async function (browser, docAcc) {
+ async function () {
ok(
await runPython(`
global doc
diff --git a/accessible/tests/browser/windows/uia/browser_tree.js b/accessible/tests/browser/windows/uia/browser_tree.js
new file mode 100644
index 0000000000..778609bedb
--- /dev/null
+++ b/accessible/tests/browser/windows/uia/browser_tree.js
@@ -0,0 +1,104 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+async function testIsControl(pyVar, isControl) {
+ const result = await runPython(`bool(${pyVar}.CurrentIsControlElement)`);
+ if (isControl) {
+ ok(result, `${pyVar} is a control element`);
+ } else {
+ ok(!result, `${pyVar} isn't a control element`);
+ }
+}
+
+/**
+ * Define a global Python variable and assign it to a given Python expression.
+ */
+function definePyVar(varName, expression) {
+ return runPython(`
+ global ${varName}
+ ${varName} = ${expression}
+ `);
+}
+
+/**
+ * Get the UIA element with the given id and assign it to a global Python
+ * variable using the id as the variable name.
+ */
+function assignPyVarToUiaWithId(id) {
+ return definePyVar(id, `findUiaByDomId(doc, "${id}")`);
+}
+
+addUiaTask(
+ `
+<p id="p">paragraph</p>
+<div id="div">div</div>
+<!-- The spans are because the UIA -> IA2 proxy seems to remove a single text
+ leaf child from even the raw tree.
+ -->
+<a id="link" href="#">link<span> </span>></a>
+<h1 id="h1">h1<span> </span></h1>
+<h1 id="h1WithDiv"><div>h1 with div<span> </span></div></h1>
+<input id="range" type="range">
+<div onclick=";" id="clickable">clickable</div>
+<div id="editable" contenteditable>editable</div>
+<table id="table"><tr><th>th</th></tr></table>
+ `,
+ async function (browser, docAcc) {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("p");
+ await testIsControl("p", false);
+ await definePyVar(
+ "pTextLeaf",
+ `uiaClient.RawViewWalker.GetFirstChildElement(p)`
+ );
+ await testIsControl("pTextLeaf", true);
+ await assignPyVarToUiaWithId("div");
+ await testIsControl("div", false);
+ await definePyVar(
+ "divTextLeaf",
+ `uiaClient.RawViewWalker.GetFirstChildElement(div)`
+ );
+ await testIsControl("divTextLeaf", true);
+ await assignPyVarToUiaWithId("link");
+ await testIsControl("link", true);
+ await assignPyVarToUiaWithId("range");
+ await testIsControl("range", true);
+ await assignPyVarToUiaWithId("editable");
+ await testIsControl("editable", true);
+ await assignPyVarToUiaWithId("table");
+ await testIsControl("table", true);
+ if (!gIsUiaEnabled) {
+ // The remaining tests are broken with the UIA -> IA2 proxy.
+ return;
+ }
+ await definePyVar(
+ "linkTextLeaf",
+ `uiaClient.RawViewWalker.GetFirstChildElement(link)`
+ );
+ await testIsControl("linkTextLeaf", false);
+ await assignPyVarToUiaWithId("h1");
+ await testIsControl("h1", true);
+ await definePyVar(
+ "h1TextLeaf",
+ `uiaClient.RawViewWalker.GetFirstChildElement(h1)`
+ );
+ await testIsControl("h1TextLeaf", false);
+ await assignPyVarToUiaWithId("h1WithDiv");
+ await testIsControl("h1WithDiv", true);
+ // h1WithDiv's text leaf is its grandchild.
+ await definePyVar(
+ "h1WithDivTextLeaf",
+ `uiaClient.RawViewWalker.GetFirstChildElement(
+ uiaClient.RawViewWalker.GetFirstChildElement(
+ h1WithDiv
+ )
+ )`
+ );
+ await testIsControl("h1WithDivTextLeaf", false);
+ await assignPyVarToUiaWithId("clickable");
+ await testIsControl("clickable", true);
+ }
+);
diff --git a/accessible/tests/browser/windows/uia/head.js b/accessible/tests/browser/windows/uia/head.js
index afc50984bd..e659354c7c 100644
--- a/accessible/tests/browser/windows/uia/head.js
+++ b/accessible/tests/browser/windows/uia/head.js
@@ -4,6 +4,8 @@
"use strict";
+/* exported gIsUiaEnabled, addUiaTask */
+
// Load the shared-head file first.
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
@@ -16,3 +18,38 @@ loadScripts(
{ name: "common.js", dir: MOCHITESTS_DIR },
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
);
+
+let gIsUiaEnabled = false;
+
+/**
+ * This is like addAccessibleTask, but takes two additional boolean options:
+ * - uiaEnabled: Whether to run a variation of this test with Gecko UIA enabled.
+ * - uiaDisabled: Whether to run a variation of this test with UIA disabled. In
+ * this case, UIA will rely entirely on the IA2 -> UIA proxy.
+ * If both are set, the test will be run twice with different configurations.
+ * You can determine which variant is currently running using the gIsUiaEnabled
+ * variable. This is useful for conditional tests; e.g. if Gecko UIA supports
+ * something that the IA2 -> UIA proxy doesn't support.
+ */
+function addUiaTask(doc, task, options = {}) {
+ const { uiaEnabled = true, uiaDisabled = true } = options;
+
+ function addTask(shouldEnable) {
+ async function uiaTask(browser, docAcc, topDocAcc) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["accessibility.uia.enable", shouldEnable]],
+ });
+ gIsUiaEnabled = shouldEnable;
+ info(shouldEnable ? "Gecko UIA enabled" : "Gecko UIA disabled");
+ await task(browser, docAcc, topDocAcc);
+ }
+ addAccessibleTask(doc, uiaTask, options);
+ }
+
+ if (uiaEnabled) {
+ addTask(true);
+ }
+ if (uiaDisabled) {
+ addTask(false);
+ }
+}