/* 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/name.js */
/* import-globals-from ../../mochitest/attributes.js */
loadScripts(
{ name: "name.js", dir: MOCHITESTS_DIR },
{ name: "attributes.js", dir: MOCHITESTS_DIR }
);
/**
* Test caching of the document title.
*/
addAccessibleTask(
``,
async function (browser, docAcc) {
let nameChanged = waitForEvent(EVENT_NAME_CHANGE, docAcc);
await invokeContentTask(browser, [], () => {
content.document.title = "new title";
});
await nameChanged;
testName(docAcc, "new title");
},
{ chrome: true, topLevel: true, iframe: true, remoteIframe: true }
);
/**
* Test that the name is updated when the content of a hidden aria-labelledby
* subtree changes.
*/
addAccessibleTask(
`
a
`,
async function (browser, docAcc) {
const button = findAccessibleChildByID(docAcc, "button");
testName(button, "a");
info("Changing label textContent");
let nameChanged = waitForEvent(EVENT_NAME_CHANGE, button);
await invokeContentTask(browser, [], () => {
content.document.getElementById("label").textContent = "c";
});
await nameChanged;
testName(button, "c");
info("Change label text node's data");
nameChanged = waitForEvent(EVENT_NAME_CHANGE, button);
await invokeContentTask(browser, [], () => {
content.document.getElementById("label").firstChild.data = "d";
});
await nameChanged;
testName(button, "d");
info("Prepending text node to label");
nameChanged = waitForEvent(EVENT_NAME_CHANGE, button);
await invokeContentTask(browser, [], () => {
content.document
.getElementById("label")
.prepend(content.document.createTextNode("b"));
});
await nameChanged;
testName(button, "bd");
},
{ chrome: true, topLevel: true, iframe: true, remoteIframe: true }
);
/**
* Test that the name does not include aria-actions targets of itself.
*/
addAccessibleTask(
`
Title
`,
async function testAriaActionInSubtree(browser, docAcc) {
const tab = findAccessibleChildByID(docAcc, "tab");
testName(tab, "Title");
let nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
invokeSetAttribute(browser, "tab", "aria-actions", "pin");
await nameChanged;
testName(tab, "Title Close");
nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
invokeSetAttribute(browser, "pin", "id", "broken-pin");
await nameChanged;
testName(tab, "Title Close Pin");
nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
invokeSetAttribute(browser, "tab", "aria-actions", "close pin");
await nameChanged;
testName(tab, "Title Pin");
nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
invokeSetAttribute(browser, "broken-pin", "id", "pin");
await nameChanged;
testName(tab, "Title");
},
{ chrome: true, topLevel: true }
);
/**
* Test abbr name change notification
*/
addAccessibleTask(
`JSON
YAML`,
async function testAbbrName(browser, docAcc) {
const abbr = findAccessibleChildByID(docAcc, "abbr");
testName(abbr, "JavaScript Object Notation");
let nameChanged = waitForEvent(EVENT_NAME_CHANGE, abbr);
invokeSetAttribute(browser, "abbr", "title", "Jason's Other Nettle");
await nameChanged;
testName(abbr, "Jason's Other Nettle");
nameChanged = waitForEvent(EVENT_NAME_CHANGE, abbr);
invokeSetAttribute(browser, "abbr", "title");
await nameChanged;
testName(abbr, null);
const labelledAbbr = findAccessibleChildByID(docAcc, "labelled-abbr");
testName(labelledAbbr, "YML");
let events = waitForEvents({
expected: [[EVENT_DESCRIPTION_CHANGE, labelledAbbr]],
unexpected: [[EVENT_NAME_CHANGE, labelledAbbr]],
});
invokeSetAttribute(
browser,
"labelled-abbr",
"title",
"Your Another Marker Lye"
);
await events;
testName(labelledAbbr, "YML");
is(labelledAbbr.description, "Your Another Marker Lye");
events = waitForEvents([
[EVENT_NAME_CHANGE, labelledAbbr],
// Bug 1997464 - When losing ARIA name, we lose the description that is used
// now for the name.
// [EVENT_DESCRIPTION_CHANGE, labelledAbbr],
]);
invokeSetAttribute(browser, "labelled-abbr", "aria-label");
await events;
testName(labelledAbbr, "Your Another Marker Lye");
},
{ chrome: true, topLevel: true }
);
/**
* Test consistent doc name for remote and local docs.
*/
addAccessibleTask(
``,
async function testDocName(browser, docAcc) {
const iframe = findAccessibleChildByID(docAcc, "iframe");
info("Setting iframe src");
// This iframe won't finish loading. Thus, it will get the stale state and
// won't fire a document load complete event. We use the reorder event on
// the iframe to know when the document has been created.
let reordered = waitForEvent(EVENT_REORDER, iframe);
await invokeContentTask(browser, [], () => {
content.document.getElementById("iframe").src =
`data:text/html,hey`;
});
let iframeDoc = (await reordered).accessible.firstChild;
is(iframeDoc.name, null, "Doc should have 'null' name");
testAbsentAttrs(iframeDoc, { "explicit-name": "true" });
reordered = waitForEvent(EVENT_REORDER, iframe);
await invokeContentTask(browser, [], () => {
content.document.getElementById("iframe").src =
`data:text/html,hellohey`;
});
iframeDoc = (await reordered).accessible.firstChild;
is(iframeDoc.name, "hello", "Doc should have name");
testAttrs(iframeDoc, { "explicit-name": "true" }, true);
},
{ topLevel: true, chrome: true }
);
/*
* All test cases taken from https://www.w3.org/TR/accname-1.1/
* These were especially called out to demonstrate edge cases.
* (migrated from mochitest/name/test_ARIACore_examples.html)
*/
addAccessibleTask(
`
`,
async function testARIACoreExamples(browser, docAcc) {
function testName_(id, expected, cached) {
const acc = findAccessibleChildByID(docAcc, id);
if (browser.isRemoteBrowser) {
is(
acc.cache.has("name"),
cached,
`Name should ${cached ? "" : "not "}be in cache for '${id}'`
);
}
testName(acc, expected);
}
// Example 1 from section 4.3.1 under 2.B.
// Element1 should get its name from the text in element3.
// Element2 should not get its name from element1 because that already
// gets its name from another element.
testName_("el1", "hello", false);
testName_("el2", null, false);
// Example 2 from section 4.3.1 under 2.C.
// The buttons should get their name from their labels and the links.
testName_("del_row1", "Delete Documentation.pdf", true);
testName_("del_row2", "Delete HolidayLetter.pdf", true);
// Example 3 from section 4.3.1 under 2.F.
// Name should be own content text plus the value of the input plus
// more own inner text, separated by 1 space.
testName_("chkbx", "Flash the screen 5 times", false);
// Example 4 from section 4.3.1 under 2.F.
// Name from content should include all the child nodes, including
// table cells.
testName_("input_with_html_label", "foo bar baz", false);
},
{ topLevel: true, chrome: true }
);
/*
* Test labels that use ARIA naming in different ways.
*/
addAccessibleTask(
`