/* 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/states.js */ loadScripts({ name: "states.js", dir: MOCHITESTS_DIR }); /** * Test outline, outline rows with computed properties */ addAccessibleTask( `

Foods

`, async (browser, accDoc) => { const outline = getNativeInterface(accDoc, "outline"); is( outline.getAttributeValue("AXRole"), "AXOutline", "Correct role for outline" ); const outChildren = outline.getAttributeValue("AXChildren"); is(outChildren.length, 2, "Outline has two direct children"); is(outChildren[0].getAttributeValue("AXSubrole"), "AXOutlineRow"); is(outChildren[1].getAttributeValue("AXSubrole"), "AXOutlineRow"); const outRows = outline.getAttributeValue("AXRows"); is(outRows.length, 4, "Outline has four rows"); is( outRows[0].getAttributeValue("AXDisclosing"), 0, "Row is not disclosing" ); is( outRows[0].getAttributeValue("AXDisclosedByRow"), null, "Row is direct child of outline" ); is( outRows[0].getAttributeValue("AXDisclosedRows").length, 0, "Row has no row children, only group" ); is( outRows[0].getAttributeValue("AXDisclosureLevel"), 0, "Row is level zero" ); is(outRows[1].getAttributeValue("AXDisclosing"), 1, "Row is disclosing"); is( outRows[1].getAttributeValue("AXDisclosedByRow"), null, "Row is direct child of group" ); is( outRows[1].getAttributeValue("AXDisclosedRows").length, 0, "Row has no row children" ); is( outRows[1].getAttributeValue("AXDisclosureLevel"), 0, "Row is level zero" ); is( outRows[2].getAttributeValue("AXDisclosing"), 0, "Row is not disclosing" ); is( outRows[2].getAttributeValue("AXDisclosedByRow"), null, "Row is direct child of outline" ); is( outRows[2].getAttributeValue("AXDisclosedRows").length, 1, "Row has one row child" ); is( outRows[2].getAttributeValue("AXDisclosureLevel"), 0, "Row is level zero" ); is(outRows[3].getAttributeValue("AXDisclosing"), 1, "Row is disclosing"); is( outRows[3] .getAttributeValue("AXDisclosedByRow") .getAttributeValue("AXDescription"), outRows[2].getAttributeValue("AXDescription"), "Row is direct child of row[2]" ); is( outRows[3].getAttributeValue("AXDisclosedRows").length, 0, "Row has no row children" ); is( outRows[3].getAttributeValue("AXDisclosureLevel"), 1, "Row is level one" ); let evt = waitForMacEvent("AXRowExpanded", "vegetables"); await SpecialPowers.spawn(browser, [], () => { content.document .getElementById("vegetables") .setAttribute("aria-expanded", "true"); }); await evt; is( outRows[2].getAttributeValue("AXDisclosing"), 1, "Row is disclosing after being expanded" ); evt = waitForMacEvent("AXRowCollapsed", "vegetables"); await SpecialPowers.spawn(browser, [], () => { content.document .getElementById("vegetables") .setAttribute("aria-expanded", "false"); }); await evt; is( outRows[2].getAttributeValue("AXDisclosing"), 0, "Row is not disclosing after being collapsed again" ); } ); /** * Test outline, outline rows with declared properties */ addAccessibleTask( `

Foods

`, async (browser, accDoc) => { const outline = getNativeInterface(accDoc, "outline"); is( outline.getAttributeValue("AXRole"), "AXOutline", "Correct role for outline" ); const outChildren = outline.getAttributeValue("AXChildren"); is(outChildren.length, 2, "Outline has two direct children"); is(outChildren[0].getAttributeValue("AXSubrole"), "AXOutlineRow"); is(outChildren[1].getAttributeValue("AXSubrole"), "AXOutlineRow"); const outRows = outline.getAttributeValue("AXRows"); is(outRows.length, 9, "Outline has nine rows"); is( outRows[0].getAttributeValue("AXDisclosing"), 0, "Row is not disclosing" ); is( outRows[0].getAttributeValue("AXDisclosedByRow"), null, "Row is direct child of outline" ); is( outRows[0].getAttributeValue("AXDisclosedRows").length, 0, "Row has no direct row children, has list" ); is( outRows[0].getAttributeValue("AXDisclosureLevel"), 0, "Row is level zero" ); is(outRows[2].getAttributeValue("AXDisclosing"), 1, "Row is disclosing"); is( outRows[2].getAttributeValue("AXDisclosedByRow"), null, "Row is direct child of group" ); is( outRows[2].getAttributeValue("AXDisclosedRows").length, 2, "Row has two row children" ); is( outRows[2].getAttributeValue("AXDisclosureLevel"), 1, "Row is level one" ); is( outRows[3].getAttributeValue("AXDisclosing"), 0, "Row is not disclosing" ); is( outRows[3] .getAttributeValue("AXDisclosedByRow") .getAttributeValue("AXDescription"), outRows[2].getAttributeValue("AXDescription"), "Row is direct child of row 2" ); is( outRows[3].getAttributeValue("AXDisclosedRows").length, 0, "Row has no row children" ); is( outRows[3].getAttributeValue("AXDisclosureLevel"), 2, "Row is level two" ); is( outRows[5].getAttributeValue("AXDisclosing"), 0, "Row is not disclosing" ); is( outRows[5].getAttributeValue("AXDisclosedByRow"), null, "Row is direct child of outline" ); is( outRows[5].getAttributeValue("AXDisclosedRows").length, 1, "Row has no one row child" ); is( outRows[5].getAttributeValue("AXDisclosureLevel"), 0, "Row is level zero" ); is(outRows[6].getAttributeValue("AXDisclosing"), 1, "Row is disclosing"); is( outRows[6] .getAttributeValue("AXDisclosedByRow") .getAttributeValue("AXDescription"), outRows[5].getAttributeValue("AXDescription"), "Row is direct child of row 5" ); is( outRows[6].getAttributeValue("AXDisclosedRows").length, 2, "Row has two row children" ); is( outRows[6].getAttributeValue("AXDisclosureLevel"), 1, "Row is level one" ); is( outRows[7].getAttributeValue("AXDisclosing"), 0, "Row is not disclosing" ); is( outRows[7] .getAttributeValue("AXDisclosedByRow") .getAttributeValue("AXDescription"), outRows[6].getAttributeValue("AXDescription"), "Row is direct child of row 6" ); is( outRows[7].getAttributeValue("AXDisclosedRows").length, 0, "Row has no row children" ); is( outRows[7].getAttributeValue("AXDisclosureLevel"), 2, "Row is level two" ); } ); // Test outline that isn't built with li/uls gets correct desc addAccessibleTask( `
`, async (browser, accDoc) => { const tree = getNativeInterface(accDoc, "tree"); is(tree.getAttributeValue("AXRole"), "AXOutline", "Correct role for tree"); const treeItems = tree.getAttributeValue("AXChildren"); is(treeItems.length, 2, "Outline has two direct children"); is(treeItems[0].getAttributeValue("AXSubrole"), "AXOutlineRow"); is(treeItems[1].getAttributeValue("AXSubrole"), "AXOutlineRow"); const outRows = tree.getAttributeValue("AXRows"); is(outRows.length, 2, "Outline has two rows"); is( outRows[0].getAttributeValue("AXDescription"), "My files", "files labelled correctly" ); is( outRows[1].getAttributeValue("AXDescription"), "Shared items", "shared items labelled correctly" ); } ); // Test outline registers AXDisclosed attr as settable addAccessibleTask( `
Shared items
`, async (browser, accDoc) => { const tree = getNativeInterface(accDoc, "tree"); const treeItems = tree.getAttributeValue("AXChildren"); is(treeItems.length, 2, "Outline has two direct children"); is(treeItems[0].getAttributeValue("AXDisclosing"), 0); is(treeItems[1].getAttributeValue("AXDisclosing"), 1); is(treeItems[0].isAttributeSettable("AXDisclosing"), true); is(treeItems[1].isAttributeSettable("AXDisclosing"), true); // attempt to change attribute values treeItems[0].setAttributeValue("AXDisclosing", 1); treeItems[0].setAttributeValue("AXDisclosing", 0); // verify they're unchanged is(treeItems[0].getAttributeValue("AXDisclosing"), 0); is(treeItems[1].getAttributeValue("AXDisclosing"), 1); } ); // Test outline rows correctly expose checkable, checked/unchecked/mixed status addAccessibleTask( `
Leaf 1
Leaf 2
Leaf 3
Leaf 4
`, async (browser, accDoc) => { const tree = getNativeInterface(accDoc, "tree"); const treeItems = tree.getAttributeValue("AXChildren"); is(treeItems.length, 4, "Outline has four direct children"); is( treeItems[0].getAttributeValue("AXValue"), 0, "Child one is not checked" ); is(treeItems[1].getAttributeValue("AXValue"), 1, "Child two is checked"); is( treeItems[2].getAttributeValue("AXValue"), null, "Child three is not checkable and has no val" ); is(treeItems[3].getAttributeValue("AXValue"), 2, "Child four is mixed"); let stateChanged = Promise.all([ waitForMacEvent("AXValueChanged", "l1"), waitForStateChange("l1", STATE_CHECKED, true), ]); // We should get a state change event for checked. await SpecialPowers.spawn(browser, [], () => { content.document .getElementById("l1") .setAttribute("aria-checked", "true"); }); await stateChanged; is(treeItems[0].getAttributeValue("AXValue"), 1, "Child one is checked"); stateChanged = Promise.all([ waitForMacEvent("AXValueChanged", "l2"), waitForMacEvent("AXValueChanged", "l2"), waitForStateChange("l2", STATE_CHECKED, false), waitForStateChange("l2", STATE_CHECKABLE, false), ]); // We should get a state change event for both checked and checkable, // and value changes for both. await SpecialPowers.spawn(browser, [], () => { content.document.getElementById("l2").removeAttribute("aria-checked"); }); await stateChanged; is( treeItems[1].getAttributeValue("AXValue"), null, "Child two is not checkable and has no val" ); stateChanged = Promise.all([ waitForMacEvent("AXValueChanged", "l3"), waitForMacEvent("AXValueChanged", "l3"), waitForStateChange("l3", STATE_CHECKED, true), waitForStateChange("l3", STATE_CHECKABLE, true), ]); // We should get a state change event for both checked and checkable, // and value changes for each. await SpecialPowers.spawn(browser, [], () => { content.document .getElementById("l3") .setAttribute("aria-checked", "true"); }); await stateChanged; is(treeItems[2].getAttributeValue("AXValue"), 1, "Child three is checked"); stateChanged = Promise.all([ waitForMacEvent("AXValueChanged", "l4"), waitForMacEvent("AXValueChanged", "l4"), waitForStateChange("l4", STATE_MIXED, false), waitForStateChange("l4", STATE_CHECKABLE, false), ]); // We should get a state change event for both mixed and checkable, // and value changes for each. await SpecialPowers.spawn(browser, [], () => { content.document.getElementById("l4").removeAttribute("aria-checked"); }); await stateChanged; is( treeItems[3].getAttributeValue("AXValue"), null, "Child four is not checkable and has no value" ); } );