gecko-dev/accessible/tests/mochitest/attributes.js

383 lines
11 KiB
JavaScript

////////////////////////////////////////////////////////////////////////////////
// Object attributes.
/**
* Test object attributes.
*
* @param aAccOrElmOrID [in] the accessible identifier
* @param aAttrs [in] the map of expected object attributes
* (name/value pairs)
* @param aSkipUnexpectedAttrs [in] points this function doesn't fail if
* unexpected attribute is encountered
*/
function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs)
{
testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs);
}
/**
* Test object attributes that must not be present.
*
* @param aAccOrElmOrID [in] the accessible identifier
* @param aAbsentAttrs [in] map of attributes that should not be
* present (name/value pairs)
*/
function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs)
{
testAttrsInternal(aAccOrElmOrID, {}, true, aAbsentAttrs);
}
/**
* Test CSS based object attributes.
*/
function testCSSAttrs(aID)
{
var node = document.getElementById(aID);
var computedStyle = document.defaultView.getComputedStyle(node, "");
var attrs = {
"display": computedStyle.display,
"text-align": computedStyle.textAlign,
"text-indent": computedStyle.textIndent,
"margin-left": computedStyle.marginLeft,
"margin-right": computedStyle.marginRight,
"margin-top": computedStyle.marginTop,
"margin-bottom": computedStyle.marginBottom
};
testAttrs(aID, attrs, true);
}
/**
* Test the accessible that it doesn't have CSS-based object attributes.
*/
function testAbsentCSSAttrs(aID)
{
var attrs = {
"display": "",
"text-align": "",
"text-indent": "",
"margin-left": "",
"margin-right": "",
"margin-top": "",
"margin-bottom": ""
};
testAbsentAttrs(aID, attrs);
}
/**
* Test group object attributes (posinset, setsize and level) and
* nsIAccessible::groupPosition() method.
*
* @param aAccOrElmOrID [in] the ID, DOM node or accessible
* @param aPosInSet [in] the value of 'posinset' attribute
* @param aSetSize [in] the value of 'setsize' attribute
* @param aLevel [in, optional] the value of 'level' attribute
*/
function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
{
var acc = getAccessible(aAccOrElmOrID);
var levelObj = {}, posInSetObj = {}, setSizeObj = {};
acc.groupPosition(levelObj, setSizeObj, posInSetObj);
if (aPosInSet && aSetSize) {
is(posInSetObj.value, aPosInSet,
"Wrong group position (posinset) for " + prettyName(aAccOrElmOrID));
is(setSizeObj.value, aSetSize,
"Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID));
var attrs = {
"posinset": String(aPosInSet),
"setsize": String(aSetSize)
};
testAttrs(aAccOrElmOrID, attrs, true);
}
if (aLevel) {
is(levelObj.value, aLevel,
"Wrong group level for " + prettyName(aAccOrElmOrID));
var attrs = { "level" : String(aLevel) };
testAttrs(aAccOrElmOrID, attrs, true);
}
}
////////////////////////////////////////////////////////////////////////////////
// Text attributes.
/**
* Test text attributes.
*
* @param aID [in] the ID of DOM element having text
* accessible
* @param aOffset [in] the offset inside text accessible to fetch
* text attributes
* @param aAttrs [in] the map of expected text attributes
* (name/value pairs) exposed at the offset
* @param aDefAttrs [in] the map of expected text attributes
* (name/value pairs) exposed on hyper text
* accessible
* @param aStartOffset [in] expected start offset where text attributes
* are applied
* @param aEndOffset [in] expected end offset where text attribute
* are applied
* @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
* unexpected attribute is encountered
*/
function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
aStartOffset, aEndOffset, aSkipUnexpectedAttrs)
{
var accessible = getAccessible(aID, [nsIAccessibleText]);
if (!accessible)
return;
var startOffset = { value: -1 };
var endOffset = { value: -1 };
// do not include attributes exposed on hyper text accessbile
var attrs = getTextAttributes(aID, accessible, false, aOffset,
startOffset, endOffset);
if (!attrs)
return;
var errorMsg = " for " + aID + " at offset " + aOffset;
is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg);
is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg);
compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
// include attributes exposed on hyper text accessbile
var expectedAttrs = {};
for (var name in aAttrs)
expectedAttrs[name] = aAttrs[name];
for (var name in aDefAttrs) {
if (!(name in expectedAttrs))
expectedAttrs[name] = aDefAttrs[name];
}
attrs = getTextAttributes(aID, accessible, true, aOffset,
startOffset, endOffset);
if (!attrs)
return;
compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs);
}
/**
* Test default text attributes.
*
* @param aID [in] the ID of DOM element having text
* accessible
* @param aDefAttrs [in] the map of expected text attributes
* (name/value pairs)
* @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
* unexpected attribute is encountered
*/
function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs)
{
var accessible = getAccessible(aID, [nsIAccessibleText]);
if (!accessible)
return;
var defAttrs = null;
try{
defAttrs = accessible.defaultTextAttributes;
} catch (e) {
}
if (!defAttrs) {
ok(false, "Can't get default text attributes for " + aID);
return;
}
var errorMsg = ". Getting default text attributes for " + aID;
compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs);
}
/**
* Test text attributes for wrong offset.
*/
function testTextAttrsWrongOffset(aID, aOffset)
{
var res = false;
try {
var s = {}, e = {};
var acc = getAccessible(ID, [nsIAccessibleText]);
acc.getTextAttributes(false, 157, s, e);
} catch (e) {
res = true;
}
ok(res,
"text attributes are calculated successfully at wrong offset " + aOffset + " for " + prettyName(aID));
}
const kNormalFontWeight =
function equalsToNormal(aWeight) { return aWeight <= 400 ; }
const kBoldFontWeight =
function equalsToBold(aWeight) { return aWeight > 400; }
// The pt font size of the input element can vary by Linux distro.
const kInputFontSize = WIN ?
"10pt" : (MAC ? "8pt" : function() { return true; });
const kAbsentFontFamily =
function(aFontFamily) { return aFontFamily != "sans-serif"; }
const kInputFontFamily =
function(aFontFamily) { return aFontFamily != "sans-serif"; }
const kMonospaceFontFamily =
function(aFontFamily) { return aFontFamily != "monospace"; }
const kSansSerifFontFamily =
function(aFontFamily) { return aFontFamily != "sans-serif"; }
const kSerifFontFamily =
function(aFontFamily) { return aFontFamily != "serif"; }
const kCursiveFontFamily = LINUX ? "DejaVu Serif" : "Comic Sans MS";
/**
* Return used font from the given computed style.
*/
function fontFamily(aComputedStyle)
{
var name = aComputedStyle.fontFamily;
switch (name) {
case "monospace":
return kMonospaceFontFamily;
case "sans-serif":
return kSansSerifFontFamily;
case "serif":
return kSerifFontFamily;
default:
return name;
}
}
/**
* Build an object of default text attributes expected for the given accessible.
*
* @param aID [in] identifier of accessible
* @param aFontSize [in] font size
* @param aFontWeight [in, optional] kBoldFontWeight or kNormalFontWeight,
* default value is kNormalFontWeight
*/
function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily)
{
var elm = getNode(aID);
var computedStyle = document.defaultView.getComputedStyle(elm, "");
var bgColor = computedStyle.backgroundColor == "transparent" ?
"rgb(255, 255, 255)" : computedStyle.backgroundColor;
var defAttrs = {
"font-style": computedStyle.fontStyle,
"font-size": aFontSize,
"background-color": bgColor,
"font-weight": aFontWeight ? aFontWeight : kNormalFontWeight,
"color": computedStyle.color,
"font-family": aFontFamily ? aFontFamily : fontFamily(computedStyle),
"text-position": computedStyle.verticalAlign
};
return defAttrs;
}
////////////////////////////////////////////////////////////////////////////////
// Private.
function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset,
aStartOffset, aEndOffset)
{
// This function expects the passed in accessible to already be queried for
// nsIAccessibleText.
var attrs = null;
try {
attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset,
aStartOffset, aEndOffset);
} catch (e) {
}
if (attrs)
return attrs;
ok(false, "Can't get text attributes for " + aID);
return null;
}
function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs,
aAbsentAttrs)
{
var accessible = getAccessible(aAccOrElmOrID);
if (!accessible)
return;
var attrs = null;
try {
attrs = accessible.attributes;
} catch (e) { }
if (!attrs) {
ok(false, "Can't get object attributes for " + prettyName(aAccOrElmOrID));
return;
}
var errorMsg = " for " + prettyName(aAccOrElmOrID);
compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs);
}
function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
aAbsentAttrs)
{
// Check if all obtained attributes are expected and have expected value.
var enumerate = aAttrs.enumerate();
while (enumerate.hasMoreElements()) {
var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
if (!(prop.key in aExpectedAttrs)) {
if (!aSkipUnexpectedAttrs)
ok(false, "Unexpected attribute '" + prop.key + "' having '" +
prop.value + "'" + aErrorMsg);
} else {
var msg = "Attribute '" + prop.key + "' has wrong value" + aErrorMsg;
var expectedValue = aExpectedAttrs[prop.key];
if (typeof expectedValue == "function")
ok(expectedValue(prop.value), msg);
else
is(prop.value, expectedValue, msg);
}
}
// Check if all expected attributes are presented.
for (var name in aExpectedAttrs) {
var value = "";
try {
value = aAttrs.getStringProperty(name);
} catch(e) { }
if (!value)
ok(false,
"There is no expected attribute '" + name + "' " + aErrorMsg);
}
// Check if all unexpected attributes are absent.
if (aAbsentAttrs) {
for (var name in aAbsentAttrs) {
var wasFound = false;
var enumerate = aAttrs.enumerate();
while (enumerate.hasMoreElements()) {
var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
if (prop.key == name)
wasFound = true;
}
}
ok(!wasFound,
"There is an unexpected attribute '" + name + "' " + aErrorMsg);
}
}