diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:14:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:14:29 +0000 |
commit | fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch) | |
tree | 4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /accessible/tests/browser/e10s | |
parent | Releasing progress-linux version 124.0.1-1~progress7.99u1. (diff) | |
download | firefox-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')
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. |