diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /accessible/tests/mochitest/relations | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | accessible/tests/mochitest/relations.js | 204 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/a11y.ini | 14 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_embeds.xhtml | 128 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_general.html | 456 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_general.xhtml | 237 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_groupInfoUpdate.html | 57 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_shadowdom.html | 58 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_tabbrowser.xhtml | 109 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_tree.xhtml | 105 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_ui_modalprompt.html | 111 | ||||
-rw-r--r-- | accessible/tests/mochitest/relations/test_update.html | 213 |
11 files changed, 1692 insertions, 0 deletions
diff --git a/accessible/tests/mochitest/relations.js b/accessible/tests/mochitest/relations.js new file mode 100644 index 0000000000..aa956649ff --- /dev/null +++ b/accessible/tests/mochitest/relations.js @@ -0,0 +1,204 @@ +/* import-globals-from common.js */ + +// ////////////////////////////////////////////////////////////////////////////// +// Constants + +var RELATION_CONTROLLED_BY = nsIAccessibleRelation.RELATION_CONTROLLED_BY; +var RELATION_CONTROLLER_FOR = nsIAccessibleRelation.RELATION_CONTROLLER_FOR; +var RELATION_DEFAULT_BUTTON = nsIAccessibleRelation.RELATION_DEFAULT_BUTTON; +var RELATION_DESCRIBED_BY = nsIAccessibleRelation.RELATION_DESCRIBED_BY; +var RELATION_DESCRIPTION_FOR = nsIAccessibleRelation.RELATION_DESCRIPTION_FOR; +var RELATION_EMBEDDED_BY = nsIAccessibleRelation.RELATION_EMBEDDED_BY; +var RELATION_EMBEDS = nsIAccessibleRelation.RELATION_EMBEDS; +var RELATION_FLOWS_FROM = nsIAccessibleRelation.RELATION_FLOWS_FROM; +var RELATION_FLOWS_TO = nsIAccessibleRelation.RELATION_FLOWS_TO; +var RELATION_LABEL_FOR = nsIAccessibleRelation.RELATION_LABEL_FOR; +var RELATION_LABELLED_BY = nsIAccessibleRelation.RELATION_LABELLED_BY; +var RELATION_MEMBER_OF = nsIAccessibleRelation.RELATION_MEMBER_OF; +var RELATION_NODE_CHILD_OF = nsIAccessibleRelation.RELATION_NODE_CHILD_OF; +var RELATION_NODE_PARENT_OF = nsIAccessibleRelation.RELATION_NODE_PARENT_OF; +var RELATION_PARENT_WINDOW_OF = nsIAccessibleRelation.RELATION_PARENT_WINDOW_OF; +var RELATION_POPUP_FOR = nsIAccessibleRelation.RELATION_POPUP_FOR; +var RELATION_SUBWINDOW_OF = nsIAccessibleRelation.RELATION_SUBWINDOW_OF; +var RELATION_CONTAINING_DOCUMENT = + nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT; +var RELATION_CONTAINING_TAB_PANE = + nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE; +var RELATION_CONTAINING_APPLICATION = + nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION; +const RELATION_DETAILS = nsIAccessibleRelation.RELATION_DETAILS; +const RELATION_DETAILS_FOR = nsIAccessibleRelation.RELATION_DETAILS_FOR; +const RELATION_ERRORMSG = nsIAccessibleRelation.RELATION_ERRORMSG; +const RELATION_ERRORMSG_FOR = nsIAccessibleRelation.RELATION_ERRORMSG_FOR; +const RELATION_LINKS_TO = nsIAccessibleRelation.RELATION_LINKS_TO; + +// ////////////////////////////////////////////////////////////////////////////// +// General + +/** + * Test the accessible relation. + * + * @param aIdentifier [in] identifier to get an accessible, may be ID + * attribute or DOM element or accessible object + * @param aRelType [in] relation type (see constants above) + * @param aRelatedIdentifiers [in] identifier or array of identifiers of + * expected related accessibles + */ +function testRelation(aIdentifier, aRelType, aRelatedIdentifiers) { + var relation = getRelationByType(aIdentifier, aRelType); + + var relDescr = getRelationErrorMsg(aIdentifier, aRelType); + var relDescrStart = getRelationErrorMsg(aIdentifier, aRelType, true); + + if (!relation || !relation.targetsCount) { + if (!aRelatedIdentifiers) { + ok(true, "No" + relDescr); + return; + } + + var msg = + relDescrStart + + "has no expected targets: '" + + prettyName(aRelatedIdentifiers) + + "'"; + + ok(false, msg); + return; + } else if (!aRelatedIdentifiers) { + ok(false, "There are unexpected targets of " + relDescr); + return; + } + + var relatedIds = + aRelatedIdentifiers instanceof Array + ? aRelatedIdentifiers + : [aRelatedIdentifiers]; + + var targets = []; + for (let idx = 0; idx < relatedIds.length; idx++) { + targets.push(getAccessible(relatedIds[idx])); + } + + if (targets.length != relatedIds.length) { + return; + } + + var actualTargets = relation.getTargets(); + + // Check if all given related accessibles are targets of obtained relation. + for (let idx = 0; idx < targets.length; idx++) { + var isFound = false; + for (let relatedAcc of actualTargets.enumerate(Ci.nsIAccessible)) { + if (targets[idx] == relatedAcc) { + isFound = true; + break; + } + } + + ok(isFound, prettyName(relatedIds[idx]) + " is not a target of" + relDescr); + } + + // Check if all obtained targets are given related accessibles. + for (let relatedAcc of actualTargets.enumerate(Ci.nsIAccessible)) { + let idx; + // eslint-disable-next-line no-empty + for (idx = 0; idx < targets.length && relatedAcc != targets[idx]; idx++) {} + + if (idx == targets.length) { + ok( + false, + "There is unexpected target" + prettyName(relatedAcc) + "of" + relDescr + ); + } + } +} + +/** + * Test that the given accessible relations don't exist. + * + * @param aIdentifier [in] identifier to get an accessible, may be ID + * attribute or DOM element or accessible object + * @param aRelType [in] relation type (see constants above) + * @param aUnrelatedIdentifiers [in] identifier or array of identifiers of + * accessibles that shouldn't exist for this + * relation. + */ +function testAbsentRelation(aIdentifier, aRelType, aUnrelatedIdentifiers) { + var relation = getRelationByType(aIdentifier, aRelType); + + var relDescr = getRelationErrorMsg(aIdentifier, aRelType); + + if (!aUnrelatedIdentifiers) { + ok(false, "No identifiers given for unrelated accessibles."); + return; + } + + if (!relation || !relation.targetsCount) { + ok(true, "No relations exist."); + return; + } + + var relatedIds = + aUnrelatedIdentifiers instanceof Array + ? aUnrelatedIdentifiers + : [aUnrelatedIdentifiers]; + + var targets = []; + for (let idx = 0; idx < relatedIds.length; idx++) { + targets.push(getAccessible(relatedIds[idx])); + } + + if (targets.length != relatedIds.length) { + return; + } + + var actualTargets = relation.getTargets(); + + // Any found targets that match given accessibles should be called out. + for (let idx = 0; idx < targets.length; idx++) { + var notFound = true; + for (let relatedAcc of actualTargets.enumerate(Ci.nsIAccessible)) { + if (targets[idx] == relatedAcc) { + notFound = false; + break; + } + } + + ok(notFound, prettyName(relatedIds[idx]) + " is a target of " + relDescr); + } +} + +/** + * Return related accessible for the given relation type. + * + * @param aIdentifier [in] identifier to get an accessible, may be ID attribute + * or DOM element or accessible object + * @param aRelType [in] relation type (see constants above) + */ +function getRelationByType(aIdentifier, aRelType) { + var acc = getAccessible(aIdentifier); + if (!acc) { + return null; + } + + var relation = null; + try { + relation = acc.getRelationByType(aRelType); + } catch (e) { + ok(false, "Can't get" + getRelationErrorMsg(aIdentifier, aRelType)); + } + + return relation; +} + +// ////////////////////////////////////////////////////////////////////////////// +// Private implementation details + +function getRelationErrorMsg(aIdentifier, aRelType, aIsStartSentence) { + var relStr = relationTypeToString(aRelType); + var msg = aIsStartSentence ? "Relation of '" : " relation of '"; + msg += relStr + "' type for '" + prettyName(aIdentifier) + "'"; + msg += aIsStartSentence ? " " : "."; + + return msg; +} diff --git a/accessible/tests/mochitest/relations/a11y.ini b/accessible/tests/mochitest/relations/a11y.ini new file mode 100644 index 0000000000..89ffaffdce --- /dev/null +++ b/accessible/tests/mochitest/relations/a11y.ini @@ -0,0 +1,14 @@ +[DEFAULT] +support-files = + !/accessible/tests/mochitest/*.js + +[test_embeds.xhtml] +skip-if = os == 'linux' && !debug # bug 1411145 +[test_general.html] +[test_general.xhtml] +[test_groupInfoUpdate.html] +[test_tabbrowser.xhtml] +[test_tree.xhtml] +[test_ui_modalprompt.html] +[test_shadowdom.html] +[test_update.html] diff --git a/accessible/tests/mochitest/relations/test_embeds.xhtml b/accessible/tests/mochitest/relations/test_embeds.xhtml new file mode 100644 index 0000000000..d49ce1f73c --- /dev/null +++ b/accessible/tests/mochitest/relations/test_embeds.xhtml @@ -0,0 +1,128 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" + type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + title="Embeds relation tests"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" /> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../states.js"></script> + <script type="application/javascript" + src="../events.js"></script> + <script type="application/javascript" + src="../relations.js"></script> + <script type="application/javascript" + src="../browser.js"></script> + + <script type="application/javascript"> + <![CDATA[ + //////////////////////////////////////////////////////////////////////////// + // Invokers + + function loadURI(aURI) + { + this.invoke = function loadURI_invoke() + { + tabBrowser().loadURI(Services.io.newURI(aURI), { + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); + } + + this.eventSeq = [ + new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument) + ]; + + this.finalCheck = function loadURI_finalCheck() + { + testRelation(browserDocument(), RELATION_EMBEDS, + getAccessible(currentTabDocument())); + } + + this.getID = function loadURI_getID() + { + return "load uri " + aURI; + } + } + + function addTab(aURI) + { + this.invoke = function addTab_invoke() + { + tabBrowser().addTab(aURI, { + referrerURI: null, + charset: null, + postData: null, + inBackground: false, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); + } + + this.eventSeq = [ + new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument) + ]; + + this.finalCheck = function loadURI_finalCheck() + { + testRelation(browserDocument(), RELATION_EMBEDS, + getAccessible(currentTabDocument())); + } + + this.getID = function addTab_getID() + { + return "load uri '" + aURI + "' in new tab"; + } + } + + //////////////////////////////////////////////////////////////////////////// + // Testing + + //gA11yEventDumpToConsole = true; // debug + + var gQueue = null; + function doTests() + { + testRelation(browserDocument(), RELATION_EMBEDS, + getAccessible(currentTabDocument())); + + enableLogging("docload"); + gQueue = new eventQueue(); + + gQueue.push(new loadURI("about:robots")); + gQueue.push(new addTab("about:mozilla")); + + gQueue.onFinish = function() + { + disableLogging(); + closeBrowserWindow(); + } + gQueue.invoke(); + } + + SimpleTest.waitForExplicitFinish(); + openBrowserWindow(doTests, "about:license"); + ]]> + </script> + + <vbox flex="1" style="overflow: auto;"> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=707654" + title="Embeds relation on root accessible can return not content document"> + Mozilla Bug 707654 + </a> + <p id="display"></p> + <div id="content" style="display: none"> + </div> + <pre id="test"> + </pre> + </body> + </vbox> +</window> diff --git a/accessible/tests/mochitest/relations/test_general.html b/accessible/tests/mochitest/relations/test_general.html new file mode 100644 index 0000000000..d16b7c1492 --- /dev/null +++ b/accessible/tests/mochitest/relations/test_general.html @@ -0,0 +1,456 @@ +<html> + +<head> + <title>nsIAccessible::getAccessibleRelated() tests</title> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../relations.js"></script> + <script type="application/javascript" + src="../role.js"></script> + + <script type="application/javascript"> + function doTest() { + // html:label@for + testRelation("label1_1", RELATION_LABEL_FOR, "control1_1"); + testRelation("control1_1", RELATION_LABELLED_BY, "label1_1"); + + // html:label@for, multiple + testRelation("label1_2", RELATION_LABEL_FOR, "control1_2"); + testRelation("label1_3", RELATION_LABEL_FOR, "control1_2"); + testRelation("control1_2", RELATION_LABELLED_BY, + [ "label1_2", "label1_3" ]); + + // ancestor html:label (implicit association) + testRelation("label1_4", RELATION_LABEL_FOR, "control1_4"); + testRelation("control1_4", RELATION_LABELLED_BY, "label1_4"); + testRelation("control1_4_option1", RELATION_LABELLED_BY, null); + testRelation("label1_5", RELATION_LABEL_FOR, "control1_5"); + testRelation("control1_5", RELATION_LABELLED_BY, "label1_5"); + testRelation("label1_6", RELATION_LABEL_FOR, "control1_6"); + testRelation("control1_6", RELATION_LABELLED_BY, "label1_6"); + testRelation("label1_7", RELATION_LABEL_FOR, "control1_7"); + testRelation("control1_7", RELATION_LABELLED_BY, "label1_7"); + testRelation("label1_8", RELATION_LABEL_FOR, "control1_8"); + testRelation("control1_8", RELATION_LABELLED_BY, "label1_8"); + testRelation("label1_9", RELATION_LABEL_FOR, "control1_9"); + testRelation("control1_9", RELATION_LABELLED_BY, "label1_9"); + testRelation("label1_10", RELATION_LABEL_FOR, "control1_10"); + testRelation("control1_10", RELATION_LABELLED_BY, "label1_10"); + testRelation("label1_11", RELATION_LABEL_FOR, "control1_11"); + testRelation("control1_11", RELATION_LABELLED_BY, "label1_11"); + testRelation("label1_12", RELATION_LABEL_FOR, "control1_12"); + testRelation("control1_12", RELATION_LABELLED_BY, "label1_12"); + + testRelation("label1_13", RELATION_LABEL_FOR, null); + testRelation("control1_13", RELATION_LABELLED_BY, null); + testRelation("control1_14", RELATION_LABELLED_BY, "label1_14"); + + // aria-labelledby + testRelation("label2", RELATION_LABEL_FOR, "checkbox2"); + testRelation("checkbox2", RELATION_LABELLED_BY, "label2"); + + // aria-labelledby, multiple relations + testRelation("label3", RELATION_LABEL_FOR, "checkbox3"); + testRelation("label4", RELATION_LABEL_FOR, "checkbox3"); + testRelation("checkbox3", RELATION_LABELLED_BY, ["label3", "label4"]); + + // aria-describedby + testRelation("descr1", RELATION_DESCRIPTION_FOR, "checkbox4"); + testRelation("checkbox4", RELATION_DESCRIBED_BY, "descr1"); + + // aria-describedby, multiple relations + testRelation("descr2", RELATION_DESCRIPTION_FOR, "checkbox5"); + testRelation("descr3", RELATION_DESCRIPTION_FOR, "checkbox5"); + testRelation("checkbox5", RELATION_DESCRIBED_BY, ["descr2", "descr3"]); + + // aria_owns, multiple relations + testRelation("treeitem1", RELATION_NODE_CHILD_OF, "tree"); + testRelation("treeitem2", RELATION_NODE_CHILD_OF, "tree"); + + // 'node child of' relation for outlineitem role + testRelation("treeitem3", RELATION_NODE_CHILD_OF, "tree"); + testRelation("treeitem4", RELATION_NODE_CHILD_OF, "tree"); + testRelation("treeitem5", RELATION_NODE_CHILD_OF, "treeitem4"); + testRelation("treeitem6", RELATION_NODE_CHILD_OF, "tree"); + testRelation("treeitem7", RELATION_NODE_CHILD_OF, "treeitem6"); + testRelation("tree2_ti1", RELATION_NODE_CHILD_OF, "tree2"); + testRelation("tree2_ti1a", RELATION_NODE_CHILD_OF, "tree2_ti1"); + testRelation("tree2_ti1b", RELATION_NODE_CHILD_OF, "tree2_ti1"); + + // 'node child of' relation for row role in grid. + // Relation for row associated using aria-level should exist. + testRelation("simplegrid-row3", RELATION_NODE_CHILD_OF, + "simplegrid-row2"); + // Relations for hierarchical children elements shouldn't exist. + testAbsentRelation("simplegrid-row1", RELATION_NODE_CHILD_OF, + "simplegrid"); + testAbsentRelation("simplegrid-row2", RELATION_NODE_CHILD_OF, + "simplegrid"); + + // 'node child of' relation for row role of treegrid + testRelation("treegridrow1", RELATION_NODE_CHILD_OF, "treegrid"); + testRelation("treegridrow2", RELATION_NODE_CHILD_OF, "treegrid"); + testRelation("treegridrow3", RELATION_NODE_CHILD_OF, "treegridrow2"); + + // 'node child of' relation for lists organized by groups + testRelation("listitem1", RELATION_NODE_CHILD_OF, "list"); + testRelation("listitem1.1", RELATION_NODE_CHILD_OF, "listitem1"); + testRelation("listitem1.2", RELATION_NODE_CHILD_OF, "listitem1"); + + // 'node child of' relation for lists and trees organized by groups, with + // intervening generic accessibles between widget components. + testRelation("list2_listitem1.1", RELATION_NODE_CHILD_OF, "list2_listitem1"); + testRelation("list2_listitem1.2", RELATION_NODE_CHILD_OF, "list2_listitem1"); + testRelation("tree4_treeitem1.1", RELATION_NODE_CHILD_OF, "tree4_treeitem1"); + testRelation("tree4_treeitem1.2", RELATION_NODE_CHILD_OF, "tree4_treeitem1"); + + // 'node child of' relation for a treeitem sibling group special case, + // with intervening generic accessibles. In this case, if a treeitem's + // parent is a group and that group has a previous treeitem sibling, the + // treeitem is a child of that previous treeitem sibling. + testRelation("tree3_treeitem1.1", RELATION_NODE_CHILD_OF, "tree3_treeitem1"); + testRelation("tree3_treeitem1.2", RELATION_NODE_CHILD_OF, "tree3_treeitem1"); + + // 'node child of' relation for the document having window, returns + // direct accessible parent (fixed in bug 419770). + var iframeElmObj = {}; + var iframeAcc = getAccessible("iframe", null, iframeElmObj); + var iframeDoc = iframeElmObj.value.contentDocument; + var iframeDocAcc = getAccessible(iframeDoc); + testRelation(iframeDocAcc, RELATION_NODE_CHILD_OF, iframeAcc); + + // 'node parent of' relation on ARIA tree and treegrid. + testRelation("tree", RELATION_NODE_PARENT_OF, + ["treeitem1", "treeitem2", // aria-owns + "treeitem3", "treeitem4", "treeitem6"]); // children + testRelation("treeitem4", RELATION_NODE_PARENT_OF, + "treeitem5"); // aria-level + testRelation("treeitem6", RELATION_NODE_PARENT_OF, + "treeitem7"); // // group role + testRelation("tree2", RELATION_NODE_PARENT_OF, "tree2_ti1"); // group role + testRelation("tree2_ti1", RELATION_NODE_PARENT_OF, + ["tree2_ti1a", "tree2_ti1b"]); // group role + + testRelation("treegridrow2", RELATION_NODE_PARENT_OF, "treegridrow3"); + testRelation("treegrid", RELATION_NODE_PARENT_OF, + ["treegridrow1", "treegridrow2"]); + + // 'node parent of' relation on ARIA grid. + // 'node parent of' relation on ARIA grid's row. + // Should only have relation to child through aria-level. + testRelation("simplegrid-row2", RELATION_NODE_PARENT_OF, + "simplegrid-row3"); + + // 'node parent of' relation on ARIA list structured by groups + testRelation("list", RELATION_NODE_PARENT_OF, + "listitem1"); + testRelation("listitem1", RELATION_NODE_PARENT_OF, + [ "listitem1.1", "listitem1.2" ]); + + // aria-atomic + testRelation(getNode("atomic").firstChild, RELATION_MEMBER_OF, "atomic"); + + // aria-controls + getAccessible("tab"); + todo(false, + "Getting an accessible tab, otherwise relations for tabpanel aren't cached. Bug 606924 will fix that."); + testRelation("tabpanel", RELATION_CONTROLLED_BY, "tab"); + testRelation("tab", RELATION_CONTROLLER_FOR, "tabpanel"); + + // aria-controls, multiple relations + testRelation("lr1", RELATION_CONTROLLED_BY, "button"); + testRelation("lr2", RELATION_CONTROLLED_BY, "button"); + testRelation("button", RELATION_CONTROLLER_FOR, ["lr1", "lr2"]); + + // aria-flowto + testRelation("flowto", RELATION_FLOWS_TO, "flowfrom"); + testRelation("flowfrom", RELATION_FLOWS_FROM, "flowto"); + + // aria-flowto, multiple relations + testRelation("flowto1", RELATION_FLOWS_TO, ["flowfrom1", "flowfrom2"]); + testRelation("flowfrom1", RELATION_FLOWS_FROM, "flowto1"); + testRelation("flowfrom2", RELATION_FLOWS_FROM, "flowto1"); + + // 'default button' relation + testRelation("input", RELATION_DEFAULT_BUTTON, "submit"); + + // output 'for' relations + testRelation("output", RELATION_CONTROLLED_BY, ["input", "input2"]); + testRelation("output2", RELATION_CONTROLLED_BY, ["input", "input2"]); + testRelation("input", RELATION_CONTROLLER_FOR, ["output", "output2"]); + testRelation("input2", RELATION_CONTROLLER_FOR, ["output", "output2"]); + + // 'described by'/'description for' relation for html:table and + // html:caption + testRelation("caption", RELATION_LABEL_FOR, "table"); + testRelation("table", RELATION_LABELLED_BY, "caption"); + + // 'labelled by'/'label for' relation for html:fieldset and + // html:legend + testRelation("legend", RELATION_LABEL_FOR, "fieldset"); + testRelation("fieldset", RELATION_LABELLED_BY, "legend"); + + // containing relations + testRelation("control1_1", RELATION_CONTAINING_DOCUMENT, document); + testRelation("control1_1", RELATION_CONTAINING_TAB_PANE, getTabDocAccessible("control1_1")); + testRelation("control1_1", RELATION_CONTAINING_APPLICATION, getApplicationAccessible()); + + // details + testRelation("has_details", RELATION_DETAILS, "details"); + testRelation("details", RELATION_DETAILS_FOR, "has_details"); + testRelation("has_multiple_details", RELATION_DETAILS, ["details2", "details3"]); + testRelation("details2", RELATION_DETAILS_FOR, "has_multiple_details"); + testRelation("details3", RELATION_DETAILS_FOR, "has_multiple_details"); + + // error + testRelation("has_error", RELATION_ERRORMSG, "error"); + testRelation("error", RELATION_ERRORMSG_FOR, "has_error"); + + // finish test + SimpleTest.finish(); + } + + disableLogging(); // from test_embeds.xhtml + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> + +<body> + + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=475298" + title="mochitests for accessible relations"> + Bug 475298 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=527461" + title="Implement RELATION_NODE_PARENT_OF"> + Bug 527461 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=558036" + title="make HTML <output> accessible"> + Bug 558036 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=682790" + title="Ignore implicit label association when it's associated explicitly"> + Bug 682790 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=687393" + title="HTML select options gets relation from containing label"> + Bug 687393 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=864224" + title="Support nested ARIA listitems structured by role='group'"> + Bug 864224 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <label id="label1_1" for="control1_1">label</label> + <input id="control1_1"> + + <label id="label1_2" for="control1_2">label</label> + <label id="label1_3" for="control1_2">label</label> + <input id="control1_2"> + + <label id="label1_4">Label + <select id="control1_4"> + <option id="control1_4_option1">option</option> + </select> + </label> + <label id="label1_5">Label + <button id="control1_5">button</button> + </label> + <label id="label1_6">Label + <input id="control1_6"> + </label> + <label id="label1_7">Label + <input id="control1_7" type="checkbox"> + </label> + <label id="label1_8">Label + <input id="control1_8" type="radio"> + </label> + <label id="label1_9">Label + <input id="control1_9" type="button" value="button"> + </label> + <label id="label1_10">Label + <input id="control1_10" type="submit"> + </label> + <label id="label1_11">Label + <input id="control1_11" type="image"> + </label> + <label id="label1_12">Label + <progress id="control1_12"></progress> + </label> + + <label id="label1_13" for="">Label + <input id="control1_13"> + </label> + <label id="label1_14" for="control1_14">Label + <input id="control1_14"> + </label> + + <span id="label2">label</span> + <span role="checkbox" id="checkbox2" aria-labelledby="label2"></span> + + <span id="label3">label1</span> + <span id="label4">label2</span> + <span role="checkbox" id="checkbox3" aria-labelledby="label3 label4"></span> + + <span id="descr1">description</span> + <span role="checkbox" id="checkbox4" aria-describedby="descr1"></span> + + <span id="descr2">description1</span> + <span id="descr3">description2</span> + <span role="checkbox" id="checkbox5" aria-describedby="descr2 descr3"></span> + + <div role="treeitem" id="treeitem1">Yellow</div> + <div role="treeitem" id="treeitem2">Orange</div> + <div id="tree" role="tree" aria-owns="treeitem1 treeitem2"> + <div role="treeitem" id="treeitem3">Blue</div> + <div role="treeitem" id="treeitem4" aria-level="1">Green</div> + <div role="treeitem" id="treeitem5" aria-level="2">Light green</div> + <div role="treeitem" id="treeitem6" aria-level="1">Green2</div> + <div role="group"> + <div role="treeitem" id="treeitem7">Super light green</div> + </div> + </div> + + <div role="grid" id="simplegrid"> + <div role="row" id="simplegrid-row1" aria-level="1"> + <div role="gridcell">cell 1,1</div> + <div role="gridcell">cell 1,2</div> + </div> + <div role="row" id="simplegrid-row2" aria-level="1"> + <div role="gridcell">cell 2,1</div> + <div role="gridcell">cell 2,2</div> + </div> + <div role="row" id="simplegrid-row3" aria-level="2"> + <div role="gridcell">cell 3,1</div> + <div role="gridcell">cell 3,2</div> + </div> + </div> + + <ul role="tree" id="tree2"> + <li role="treeitem" id="tree2_ti1">Item 1 + <ul role="group"> + <li role="treeitem" id="tree2_ti1a">Item 1A</li> + <li role="treeitem" id="tree2_ti1b">Item 1B</li> + </ul> + </li> + </ul> + + <div role="tree" id="tree3"> + <div tabindex="0"> + <div role="treeitem" id="tree3_treeitem1">1</div> + </div> + <div tabindex="0"> + <div role="group"> + <div role="treeitem" id="tree3_treeitem1.1">1.1</div> + <div role="treeitem" id="tree3_treeitem1.2">1.2</div> + </div> + </div> + </div> + + <div role="treegrid" id="treegrid"> + <div role="row" id="treegridrow1"> + <span role="gridcell">cell1</span><span role="gridcell">cell2</span> + </div> + <div role="row" id="treegridrow2" aria-level="1"> + <span role="gridcell">cell3</span><span role="gridcell">cell4</span> + </div> + <div role="row" id="treegridrow3" aria-level="2"> + <span role="gridcell">cell5</span><span role="gridcell">cell6</span> + </div> + </div> + + <div role="list" id="list"> + <div role="listitem" id="listitem1">Item 1 + <div role="group"> + <div role="listitem" id="listitem1.1">Item 1A</div> + <div role="listitem" id="listitem1.2">Item 1B</div> + </div> + </div> + </div> + + <div role="tree" id="tree4"> + <div role="treeitem" id="tree4_treeitem1">1 + <div tabindex="0"> + <div role="group"> + <div role="treeitem" id="tree4_treeitem1.1">1.1</div> + <div role="treeitem" id="tree4_treeitem1.2">1.2</div> + </div> + </div> + </div> + </div> + + <div role="list" id="list2"> + <div role="listitem" id="list2_listitem1">1 + <div tabindex="0"> + <div role="group"> + <div role="listitem" id="list2_listitem1.1">1.1</div> + <div role="listitem" id="list2_listitem1.2">1.2</div> + </div> + </div> + </div> + </div> + + <iframe id="iframe"></iframe> + + <div id="tablist" role="tablist"> + <div id="tab" role="tab" aria-controls="tabpanel">tab</div> + </div> + <div id="tabpanel" role="tabpanel">tabpanel</div> + + <div id="lr1" aria-live="assertive">1</div> + <div id="lr2" aria-live="assertive">a</div> + <input type="button" id="button" aria-controls="lr1 lr2" + onclick="getNode('lr1').textContent += '1'; getNode('lr2').textContent += 'a';"/> + + <div id="atomic" aria-atomic="true">live region</div> + + <span id="flowto" aria-flowto="flowfrom">flow to</span> + <span id="flowfrom">flow from</span> + + <span id="flowto1" aria-flowto="flowfrom1 flowfrom2">flow to</span> + <span id="flowfrom1">flow from</span> + <span id="flowfrom2">flow from</span> + + <form id="form"> + <input id="input" /> + <input id="input2" /> + <input type="submit" id="submit" /> + <output id="output" style="display:block" for="input input2"></output> + <output id="output2" for="input input2"></output> + </form> + + <table id="table"> + <caption id="caption">tabple caption</caption> + <tr> + <td>cell1</td><td>cell2</td> + </tr> + </table> + + <fieldset id="fieldset"> + <legend id="legend">legend</legend> + <input /> + </fieldset> + + <input id="has_details" aria-details="details"><section id="details"></section> + <input id="has_multiple_details" aria-details="details2 details3"><section id="details2"></section><section id="details3"></section> + <input id="has_error" aria-errormessage="error"><section id="error"></section> +</body> +</html> diff --git a/accessible/tests/mochitest/relations/test_general.xhtml b/accessible/tests/mochitest/relations/test_general.xhtml new file mode 100644 index 0000000000..bc3b328fd9 --- /dev/null +++ b/accessible/tests/mochitest/relations/test_general.xhtml @@ -0,0 +1,237 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" + type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml" + title="nsIAccessible::getAccessibleRelated() tests"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" /> + + <script type="application/javascript" + src="../common.js" /> + <script type="application/javascript" + src="../relations.js" /> + <script type="application/javascript" + src="../role.js" /> + + <script type="application/javascript"> + <![CDATA[ + function doTest() + { + // xul:label@control + testRelation("label1", RELATION_LABEL_FOR, "checkbox1"); + testRelation("checkbox1", RELATION_LABELLED_BY, "label1"); + + // xul:label@control, multiple + testRelation("label1_1", RELATION_LABEL_FOR, "checkbox1_1"); + testRelation("label1_2", RELATION_LABEL_FOR, "checkbox1_1"); + testRelation("checkbox1_1", RELATION_LABELLED_BY, + [ "label1_1", "label1_2" ]); + + // aria-labelledby + testRelation("label2", RELATION_LABEL_FOR, "checkbox2"); + testRelation("checkbox2", RELATION_LABELLED_BY, "label2"); + + // aria-labelledby, multiple relations + testRelation("label3", RELATION_LABEL_FOR, "checkbox3"); + testRelation("label4", RELATION_LABEL_FOR, "checkbox3"); + testRelation("checkbox3", RELATION_LABELLED_BY, ["label3", "label4"]); + + // xul:label@control referring to HTML element + testRelation("label_input", RELATION_LABEL_FOR, "input"); + testRelation("input", RELATION_LABELLED_BY, "label_input"); + + // aria-describedby + testRelation("descr1", RELATION_DESCRIPTION_FOR, "checkbox4"); + testRelation("checkbox4", RELATION_DESCRIBED_BY, "descr1"); + + // aria-describedby, multiple relations + testRelation("descr2", RELATION_DESCRIPTION_FOR, "checkbox5"); + testRelation("descr3", RELATION_DESCRIPTION_FOR, "checkbox5"); + testRelation("checkbox5", RELATION_DESCRIBED_BY, ["descr2", "descr3"]); + + // xul:description@control + testRelation("descr4", RELATION_DESCRIPTION_FOR, "checkbox6"); + testRelation("checkbox6", RELATION_DESCRIBED_BY, "descr4"); + + // xul:description@control, multiple + testRelation("descr5", RELATION_DESCRIPTION_FOR, "checkbox7"); + testRelation("descr6", RELATION_DESCRIPTION_FOR, "checkbox7"); + testRelation("checkbox7", RELATION_DESCRIBED_BY, + [ "descr5", "descr6" ]); + + // aria_owns, multiple relations + testRelation("treeitem1", RELATION_NODE_CHILD_OF, "tree"); + testRelation("treeitem2", RELATION_NODE_CHILD_OF, "tree"); + + // 'node child of' relation for outlineitem role + testRelation("treeitem3", RELATION_NODE_CHILD_OF, "tree"); + testRelation("treeitem4", RELATION_NODE_CHILD_OF, "tree"); + testRelation("treeitem5", RELATION_NODE_CHILD_OF, "treeitem4"); + + // no relation node_child_of for accessible contained in an unexpected + // parent + testRelation("treeitem6", RELATION_NODE_CHILD_OF, null); + + // 'node child of' relation for the document having window, returns + // direct accessible parent (fixed in bug 419770). + var iframeElmObj = {}; + var iframeAcc = getAccessible("iframe", null, iframeElmObj); + var iframeDoc = iframeElmObj.value.contentDocument; + var iframeDocAcc = getAccessible(iframeDoc); + testRelation(iframeDocAcc, RELATION_NODE_CHILD_OF, iframeAcc); + + // aria-controls + getAccessible("tab"); + todo(false, + "Getting an accessible tab, otherwise relations for tabpanel aren't cached. Bug 606924 will fix that."); + testRelation("tabpanel", RELATION_CONTROLLED_BY, "tab"); + testRelation("tab", RELATION_CONTROLLER_FOR, "tabpanel"); + + // aria-controls, multiple relations + testRelation("lr1", RELATION_CONTROLLED_BY, "button"); + testRelation("lr2", RELATION_CONTROLLED_BY, "button"); + testRelation("button", RELATION_CONTROLLER_FOR, ["lr1", "lr2"]); + + // aria-flowto + testRelation("flowto", RELATION_FLOWS_TO, "flowfrom"); + testRelation("flowfrom", RELATION_FLOWS_FROM, "flowto"); + + // aria-flowto, multiple relations + testRelation("flowto1", RELATION_FLOWS_TO, ["flowfrom1", "flowfrom2"]); + testRelation("flowfrom1", RELATION_FLOWS_FROM, "flowto1"); + testRelation("flowfrom2", RELATION_FLOWS_FROM, "flowto1"); + + // 'labelled by'/'label for' relation for xul:groupbox and xul:label + var groupboxAcc = getAccessible("groupbox"); + var labelAcc = groupboxAcc.firstChild; + testRelation(labelAcc, RELATION_LABEL_FOR, groupboxAcc); + testRelation(groupboxAcc, RELATION_LABELLED_BY, labelAcc); + + // 'labelled by'/'label for' relations for xul:tab and xul:tabpanel + // (fixed in bug 366527) + testRelation("tabpanel1", RELATION_LABELLED_BY, "tab1"); + testRelation("tab1", RELATION_LABEL_FOR, "tabpanel1"); + testRelation("tabpanel2", RELATION_LABELLED_BY, "tab2"); + testRelation("tab2", RELATION_LABEL_FOR, "tabpanel2"); + testRelation("tabpanel3", RELATION_LABELLED_BY, "tab3"); + testRelation("tab3", RELATION_LABEL_FOR, "tabpanel3"); + + // finish test + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + ]]> + </script> + + <vbox style="overflow: auto;" flex="1"> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=475298" + title="mochitests for accessible relations"> + Mozilla Bug 475298 + </a><br/> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=673389" + title="node_child_of on an item not in a proper container"> + Mozilla Bug 67389 + </a><br/> + + <p id="display"></p> + <div id="content" style="display: none"> + </div> + <pre id="test"> + </pre> + </body> + + <label id="label1" control="checkbox1">label</label> + <checkbox id="checkbox1"/> + + <label id="label1_1" control="checkbox1_1">label</label> + <label id="label1_2" control="checkbox1_1">label</label> + <checkbox id="checkbox1_1"/> + + <description id="label2">label</description> + <description role="checkbox" id="checkbox2" aria-labelledby="label2"/> + + <description id="label3">label</description> + <description id="label4">label</description> + <description role="checkbox" id="checkbox3" + aria-labelledby="label3 label4"/> + + <label id="label_input" control="input">label</label> + <html:input id="input"/> + + <description id="descr1">description</description> + <description role="checkbox" id="checkbox4" aria-describedby="descr1"/> + + <description id="descr2">label</description> + <description id="descr3">label</description> + <description role="checkbox" id="checkbox5" + aria-describedby="descr2 descr3"/> + + <description id="descr4" control="checkbox6">description</description> + <checkbox id="checkbox6"/> + + <description id="descr5" control="checkbox7">description</description> + <description id="descr6" control="checkbox7">description</description> + <checkbox id="checkbox7"/> + + <description role="treeitem" id="treeitem1">Yellow</description> + <description role="treeitem" id="treeitem2">Orange</description> + <vbox id="tree" role="tree" aria-owns="treeitem1 treeitem2"> + <description role="treeitem" id="treeitem3">Blue</description> + <description role="treeitem" id="treeitem4" aria-level="1">Green</description> + <description role="treeitem" id="treeitem5" aria-level="2">Light green</description> + </vbox> + + <description role="treeitem" id="treeitem6">Dark green</description> + + <iframe id="iframe"/> + + <hbox id="tablist" role="tablist"> + <description id="tab" role="tab" aria-controls="tabpanel">tab</description> + </hbox> + <description id="tabpanel" role="tabpanel">tabpanel</description> + + <description id="lr1" aria-live="assertive">1</description> + <description id="lr2" aria-live="assertive">a</description> + <button id="button" aria-controls="lr1 lr2" label="button" + oncommand="getNode('lr1').textContent += '1'; getNode('lr2').textContent += 'a';"/> + + <description id="flowto1" aria-flowto="flowfrom1 flowfrom2">flow to</description> + <description id="flowfrom1">flow from</description> + <description id="flowfrom2">flow from</description> + + <description id="flowto" aria-flowto="flowfrom">flow to</description> + <description id="flowfrom">flow from</description> + + <groupbox id="groupbox"> + <label value="caption"/> + </groupbox> + + <tabbox> + <tabs> + <tab label="tab1" id="tab1"/> + <tab label="tab2" id="tab2" linkedpanel="tabpanel2"/> + <tab label="tab3" id="tab3" linkedpanel="tabpanel3"/> + </tabs> + <tabpanels> + <tabpanel id="tabpanel1"> + <description>tabpanel1</description> + </tabpanel> + <tabpanel id="tabpanel3"> + <description>tabpanel3</description> + </tabpanel> + <tabpanel id="tabpanel2"> + <description>tabpanel2</description> + </tabpanel> + </tabpanels> + </tabbox> + + </vbox> +</window> diff --git a/accessible/tests/mochitest/relations/test_groupInfoUpdate.html b/accessible/tests/mochitest/relations/test_groupInfoUpdate.html new file mode 100644 index 0000000000..efca27617c --- /dev/null +++ b/accessible/tests/mochitest/relations/test_groupInfoUpdate.html @@ -0,0 +1,57 @@ +<html> +<head> + <title>Test accessible relations when AccGroupInfo updated</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../relations.js"></script> + <script type="application/javascript" + src="../promisified-events.js"></script> + + <script type="application/javascript"> + async function doTests() { + info("Testing NODE_CHILD_OF update after DOM removal"); + testRelation("l1i2", RELATION_NODE_CHILD_OF, "l1i1"); + let reorder = waitForEvent(EVENT_REORDER, "l1"); + getNode("l1i1").remove(); + await reorder; + testRelation("l1i2", RELATION_NODE_CHILD_OF, "l1"); + + info("Testing NODE_CHILD_OF update after aria-owns removal"); + testRelation("l2i2", RELATION_NODE_CHILD_OF, "l2i1"); + reorder = waitForEvent(EVENT_REORDER, "l2"); + // Move l2i1 out of l2 using aria-owns. + getNode("l2trash").setAttribute("aria-owns", "l2i1"); + await reorder; + testRelation("l2i2", RELATION_NODE_CHILD_OF, "l2"); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTests); + </script> +</head> + +<body id="body"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <div id="l1" role="list"> + <div id="l1i1" role="listitem" aria-level="1">a</div> + <div id="l1i2" role="listitem" aria-level="2">b</div> + </div> + + <div id="l2" role="list"> + <div id="l2i1" role="listitem" aria-level="1">a</div> + <div id="l2i2" role="listitem" aria-level="2">b</div> + </div> + <div id="l2trash"></div> +</body> +</html> diff --git a/accessible/tests/mochitest/relations/test_shadowdom.html b/accessible/tests/mochitest/relations/test_shadowdom.html new file mode 100644 index 0000000000..adb9490d99 --- /dev/null +++ b/accessible/tests/mochitest/relations/test_shadowdom.html @@ -0,0 +1,58 @@ +<html> + +<head> + <title>Explicit content and shadow DOM content relations tests</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../relations.js"></script> + <script type="application/javascript" + src="../role.js"></script> + + <script type="application/javascript"> + function doTest() { + // explicit content + let label = document.getElementById("label"); + let element = document.getElementById("element"); + testRelation(label, RELATION_LABEL_FOR, element); + testRelation(element, RELATION_LABELLED_BY, label); + + // shadow DOM content + let shadowRoot = document.getElementById("shadowcontainer").shadowRoot; + let shadowLabel = shadowRoot.getElementById("label"); + let shadowElement = shadowRoot.getElementById("element"); + + testRelation(shadowLabel, RELATION_LABEL_FOR, shadowElement); + testRelation(shadowElement, RELATION_LABELLED_BY, shadowLabel); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + + addA11yLoadEvent(doTest, window); + </script> +</head> + +<body> + <p id="display"></p> + <div id="content"> + <div id="label"></div> + <div id="element" aria-labelledby="label"></div> + <div id="shadowcontainer"></div> + <script> + let shadowRoot = document.getElementById("shadowcontainer"). + attachShadow({mode: "open"}); + shadowRoot.innerHTML = + `<div id="label"></div><div id="element" aria-labelledby="label"></div>`; + </script> + </div> + <pre id="test"> + </pre> +</body> +</html> diff --git a/accessible/tests/mochitest/relations/test_tabbrowser.xhtml b/accessible/tests/mochitest/relations/test_tabbrowser.xhtml new file mode 100644 index 0000000000..3356bc6140 --- /dev/null +++ b/accessible/tests/mochitest/relations/test_tabbrowser.xhtml @@ -0,0 +1,109 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" + type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + title="Accessible XUL tabbrowser relation tests"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" /> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" + src="../common.js" /> + <script type="application/javascript" + src="../role.js" /> + <script type="application/javascript" + src="../relations.js" /> + <script type="application/javascript" + src="../events.js" /> + <script type="application/javascript" + src="../browser.js"></script> + + <script type="application/javascript"> + <![CDATA[ + //////////////////////////////////////////////////////////////////////////// + // Invoker + function testTabRelations() + { + this.eventSeq = [ + new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 0), + new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1) + ]; + + this.invoke = function testTabRelations_invoke() + { + var docURIs = ["about:license", "about:mozilla"]; + tabBrowser().loadTabs(docURIs, { + inBackground: false, + replace: true, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); + // Flush layout, so as to guarantee that the a11y tree is constructed. + browserDocument().documentElement.getBoundingClientRect(); + } + + this.finalCheck = function testTabRelations_finalCheck(aEvent) + { + //////////////////////////////////////////////////////////////////////// + // 'labelled by'/'label for' relations for xul:tab and xul:tabpanel + + var tabs = Array.from(tabBrowser().tabContainer.allTabs); + // For preloaded tabs, there might be items in this array where this relation + // doesn't hold, so just deal with that: + var panels = tabs.map(t => t.linkedBrowser.closest("tabpanels > *")); + + testRelation(panels[0], RELATION_LABELLED_BY, tabs[0]); + testRelation(tabs[0], RELATION_LABEL_FOR, panels[0]); + testRelation(panels[1], RELATION_LABELLED_BY, tabs[1]); + testRelation(tabs[1], RELATION_LABEL_FOR, panels[1]); + } + + this.getID = function testTabRelations_getID() + { + return "relations of tabs"; + } + } + + //////////////////////////////////////////////////////////////////////////// + // Test + + //gA11yEventDumpToConsole = true; // debug stuff + + var gQueue = null; + function doTest() + { + // Load documents into tabs and wait for DocLoadComplete events caused by + // these documents load before we start the test. + + gQueue = new eventQueue(); + + gQueue.push(new testTabRelations()); + gQueue.onFinish = function() { closeBrowserWindow(); } + gQueue.invoke(); // Will call SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + openBrowserWindow(doTest); + ]]> + </script> + + <vbox flex="1" style="overflow: auto;"> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=552944" + title="No relationship between tabs and associated property page in new tabbrowser construct"> + Mozilla Bug 552944 + </a><br/> + <p id="display"></p> + <div id="content" style="display: none"> + </div> + <pre id="test"> + </pre> + </body> + + <vbox id="eventdump"></vbox> + </vbox> + +</window> + diff --git a/accessible/tests/mochitest/relations/test_tree.xhtml b/accessible/tests/mochitest/relations/test_tree.xhtml new file mode 100644 index 0000000000..7c309f0956 --- /dev/null +++ b/accessible/tests/mochitest/relations/test_tree.xhtml @@ -0,0 +1,105 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" + type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + title="Accessible XUL tree relations tests"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" /> + + <script type="application/javascript" + src="../treeview.js" /> + + <script type="application/javascript" + src="../common.js" /> + <script type="application/javascript" + src="../events.js" /> + <script type="application/javascript" + src="../relations.js" /> + + <script type="application/javascript"> + <![CDATA[ + //////////////////////////////////////////////////////////////////////////// + // Test + + function doTest() + { + var treeNode = getNode("tree"); + + var tree = getAccessible(treeNode); + var treeitem1 = tree.firstChild.nextSibling; + testRelation(treeitem1, RELATION_NODE_CHILD_OF, [tree]); + + var treeitem2 = treeitem1.nextSibling; + testRelation(treeitem2, RELATION_NODE_CHILD_OF, [tree]); + + var treeitem3 = treeitem2.nextSibling; + testRelation(treeitem3, RELATION_NODE_CHILD_OF, [treeitem2]); + + var treeitem4 = treeitem3.nextSibling; + testRelation(treeitem4, RELATION_NODE_CHILD_OF, [treeitem2]); + + var treeitem5 = treeitem4.nextSibling; + testRelation(treeitem5, RELATION_NODE_CHILD_OF, [tree]); + + var treeitem6 = treeitem5.nextSibling; + testRelation(treeitem6, RELATION_NODE_CHILD_OF, [tree]); + + testRelation(tree, RELATION_NODE_PARENT_OF, + [treeitem1, treeitem2, treeitem5, treeitem6]); + testRelation(treeitem2, RELATION_NODE_PARENT_OF, + [treeitem3, treeitem4]); + + // treeitems and treecells shouldn't pick up relations from tree + testRelation(treeitem1, RELATION_LABELLED_BY, null); + testRelation(treeitem1.firstChild, RELATION_LABELLED_BY, null); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yXULTreeLoadEvent(doTest, "tree", new nsTreeTreeView()); + ]]> + </script> + + <hbox flex="1" style="overflow: auto;"> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=503727" + title="Reorganize implementation of XUL tree accessibility"> + Bug 503727 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=527461" + title="Implement RELATION_NODE_PARENT_OF"> + Bug 527461 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=691248" + title="XUL tree items shouldn't pick up relations from XUL tree"> + Bug 691248 + </a> + <p id="display"></p> + <div id="content" style="display: none"> + </div> + <pre id="test"> + </pre> + </body> + + <vbox flex="1"> + <label control="tree" value="It's a tree"/> + <tree id="tree" flex="1"> + <treecols> + <treecol id="col" flex="1" primary="true" label="column"/> + <treecol id="col2" flex="1" label="column2"/> + </treecols> + <treechildren/> + </tree> + + <vbox id="debug"/> + </vbox> + </hbox> + +</window> + diff --git a/accessible/tests/mochitest/relations/test_ui_modalprompt.html b/accessible/tests/mochitest/relations/test_ui_modalprompt.html new file mode 100644 index 0000000000..a05b273d86 --- /dev/null +++ b/accessible/tests/mochitest/relations/test_ui_modalprompt.html @@ -0,0 +1,111 @@ +<html> + +<head> + <title>Modal prompts</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../relations.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../events.js"></script> + <script type="application/javascript" + src="../browser.js"></script> + + <script type="application/javascript"> + SpecialPowers.pushPrefEnv({ + set: [["prompts.contentPromptSubDialog", false]], + }); + function showAlert() { + this.eventSeq = [ + { + type: EVENT_SHOW, + match(aEvent) { + return aEvent.accessible.role == ROLE_DIALOG; + }, + }, + ]; + + this.invoke = function showAlert_invoke() { + window.setTimeout( + function() { + currentTabDocument().defaultView.alert("hello"); + }, 0); + }; + + this.check = function showAlert_finalCheck(aEvent) { + if(aEvent.type === EVENT_HIDE) { + return; + } + var dialog = aEvent.accessible.DOMNode; + var info = dialog.querySelector(".tabmodalprompt-infoBody"); + testRelation(info, RELATION_DESCRIPTION_FOR, dialog); + testRelation(dialog, RELATION_DESCRIBED_BY, info); + }; + + this.getID = function showAlert_getID() { + return "show alert"; + }; + } + + function closeAlert() { + this.eventSeq = [ + { + type: EVENT_HIDE, + match(aEvent) { + return aEvent.accessible.role == ROLE_DIALOG; + }, + }, + ]; + + this.invoke = function showAlert_invoke() { + synthesizeKey("VK_RETURN", {}, browserWindow()); + }; + + this.getID = function showAlert_getID() { + return "cleanup alert"; + }; + } + + + // gA11yEventDumpToConsole = true; // debug + + var gQueue = null; + function doTests() { + gQueue = new eventQueue(); + gQueue.push(new showAlert()); + gQueue.push(new closeAlert()); + gQueue.onFinish = function() { + closeBrowserWindow(); + }; + gQueue.invoke(); // will call SimpleTest.finish() + } + + SimpleTest.waitForExplicitFinish(); + openBrowserWindow(doTests); + </script> + +</head> + +<body id="body"> + + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=661293" + title="The tabmodalprompt dialog's prompt label doesn't get the text properly associated for accessibility"> + Mozilla Bug 661293 + </a> + <br> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + +</body> +</html> diff --git a/accessible/tests/mochitest/relations/test_update.html b/accessible/tests/mochitest/relations/test_update.html new file mode 100644 index 0000000000..581d592bec --- /dev/null +++ b/accessible/tests/mochitest/relations/test_update.html @@ -0,0 +1,213 @@ +<html> + +<head> + <title>Test updating of accessible relations</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../relations.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../events.js"></script> + + <script type="application/javascript"> + function testRelated(aRelAttr, aHostRelation, aDependentRelation, + aHostID, aHostNodeID, aDependent1ID, aDependent2ID) { + // no attribute + testRelation(aDependent1ID, aDependentRelation, null); + testRelation(aDependent2ID, aDependentRelation, null); + if (aHostRelation) + testRelation(aHostID, aHostRelation, null); + + // set attribute + getNode(aHostNodeID).setAttribute(aRelAttr, aDependent1ID); + testRelation(aDependent1ID, aDependentRelation, aHostID); + testRelation(aDependent2ID, aDependentRelation, null); + if (aHostRelation) + testRelation(aHostID, aHostRelation, aDependent1ID); + + // change attribute + getNode(aHostNodeID).setAttribute(aRelAttr, aDependent2ID); + testRelation(aDependent1ID, aDependentRelation, null); + testRelation(aDependent2ID, aDependentRelation, aHostID); + if (aHostRelation) + testRelation(aHostID, aHostRelation, aDependent2ID); + + // remove attribute + getNode(aHostNodeID).removeAttribute(aRelAttr); + testRelation(aDependent1ID, aDependentRelation, null); + testRelation(aDependent2ID, aDependentRelation, null); + if (aHostRelation) + testRelation(aHostID, aHostRelation, null); + } + + function insertRelated(aHostRelAttr, aDependentID, aInsertHostFirst, + aHostRelation, aDependentRelation) { + this.eventSeq = [ + new invokerChecker(EVENT_REORDER, document), + ]; + + this.invoke = function insertRelated_invoke() { + this.hostNode = document.createElement("div"); + this.hostNode.setAttribute(aHostRelAttr, aDependentID); + + this.dependentNode = document.createElement("div"); + this.dependentNode.setAttribute("id", aDependentID); + + if (aInsertHostFirst) { + document.body.appendChild(this.hostNode); + document.body.appendChild(this.dependentNode); + } else { + document.body.appendChild(this.dependentNode); + document.body.appendChild(this.hostNode); + } + }; + + this.finalCheck = function insertRelated_finalCheck() { + testRelation(this.dependentNode, aDependentRelation, this.hostNode); + if (aHostRelation) + testRelation(this.hostNode, aHostRelation, this.dependentNode); + }; + + this.getID = function insertRelated_getID() { + return "Insert " + aHostRelAttr + "='" + aDependentID + "' node" + + (aInsertHostFirst ? " before" : "after") + " dependent node"; + }; + } + + /** + * Relative accessible recreation shouldn't break accessible relations. + * Note: modify this case if the invoke function doesn't change accessible + * tree due to changes in layout module. It can be changed on any case + * when accessibles are recreated. + */ + function recreateRelatives(aContainerID, aLabelID, aElmID) { + this.containerNode = getNode(aContainerID); + this.container = getNode(this.containerNode); + + this.eventSeq = [ + new invokerChecker(EVENT_HIDE, this.container), + new invokerChecker(EVENT_SHOW, this.containerNode), + ]; + + this.invoke = function recreateRelatives_invoke() { + testRelation(aLabelID, RELATION_LABEL_FOR, aElmID); + testRelation(aElmID, RELATION_LABELLED_BY, aLabelID); + + this.containerNode.setAttribute('role', 'group'); + }; + + this.finalCheck = function recreateRelatives_finalCheck() { + testRelation(aLabelID, RELATION_LABEL_FOR, aElmID); + testRelation(aElmID, RELATION_LABELLED_BY, aLabelID); + }; + + this.getID = function recreateRelatives_getID() { + return "recreate relatives "; + }; + } + + // gA11yEventDumpToConsole = true; // debug + + var gQueue = null; + + function doTest() { + // Relation updates on ARIA attribute changes. + testRelated("aria-labelledby", + RELATION_LABELLED_BY, RELATION_LABEL_FOR, + "host", "host", "dependent1", "dependent2"); + + testRelated("aria-describedby", + RELATION_DESCRIBED_BY, RELATION_DESCRIPTION_FOR, + "host", "host", "dependent1", "dependent2"); + + testRelated("aria-controls", + RELATION_CONTROLLER_FOR, RELATION_CONTROLLED_BY, + "host", "host", "dependent1", "dependent2"); + + testRelated("aria-flowto", + RELATION_FLOWS_TO, RELATION_FLOWS_FROM, + "host", "host", "dependent1", "dependent2"); + + // Document relation updates on ARIA attribute change. + testRelated("aria-labelledby", + RELATION_LABELLED_BY, RELATION_LABEL_FOR, + document, "body", "dependent1", "dependent2"); + + // Insert related accessibles into tree. + gQueue = new eventQueue(); + gQueue.push(new insertRelated("aria-labelledby", "dependent3", true, + RELATION_LABELLED_BY, RELATION_LABEL_FOR)); + gQueue.push(new insertRelated("aria-labelledby", "dependent4", false, + RELATION_LABELLED_BY, RELATION_LABEL_FOR)); + + gQueue.push(new insertRelated("aria-describedby", "dependent5", true, + RELATION_DESCRIBED_BY, + RELATION_DESCRIPTION_FOR)); + gQueue.push(new insertRelated("aria-describedby", "dependent6", false, + RELATION_DESCRIBED_BY, + RELATION_DESCRIPTION_FOR)); + + gQueue.push(new insertRelated("aria-controls", "dependent9", true, + RELATION_CONTROLLER_FOR, + RELATION_CONTROLLED_BY)); + gQueue.push(new insertRelated("aria-controls", "dependent10", false, + RELATION_CONTROLLER_FOR, + RELATION_CONTROLLED_BY)); + + gQueue.push(new insertRelated("aria-flowto", "dependent11", true, + RELATION_FLOWS_TO, RELATION_FLOWS_FROM)); + gQueue.push(new insertRelated("aria-flowto", "dependent12", false, + RELATION_FLOWS_TO, RELATION_FLOWS_FROM)); + + // Update relations when accessibles are recreated + gQueue.push(new recreateRelatives("container", "label", "input")); + + gQueue.invoke(); // will call SimpleTest.finish() + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> + +<body id="body"> + + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=573469" + title="Cache relations defined by ARIA attributes"> + Mozilla Bug 573469 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=631068" + title="Accessible recreation breaks relations"> + Mozilla Bug 631068 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=635346" + title="Allow relations for document defined on document content"> + Mozilla Bug 635346 + </a> + <br> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <div id="dependent1">label</div> + <div id="dependent2">label2</div> + <div role="checkbox" id="host"></div> + + <form id="container" style="overflow: hidden;"> + <label for="input" id="label">label</label> + <input id="input"> + </form> +</body> +</html> |