summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser/e10s
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
commitfbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch)
tree4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /accessible/tests/browser/e10s
parentReleasing progress-linux version 124.0.1-1~progress7.99u1. (diff)
downloadfirefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz
firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible/tests/browser/e10s')
-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
11 files changed, 814 insertions, 63 deletions
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.