gecko/accessible/tests/mochitest/name/markup.js

383 lines
10 KiB
JavaScript

////////////////////////////////////////////////////////////////////////////////
// Name tests described by "markuprules.xml" file.
var gNameRulesFileURL = "markuprules.xml";
var gRuleDoc = null;
// Debuggin stuff.
var gDumpToConsole = false;
/**
* Start name tests. Run through markup elements and test names for test
* element (see namerules.xml for details).
*/
function testNames()
{
//enableLogging("tree,stack"); // debugging
var request = new XMLHttpRequest();
request.open("get", gNameRulesFileURL, false);
request.send();
gRuleDoc = request.responseXML;
var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
gTestIterator.iterateMarkups(markupElms);
}
////////////////////////////////////////////////////////////////////////////////
// Private section.
/**
* Helper class to interate through name tests.
*/
var gTestIterator =
{
iterateMarkups: function gTestIterator_iterateMarkups(aMarkupElms)
{
this.markupElms = aMarkupElms;
this.iterateNext();
},
iterateRules: function gTestIterator_iterateRules(aElm, aContainer,
aRuleSetElm, aRuleElms,
aTestID)
{
this.ruleSetElm = aRuleSetElm;
this.ruleElms = aRuleElms;
this.elm = aElm;
this.container = aContainer;
this.testID = aTestID;
this.iterateNext();
},
iterateNext: function gTestIterator_iterateNext()
{
if (this.markupIdx == -1) {
this.markupIdx++;
testNamesForMarkup(this.markupElms[this.markupIdx]);
return;
}
this.ruleIdx++;
if (this.ruleIdx == this.ruleElms.length) {
// When test is finished then name is empty and no explict-name.
var defaultName = this.ruleSetElm.hasAttribute("defaultName") ?
this.ruleSetElm.getAttribute("defaultName") : null;
testName(this.elm, defaultName,
"Default name test (" + gTestIterator.testID + "). ");
testAbsentAttrs(this.elm, {"explicit-name" : "true"});
this.markupIdx++;
if (this.markupIdx == this.markupElms.length) {
//disableLogging("tree"); // debugging
SimpleTest.finish();
return;
}
this.ruleIdx = -1;
if (gDumpToConsole) {
dump("\nPend next markup processing. Wait for reorder event on " +
prettyName(document) + "'\n");
}
waitForEvent(EVENT_REORDER, document, testNamesForMarkup,
null, this.markupElms[this.markupIdx]);
document.body.removeChild(this.container);
return;
}
testNameForRule(this.elm, this.ruleElms[this.ruleIdx]);
},
markupElms: null,
markupIdx: -1,
rulesetElm: null,
ruleElms: null,
ruleIdx: -1,
elm: null,
container: null,
testID: ""
};
/**
* Process every 'markup' element and test names for it. Used by testNames
* function.
*/
function testNamesForMarkup(aMarkupElm)
{
if (gDumpToConsole)
dump("\nProcessing markup '" + aMarkupElm.getAttribute("id") + "'\n");
var div = document.createElement("div");
div.setAttribute("id", "test");
var child = aMarkupElm.firstChild;
while (child) {
var newChild = document.importNode(child, true);
div.appendChild(newChild);
child = child.nextSibling;
}
if (gDumpToConsole) {
dump("\nProcessing markup. Wait for reorder event on " +
prettyName(document) + "'\n");
}
waitForEvent(EVENT_REORDER, document, testNamesForMarkupRules,
null, aMarkupElm, div);
document.body.appendChild(div);
}
function testNamesForMarkupRules(aMarkupElm, aContainer)
{
var testID = aMarkupElm.getAttribute("id");
if (gDumpToConsole)
dump("\nProcessing markup rules '" + testID + "'\n");
var serializer = new XMLSerializer();
var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref");
var elm = evaluateXPath(document, expr, htmlDocResolver)[0];
var ruleId = aMarkupElm.getAttribute("ruleset");
var ruleElm = gRuleDoc.querySelector("[id='" + ruleId + "']");
var ruleElms = getRuleElmsByRulesetId(ruleId);
var processMarkupRules =
gTestIterator.iterateRules.bind(gTestIterator, elm, aContainer,
ruleElm, ruleElms, testID);
// Images may be recreated after we append them into subtree. We need to wait
// in this case. If we are on profiling enabled build then stack tracing
// works and thus let's log instead. Note, that works if you enabled logging
// (refer to testNames() function).
if (isAccessible(elm) || isLogged("stack"))
processMarkupRules();
else
waitForEvent(EVENT_SHOW, elm, processMarkupRules);
}
/**
* Test name for current rule and current 'markup' element. Used by
* testNamesForMarkup function.
*/
function testNameForRule(aElm, aRuleElm)
{
if (aRuleElm.hasAttribute("attr")) {
if (gDumpToConsole) {
dump("\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") +" }\n");
}
testNameForAttrRule(aElm, aRuleElm);
} else if (aRuleElm.hasAttribute("elm")) {
if (gDumpToConsole) {
dump("\nProcessing rule { elm: " + aRuleElm.getAttribute("elm") +
", elmattr: " + aRuleElm.getAttribute("elmattr") +" }\n");
}
testNameForElmRule(aElm, aRuleElm);
} else if (aRuleElm.getAttribute("fromsubtree") == "true") {
if (gDumpToConsole) {
dump("\nProcessing rule { fromsubtree: " +
aRuleElm.getAttribute("fromsubtree") +" }\n");
}
testNameForSubtreeRule(aElm, aRuleElm);
}
}
function testNameForAttrRule(aElm, aRule)
{
var name = "";
var attr = aRule.getAttribute("attr");
var attrValue = aElm.getAttribute(attr);
var type = aRule.getAttribute("type");
if (type == "string") {
name = attrValue;
} else if (type == "ref" && attrValue) {
var ids = attrValue.split(/\s+/);
for (var idx = 0; idx < ids.length; idx++) {
var labelElm = getNode(ids[idx]);
if (name != "")
name += " ";
name += labelElm.getAttribute("textequiv");
}
}
var msg = "Attribute '" + attr + "' test (" + gTestIterator.testID + "). ";
testName(aElm, name, msg);
if (aRule.getAttribute("explict-name") != "false")
testAttrs(aElm, {"explicit-name" : "true"}, true);
else
testAbsentAttrs(aElm, {"explicit-name" : "true"});
// If @recreated attribute is used then this attribute change recreates an
// accessible. Wait for reorder event in this case or otherwise proceed next
// test immediately.
if (aRule.hasAttribute("recreated")) {
waitForEvent(EVENT_REORDER, aElm.parentNode,
gTestIterator.iterateNext, gTestIterator);
aElm.removeAttribute(attr);
} else if (aRule.hasAttribute("textchanged")) {
waitForEvent(EVENT_TEXT_INSERTED, aElm,
gTestIterator.iterateNext, gTestIterator);
aElm.removeAttribute(attr);
} else if (aRule.hasAttribute("contentchanged")) {
waitForEvent(EVENT_REORDER, aElm,
gTestIterator.iterateNext, gTestIterator);
aElm.removeAttribute(attr);
} else {
aElm.removeAttribute(attr);
gTestIterator.iterateNext();
}
}
function testNameForElmRule(aElm, aRule)
{
var labelElm;
var tagname = aRule.getAttribute("elm");
var attrname = aRule.getAttribute("elmattr");
if (attrname) {
var filter = {
acceptNode: function filter_acceptNode(aNode)
{
if (aNode.localName == this.mLocalName &&
aNode.getAttribute(this.mAttrName) == this.mAttrValue)
return NodeFilter.FILTER_ACCEPT;
return NodeFilter.FILTER_SKIP;
},
mLocalName: tagname,
mAttrName: attrname,
mAttrValue: aElm.getAttribute("id")
};
var treeWalker = document.createTreeWalker(document.body,
NodeFilter.SHOW_ELEMENT,
filter);
labelElm = treeWalker.nextNode();
} else {
// if attrname is empty then look for the element in subtree.
labelElm = aElm.getElementsByTagName(tagname)[0];
if (!labelElm)
labelElm = aElm.getElementsByTagName("html:" + tagname)[0];
}
if (!labelElm) {
ok(false, msg + " Failed to find '" + tagname + "' element.");
gTestIterator.iterateNext();
return;
}
var msg = "Element '" + tagname + "' test (" + gTestIterator.testID + ").";
testName(aElm, labelElm.getAttribute("textequiv"), msg);
testAttrs(aElm, {"explicit-name" : "true"}, true);
var parentNode = labelElm.parentNode;
if (gDumpToConsole) {
dump("\nProcessed elm rule. Wait for reorder event on " +
prettyName(parentNode) + "\n");
}
waitForEvent(EVENT_REORDER, parentNode,
gTestIterator.iterateNext, gTestIterator);
parentNode.removeChild(labelElm);
}
function testNameForSubtreeRule(aElm, aRule)
{
var msg = "From subtree test (" + gTestIterator.testID + ").";
testName(aElm, aElm.getAttribute("textequiv"), msg);
testAbsentAttrs(aElm, {"explicit-name" : "true"});
if (gDumpToConsole) {
dump("\nProcessed from subtree rule. Wait for reorder event on " +
prettyName(aElm) + "\n");
}
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
while (aElm.firstChild)
aElm.removeChild(aElm.firstChild);
}
/**
* Return array of 'rule' elements. Used in conjunction with
* getRuleElmsFromRulesetElm() function.
*/
function getRuleElmsByRulesetId(aRulesetId)
{
var expr = "//rules/ruledfn/ruleset[@id='" + aRulesetId + "']";
var rulesetElm = evaluateXPath(gRuleDoc, expr);
return getRuleElmsFromRulesetElm(rulesetElm[0]);
}
function getRuleElmsFromRulesetElm(aRulesetElm)
{
var rulesetId = aRulesetElm.getAttribute("ref");
if (rulesetId)
return getRuleElmsByRulesetId(rulesetId);
var ruleElms = [];
var child = aRulesetElm.firstChild;
while (child) {
if (child.localName == "ruleset")
ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
if (child.localName == "rule")
ruleElms.push(child);
child = child.nextSibling;
}
return ruleElms;
}
/**
* Helper method to evaluate xpath expression.
*/
function evaluateXPath(aNode, aExpr, aResolver)
{
var xpe = new XPathEvaluator();
var resolver = aResolver;
if (!resolver) {
var node = aNode.ownerDocument == null ?
aNode.documentElement : aNode.ownerDocument.documentElement;
resolver = xpe.createNSResolver(node);
}
var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
var found = [];
var res;
while (res = result.iterateNext())
found.push(res);
return found;
}
function htmlDocResolver(aPrefix) {
var ns = {
'html' : 'http://www.w3.org/1999/xhtml'
};
return ns[aPrefix] || null;
}