/* 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( ` `, 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( `
`, 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( `
hello
`, 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( `
bye world
bye world
bye
`, async function testSomeInterestingLabels(browser, docAcc) { const btn1 = findAccessibleChildByID(docAcc, "btn1"); const btn2 = findAccessibleChildByID(docAcc, "btn2"); const btn3 = findAccessibleChildByID(docAcc, "btn3"); // A button whose label subtree references the button testName(btn1, "bye world"); // A button whose label subtree has an explicit aria-label testName(btn2, "bye mars"); // A button whose label has an explicit aria-label of its own testName(btn3, "mars"); }, { topLevel: true, chrome: true } ); addAccessibleTask( ``, async function testInputPlaceHolder(browser, docAcc) { const input = findAccessibleChildByID(docAcc, "input"); testName(input, "title"); }, { topLevel: true, chrome: true } );