/* 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"; requestLongerTimeout(2); /* import-globals-from ../../mochitest/role.js */ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR }); /* import-globals-from ../../mochitest/states.js */ loadScripts({ name: "states.js", dir: MOCHITESTS_DIR }); /** * Test MEMBER_OF relation caching on HTML radio buttons */ addAccessibleTask( ` I have no name
I also have no name
I have a name
I have a different name
I have an already used name and am in a different part of the tree I have a different name but am in the same group
`, async function (browser, accDoc) { const r1 = findAccessibleChildByID(accDoc, "r1"); const r2 = findAccessibleChildByID(accDoc, "r2"); const r3 = findAccessibleChildByID(accDoc, "r3"); const r4 = findAccessibleChildByID(accDoc, "r4"); const r5 = findAccessibleChildByID(accDoc, "r5"); const r6 = findAccessibleChildByID(accDoc, "r6"); await testCachedRelation(r1, RELATION_MEMBER_OF, []); await testCachedRelation(r2, RELATION_MEMBER_OF, []); await testCachedRelation(r3, RELATION_MEMBER_OF, [r3, r5]); await testCachedRelation(r4, RELATION_MEMBER_OF, r4); await testCachedRelation(r5, RELATION_MEMBER_OF, [r3, r5]); await testCachedRelation(r6, RELATION_MEMBER_OF, r6); await invokeContentTask(browser, [], () => { content.document.getElementById("r5").name = "a"; }); await testCachedRelation(r3, RELATION_MEMBER_OF, r3); await testCachedRelation(r4, RELATION_MEMBER_OF, [r5, r4]); await testCachedRelation(r5, RELATION_MEMBER_OF, [r5, r4]); }, { chrome: true, iframe: true, remoteIframe: true } ); /* * Test MEMBER_OF relation caching on aria radio buttons */ addAccessibleTask( `


`, async function (browser, accDoc) { const r1 = findAccessibleChildByID(accDoc, "r1"); const r2 = findAccessibleChildByID(accDoc, "r2"); let r3 = findAccessibleChildByID(accDoc, "r3"); await testCachedRelation(r1, RELATION_MEMBER_OF, []); await testCachedRelation(r2, RELATION_MEMBER_OF, [r2, r3]); await testCachedRelation(r3, RELATION_MEMBER_OF, [r2, r3]); const r = waitForEvent(EVENT_INNER_REORDER, "fs"); await invokeContentTask(browser, [], () => { let innerRadio = content.document.getElementById("r3"); content.document.body.appendChild(innerRadio); }); await r; r3 = findAccessibleChildByID(accDoc, "r3"); await testCachedRelation(r1, RELATION_MEMBER_OF, []); await testCachedRelation(r2, RELATION_MEMBER_OF, r2); await testCachedRelation(r3, RELATION_MEMBER_OF, []); }, { chrome: true, iframe: true, remoteIframe: true, } ); /* * Test mutation of LABEL relations via DOM ID reuse. */ addAccessibleTask( `
before
`, async function (browser, accDoc) { let label = findAccessibleChildByID(accDoc, "label"); const input = findAccessibleChildByID(accDoc, "input"); await testCachedRelation(label, RELATION_LABEL_FOR, input); await testCachedRelation(input, RELATION_LABELLED_BY, label); const r = waitForEvent(EVENT_REORDER, accDoc); await invokeContentTask(browser, [], () => { content.document.getElementById("label").remove(); let l = content.document.createElement("div"); l.id = "label"; l.textContent = "after"; content.document.body.insertBefore( l, content.document.getElementById("input") ); }); await r; label = findAccessibleChildByID(accDoc, "label"); await testCachedRelation(label, RELATION_LABEL_FOR, input); await testCachedRelation(input, RELATION_LABELLED_BY, label); }, { chrome: true, iframe: true, remoteIframe: true, } ); /* * Test LINKS_TO relation caching an anchor with multiple hashes */ addAccessibleTask( ` Origin
Destination`, async function (browser, accDoc) { const link = findAccessibleChildByID(accDoc, "link"); const anchor = findAccessibleChildByID(accDoc, "anchor"); await testCachedRelation(link, RELATION_LINKS_TO, anchor); }, { chrome: true, // IA2 doesn't have a LINKS_TO relation and Windows non-cached // RemoteAccessible uses IA2, so we can't run these tests in this case. topLevel: true, iframe: true, remoteIframe: true, } ); /* * Test mutation of LABEL relations via accessible shutdown. */ addAccessibleTask( ` `, async function (browser, accDoc) { const label = findAccessibleChildByID(accDoc, "l"); const select = findAccessibleChildByID(accDoc, "s"); const input = findAccessibleChildByID(accDoc, "d"); await testCachedRelation(label, RELATION_LABEL_FOR, select); await testCachedRelation(select, RELATION_LABELLED_BY, label); await testCachedRelation(input, RELATION_LABELLED_BY, []); await untilCacheOk(() => { if (!browser.isRemoteBrowser) { return true; } try { // We should get an acc ID back from this, but we don't have a way of // verifying its correctness -- it should be the ID of the select. return label.cache.getStringProperty("for"); } catch (e) { ok(false, "Exception thrown while trying to read from the cache"); return false; } }, "Label for relation exists"); const r = waitForEvent(EVENT_INNER_REORDER, "l"); await invokeContentTask(browser, [], () => { content.document.getElementById("s").remove(); }); await r; await untilCacheOk(() => { if (!browser.isRemoteBrowser) { return true; } try { label.cache.getStringProperty("for"); } catch (e) { // This property should no longer exist in the cache, so we should // get an exception if we try to fetch it. return true; } return false; }, "Label for relation exists"); await invokeContentTask(browser, [], () => { const l = content.document.getElementById("l"); l.htmlFor = "d"; }); await testCachedRelation(label, RELATION_LABEL_FOR, input); await testCachedRelation(input, RELATION_LABELLED_BY, label); }, { chrome: true, iframe: true, remoteIframe: true, topLevel: true, } ); /** * Test label relations on HTML figure/figcaption. */ addAccessibleTask( `
before
caption1
after
caption2
label
`, async function (browser, docAcc) { const figure1 = findAccessibleChildByID(docAcc, "figure1"); let caption1 = findAccessibleChildByID(docAcc, "caption1"); await testCachedRelation(figure1, RELATION_LABELLED_BY, caption1); await testCachedRelation(caption1, RELATION_LABEL_FOR, figure1); info("Hiding caption1"); let mutated = waitForEvent(EVENT_HIDE, caption1); await invokeContentTask(browser, [], () => { content.document.getElementById("caption1").hidden = true; }); await mutated; await testCachedRelation(figure1, RELATION_LABELLED_BY, []); info("Showing caption1"); mutated = waitForEvent(EVENT_SHOW, "caption1"); await invokeContentTask(browser, [], () => { content.document.getElementById("caption1").hidden = false; }); caption1 = (await mutated).accessible; await testCachedRelation(figure1, RELATION_LABELLED_BY, caption1); await testCachedRelation(caption1, RELATION_LABEL_FOR, figure1); const figure2 = findAccessibleChildByID(docAcc, "figure2"); const caption2 = findAccessibleChildByID(docAcc, "caption2"); const label = findAccessibleChildByID(docAcc, "label"); await testCachedRelation(figure2, RELATION_LABELLED_BY, [label, caption2]); await testCachedRelation(caption2, RELATION_LABEL_FOR, figure2); await testCachedRelation(label, RELATION_LABEL_FOR, figure2); }, { chrome: true, topLevel: true } ); /** * Test aria-owns morphs to controls relationship when container is combobox. */ addAccessibleTask( `
`, async (browser, accDoc) => { const combobox = findAccessibleChildByID(accDoc, "box"); const listbox = findAccessibleChildByID(accDoc, "listbox"); testStates(combobox, 0, EXT_STATE_EDITABLE, 0, 0); is(combobox.childCount, 0, "combobox has no children"); await testCachedRelation(combobox, RELATION_CONTROLLER_FOR, [listbox]); await testCachedRelation(listbox, RELATION_CONTROLLED_BY, [combobox]); let expectedEvents = Promise.all([ waitForStateChange(combobox, EXT_STATE_EDITABLE, false, true), waitForEvent(EVENT_REORDER, accDoc), ]); await invokeContentTask(browser, [], () => { content.document.getElementById("box").contentEditable = false; }); await expectedEvents; await testCachedRelation(combobox, RELATION_CONTROLLER_FOR, []); await testCachedRelation(listbox, RELATION_CONTROLLED_BY, []); is(combobox.childCount, 1, "combobox has listbox"); } ); /* * Test relocated child preserves relation. */ addAccessibleTask( `
World
`, async function testRelocationRelation(browser, docAcc) { const btn = findAccessibleChildByID(docAcc, "btn"); const relocated = findAccessibleChildByID(docAcc, "relocated"); await testCachedRelation(btn, RELATION_LABELLED_BY, relocated); await testCachedRelation(relocated, RELATION_LABEL_FOR, btn); }, { chrome: true, topLevel: true } ); /** * Test table caption. */ addAccessibleTask( `
caption
a
`, async function testTableCaption(browser, docAcc) { const table = findAccessibleChildByID(docAcc, "table"); const caption = findAccessibleChildByID(docAcc, "caption"); await testCachedRelation(table, RELATION_LABELLED_BY, caption); await testCachedRelation(caption, RELATION_LABEL_FOR, table); }, { chrome: true, topLevel: true } ); /** * Test elements that are not label by spec do not get LABEL relations */ addAccessibleTask( `
`, async function testLabelOnDiv(browser, docAcc) { const btn = findAccessibleChildByID(docAcc, "btn"); const label = findAccessibleChildByID(docAcc, "label"); await testCachedRelation(btn, RELATION_LABELLED_BY, []); await testCachedRelation(label, RELATION_LABEL_FOR, []); }, { chrome: true, topLevel: true } );