accessible/tests/mochitest/common.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 ////////////////////////////////////////////////////////////////////////////////
michael@0 2 // Interfaces
michael@0 3
michael@0 4 const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
michael@0 5
michael@0 6 const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
michael@0 7 const nsIAccessibleStateChangeEvent =
michael@0 8 Components.interfaces.nsIAccessibleStateChangeEvent;
michael@0 9 const nsIAccessibleCaretMoveEvent =
michael@0 10 Components.interfaces.nsIAccessibleCaretMoveEvent;
michael@0 11 const nsIAccessibleTextChangeEvent =
michael@0 12 Components.interfaces.nsIAccessibleTextChangeEvent;
michael@0 13 const nsIAccessibleVirtualCursorChangeEvent =
michael@0 14 Components.interfaces.nsIAccessibleVirtualCursorChangeEvent;
michael@0 15
michael@0 16 const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates;
michael@0 17 const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
michael@0 18 const nsIAccessibleScrollType = Components.interfaces.nsIAccessibleScrollType;
michael@0 19 const nsIAccessibleCoordinateType = Components.interfaces.nsIAccessibleCoordinateType;
michael@0 20
michael@0 21 const nsIAccessibleRelation = Components.interfaces.nsIAccessibleRelation;
michael@0 22
michael@0 23 const nsIAccessible = Components.interfaces.nsIAccessible;
michael@0 24
michael@0 25 const nsIAccessibleDocument = Components.interfaces.nsIAccessibleDocument;
michael@0 26 const nsIAccessibleApplication = Components.interfaces.nsIAccessibleApplication;
michael@0 27
michael@0 28 const nsIAccessibleText = Components.interfaces.nsIAccessibleText;
michael@0 29 const nsIAccessibleEditableText = Components.interfaces.nsIAccessibleEditableText;
michael@0 30
michael@0 31 const nsIAccessibleHyperLink = Components.interfaces.nsIAccessibleHyperLink;
michael@0 32 const nsIAccessibleHyperText = Components.interfaces.nsIAccessibleHyperText;
michael@0 33
michael@0 34 const nsIAccessibleCursorable = Components.interfaces.nsIAccessibleCursorable;
michael@0 35 const nsIAccessibleImage = Components.interfaces.nsIAccessibleImage;
michael@0 36 const nsIAccessiblePivot = Components.interfaces.nsIAccessiblePivot;
michael@0 37 const nsIAccessibleSelectable = Components.interfaces.nsIAccessibleSelectable;
michael@0 38 const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable;
michael@0 39 const nsIAccessibleTableCell = Components.interfaces.nsIAccessibleTableCell;
michael@0 40 const nsIAccessibleTraversalRule = Components.interfaces.nsIAccessibleTraversalRule;
michael@0 41 const nsIAccessibleValue = Components.interfaces.nsIAccessibleValue;
michael@0 42
michael@0 43 const nsIObserverService = Components.interfaces.nsIObserverService;
michael@0 44
michael@0 45 const nsIDOMDocument = Components.interfaces.nsIDOMDocument;
michael@0 46 const nsIDOMEvent = Components.interfaces.nsIDOMEvent;
michael@0 47 const nsIDOMHTMLDocument = Components.interfaces.nsIDOMHTMLDocument;
michael@0 48 const nsIDOMNode = Components.interfaces.nsIDOMNode;
michael@0 49 const nsIDOMHTMLElement = Components.interfaces.nsIDOMHTMLElement;
michael@0 50 const nsIDOMWindow = Components.interfaces.nsIDOMWindow;
michael@0 51 const nsIDOMXULElement = Components.interfaces.nsIDOMXULElement;
michael@0 52
michael@0 53 const nsIPropertyElement = Components.interfaces.nsIPropertyElement;
michael@0 54
michael@0 55 ////////////////////////////////////////////////////////////////////////////////
michael@0 56 // OS detect
michael@0 57
michael@0 58 const MAC = (navigator.platform.indexOf("Mac") != -1);
michael@0 59 const LINUX = (navigator.platform.indexOf("Linux") != -1);
michael@0 60 const SOLARIS = (navigator.platform.indexOf("SunOS") != -1);
michael@0 61 const WIN = (navigator.platform.indexOf("Win") != -1);
michael@0 62
michael@0 63 ////////////////////////////////////////////////////////////////////////////////
michael@0 64 // Application detect
michael@0 65 // Firefox is assumed by default.
michael@0 66
michael@0 67 const SEAMONKEY = navigator.userAgent.match(/ SeaMonkey\//);
michael@0 68
michael@0 69 ////////////////////////////////////////////////////////////////////////////////
michael@0 70 // Accessible general
michael@0 71
michael@0 72 const STATE_BUSY = nsIAccessibleStates.STATE_BUSY;
michael@0 73
michael@0 74 const SCROLL_TYPE_ANYWHERE = nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE;
michael@0 75
michael@0 76 const COORDTYPE_SCREEN_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE;
michael@0 77 const COORDTYPE_WINDOW_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE;
michael@0 78 const COORDTYPE_PARENT_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE;
michael@0 79
michael@0 80 const kEmbedChar = String.fromCharCode(0xfffc);
michael@0 81
michael@0 82 const kDiscBulletChar = String.fromCharCode(0x2022);
michael@0 83 const kDiscBulletText = kDiscBulletChar + " ";
michael@0 84 const kCircleBulletText = String.fromCharCode(0x25e6) + " ";
michael@0 85 const kSquareBulletText = String.fromCharCode(0x25aa) + " ";
michael@0 86
michael@0 87 const MAX_TRIM_LENGTH = 100;
michael@0 88
michael@0 89 /**
michael@0 90 * nsIAccessibleRetrieval service.
michael@0 91 */
michael@0 92 var gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
michael@0 93 getService(nsIAccessibleRetrieval);
michael@0 94
michael@0 95 /**
michael@0 96 * Enable/disable logging.
michael@0 97 */
michael@0 98 function enableLogging(aModules)
michael@0 99 {
michael@0 100 gAccRetrieval.setLogging(aModules);
michael@0 101 }
michael@0 102 function disableLogging()
michael@0 103 {
michael@0 104 gAccRetrieval.setLogging("");
michael@0 105 }
michael@0 106 function isLogged(aModule)
michael@0 107 {
michael@0 108 return gAccRetrieval.isLogged(aModule);
michael@0 109 }
michael@0 110
michael@0 111 /**
michael@0 112 * Invokes the given function when document is loaded and focused. Preferable
michael@0 113 * to mochitests 'addLoadEvent' function -- additionally ensures state of the
michael@0 114 * document accessible is not busy.
michael@0 115 *
michael@0 116 * @param aFunc the function to invoke
michael@0 117 */
michael@0 118 function addA11yLoadEvent(aFunc, aWindow)
michael@0 119 {
michael@0 120 function waitForDocLoad()
michael@0 121 {
michael@0 122 window.setTimeout(
michael@0 123 function()
michael@0 124 {
michael@0 125 var targetDocument = aWindow ? aWindow.document : document;
michael@0 126 var accDoc = getAccessible(targetDocument);
michael@0 127 var state = {};
michael@0 128 accDoc.getState(state, {});
michael@0 129 if (state.value & STATE_BUSY)
michael@0 130 return waitForDocLoad();
michael@0 131
michael@0 132 window.setTimeout(aFunc, 0);
michael@0 133 },
michael@0 134 0
michael@0 135 );
michael@0 136 }
michael@0 137
michael@0 138 SimpleTest.waitForFocus(waitForDocLoad, aWindow);
michael@0 139 }
michael@0 140
michael@0 141 /**
michael@0 142 * Analogy of SimpleTest.is function used to compare objects.
michael@0 143 */
michael@0 144 function isObject(aObj, aExpectedObj, aMsg)
michael@0 145 {
michael@0 146 if (aObj == aExpectedObj) {
michael@0 147 ok(true, aMsg);
michael@0 148 return;
michael@0 149 }
michael@0 150
michael@0 151 ok(false,
michael@0 152 aMsg + " - got '" + prettyName(aObj) +
michael@0 153 "', expected '" + prettyName(aExpectedObj) + "'");
michael@0 154 }
michael@0 155
michael@0 156 ////////////////////////////////////////////////////////////////////////////////
michael@0 157 // Helpers for getting DOM node/accessible
michael@0 158
michael@0 159 /**
michael@0 160 * Return the DOM node by identifier (may be accessible, DOM node or ID).
michael@0 161 */
michael@0 162 function getNode(aAccOrNodeOrID, aDocument)
michael@0 163 {
michael@0 164 if (!aAccOrNodeOrID)
michael@0 165 return null;
michael@0 166
michael@0 167 if (aAccOrNodeOrID instanceof nsIDOMNode)
michael@0 168 return aAccOrNodeOrID;
michael@0 169
michael@0 170 if (aAccOrNodeOrID instanceof nsIAccessible)
michael@0 171 return aAccOrNodeOrID.DOMNode;
michael@0 172
michael@0 173 node = (aDocument || document).getElementById(aAccOrNodeOrID);
michael@0 174 if (!node) {
michael@0 175 ok(false, "Can't get DOM element for " + aAccOrNodeOrID);
michael@0 176 return null;
michael@0 177 }
michael@0 178
michael@0 179 return node;
michael@0 180 }
michael@0 181
michael@0 182 /**
michael@0 183 * Constants indicates getAccessible doesn't fail if there is no accessible.
michael@0 184 */
michael@0 185 const DONOTFAIL_IF_NO_ACC = 1;
michael@0 186
michael@0 187 /**
michael@0 188 * Constants indicates getAccessible won't fail if accessible doesn't implement
michael@0 189 * the requested interfaces.
michael@0 190 */
michael@0 191 const DONOTFAIL_IF_NO_INTERFACE = 2;
michael@0 192
michael@0 193 /**
michael@0 194 * Return accessible for the given identifier (may be ID attribute or DOM
michael@0 195 * element or accessible object) or null.
michael@0 196 *
michael@0 197 * @param aAccOrElmOrID [in] identifier to get an accessible implementing
michael@0 198 * the given interfaces
michael@0 199 * @param aInterfaces [in, optional] the interface or an array interfaces
michael@0 200 * to query it/them from obtained accessible
michael@0 201 * @param aElmObj [out, optional] object to store DOM element which
michael@0 202 * accessible is obtained for
michael@0 203 * @param aDoNotFailIf [in, optional] no error for special cases (see
michael@0 204 * constants above)
michael@0 205 */
michael@0 206 function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf)
michael@0 207 {
michael@0 208 if (!aAccOrElmOrID)
michael@0 209 return null;
michael@0 210
michael@0 211 var elm = null;
michael@0 212
michael@0 213 if (aAccOrElmOrID instanceof nsIAccessible) {
michael@0 214 elm = aAccOrElmOrID.DOMNode;
michael@0 215
michael@0 216 } else if (aAccOrElmOrID instanceof nsIDOMNode) {
michael@0 217 elm = aAccOrElmOrID;
michael@0 218
michael@0 219 } else {
michael@0 220 elm = document.getElementById(aAccOrElmOrID);
michael@0 221 if (!elm) {
michael@0 222 ok(false, "Can't get DOM element for " + aAccOrElmOrID);
michael@0 223 return null;
michael@0 224 }
michael@0 225 }
michael@0 226
michael@0 227 if (aElmObj && (typeof aElmObj == "object"))
michael@0 228 aElmObj.value = elm;
michael@0 229
michael@0 230 var acc = (aAccOrElmOrID instanceof nsIAccessible) ? aAccOrElmOrID : null;
michael@0 231 if (!acc) {
michael@0 232 try {
michael@0 233 acc = gAccRetrieval.getAccessibleFor(elm);
michael@0 234 } catch (e) {
michael@0 235 }
michael@0 236
michael@0 237 if (!acc) {
michael@0 238 if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC))
michael@0 239 ok(false, "Can't get accessible for " + aAccOrElmOrID);
michael@0 240
michael@0 241 return null;
michael@0 242 }
michael@0 243 }
michael@0 244
michael@0 245 if (!aInterfaces)
michael@0 246 return acc;
michael@0 247
michael@0 248 if (!(aInterfaces instanceof Array))
michael@0 249 aInterfaces = [ aInterfaces ];
michael@0 250
michael@0 251 for (var index = 0; index < aInterfaces.length; index++) {
michael@0 252 try {
michael@0 253 acc.QueryInterface(aInterfaces[index]);
michael@0 254 } catch (e) {
michael@0 255 if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE))
michael@0 256 ok(false, "Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID);
michael@0 257
michael@0 258 return null;
michael@0 259 }
michael@0 260 }
michael@0 261
michael@0 262 return acc;
michael@0 263 }
michael@0 264
michael@0 265 /**
michael@0 266 * Return true if the given identifier has an accessible, or exposes the wanted
michael@0 267 * interfaces.
michael@0 268 */
michael@0 269 function isAccessible(aAccOrElmOrID, aInterfaces)
michael@0 270 {
michael@0 271 return getAccessible(aAccOrElmOrID, aInterfaces, null,
michael@0 272 DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE) ?
michael@0 273 true : false;
michael@0 274 }
michael@0 275
michael@0 276 /**
michael@0 277 * Return an accessible that contains the DOM node for the given identifier.
michael@0 278 */
michael@0 279 function getContainerAccessible(aAccOrElmOrID)
michael@0 280 {
michael@0 281 var node = getNode(aAccOrElmOrID);
michael@0 282 if (!node)
michael@0 283 return null;
michael@0 284
michael@0 285 while ((node = node.parentNode) && !isAccessible(node));
michael@0 286 return node ? getAccessible(node) : null;
michael@0 287 }
michael@0 288
michael@0 289 /**
michael@0 290 * Return root accessible for the given identifier.
michael@0 291 */
michael@0 292 function getRootAccessible(aAccOrElmOrID)
michael@0 293 {
michael@0 294 var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document);
michael@0 295 return acc ? acc.rootDocument.QueryInterface(nsIAccessible) : null;
michael@0 296 }
michael@0 297
michael@0 298 /**
michael@0 299 * Return tab document accessible the given accessible is contained by.
michael@0 300 */
michael@0 301 function getTabDocAccessible(aAccOrElmOrID)
michael@0 302 {
michael@0 303 var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document);
michael@0 304
michael@0 305 var docAcc = acc.document.QueryInterface(nsIAccessible);
michael@0 306 var containerDocAcc = docAcc.parent.document;
michael@0 307
michael@0 308 // Test is running is stand-alone mode.
michael@0 309 if (acc.rootDocument == containerDocAcc)
michael@0 310 return docAcc;
michael@0 311
michael@0 312 // In the case of running all tests together.
michael@0 313 return containerDocAcc.QueryInterface(nsIAccessible);
michael@0 314 }
michael@0 315
michael@0 316 /**
michael@0 317 * Return application accessible.
michael@0 318 */
michael@0 319 function getApplicationAccessible()
michael@0 320 {
michael@0 321 return gAccRetrieval.getApplicationAccessible().
michael@0 322 QueryInterface(nsIAccessibleApplication);
michael@0 323 }
michael@0 324
michael@0 325 /**
michael@0 326 * A version of accessible tree testing, doesn't fail if tree is not complete.
michael@0 327 */
michael@0 328 function testElm(aID, aTreeObj)
michael@0 329 {
michael@0 330 testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
michael@0 331 }
michael@0 332
michael@0 333 /**
michael@0 334 * Flags used for testAccessibleTree
michael@0 335 */
michael@0 336 const kSkipTreeFullCheck = 1;
michael@0 337
michael@0 338 /**
michael@0 339 * Compare expected and actual accessibles trees.
michael@0 340 *
michael@0 341 * @param aAccOrElmOrID [in] accessible identifier
michael@0 342 * @param aAccTree [in] JS object, each field corresponds to property of
michael@0 343 * accessible object. Additionally special properties
michael@0 344 * are presented:
michael@0 345 * children - an array of JS objects representing
michael@0 346 * children of accessible
michael@0 347 * states - an object having states and extraStates
michael@0 348 * fields
michael@0 349 * @param aFlags [in, optional] flags, see constants above
michael@0 350 */
michael@0 351 function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
michael@0 352 {
michael@0 353 var acc = getAccessible(aAccOrElmOrID);
michael@0 354 if (!acc)
michael@0 355 return;
michael@0 356
michael@0 357 var accTree = aAccTree;
michael@0 358
michael@0 359 // Support of simplified accessible tree object.
michael@0 360 var key = Object.keys(accTree)[0];
michael@0 361 var roleName = "ROLE_" + key;
michael@0 362 if (roleName in nsIAccessibleRole) {
michael@0 363 accTree = {
michael@0 364 role: nsIAccessibleRole[roleName],
michael@0 365 children: accTree[key]
michael@0 366 };
michael@0 367 }
michael@0 368
michael@0 369 // Test accessible properties.
michael@0 370 for (var prop in accTree) {
michael@0 371 var msg = "Wrong value of property '" + prop + "' for " + prettyName(acc) + ".";
michael@0 372
michael@0 373 switch (prop) {
michael@0 374 case "actions": {
michael@0 375 testActionNames(acc, accTree.actions);
michael@0 376 break;
michael@0 377 }
michael@0 378
michael@0 379 case "attributes":
michael@0 380 testAttrs(acc, accTree[prop], true);
michael@0 381 break;
michael@0 382
michael@0 383 case "absentAttributes":
michael@0 384 testAbsentAttrs(acc, accTree[prop]);
michael@0 385 break;
michael@0 386
michael@0 387 case "interfaces": {
michael@0 388 var ifaces = (accTree[prop] instanceof Array) ?
michael@0 389 accTree[prop] : [ accTree[prop] ];
michael@0 390 for (var i = 0; i < ifaces.length; i++) {
michael@0 391 ok((acc instanceof ifaces[i]),
michael@0 392 "No " + ifaces[i] + " interface on " + prettyName(acc));
michael@0 393 }
michael@0 394 break;
michael@0 395 }
michael@0 396
michael@0 397 case "relations": {
michael@0 398 for (var rel in accTree[prop])
michael@0 399 testRelation(acc, window[rel], accTree[prop][rel]);
michael@0 400 break;
michael@0 401 }
michael@0 402
michael@0 403 case "role":
michael@0 404 isRole(acc, accTree[prop], msg);
michael@0 405 break;
michael@0 406
michael@0 407 case "states":
michael@0 408 case "extraStates":
michael@0 409 case "absentStates":
michael@0 410 case "absentExtraStates": {
michael@0 411 testStates(acc, accTree["states"], accTree["extraStates"],
michael@0 412 accTree["absentStates"], accTree["absentExtraStates"]);
michael@0 413 break;
michael@0 414 }
michael@0 415
michael@0 416 case "tagName":
michael@0 417 is(accTree[prop], acc.DOMNode.tagName, msg);
michael@0 418 break;
michael@0 419
michael@0 420 case "textAttrs": {
michael@0 421 var prevOffset = -1;
michael@0 422 for (var offset in accTree[prop]) {
michael@0 423 if (prevOffset !=- 1) {
michael@0 424 var attrs = accTree[prop][prevOffset];
michael@0 425 testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, offset, true);
michael@0 426 }
michael@0 427 prevOffset = offset;
michael@0 428 }
michael@0 429
michael@0 430 if (prevOffset != -1) {
michael@0 431 var charCount = getAccessible(acc, [nsIAccessibleText]).characterCount;
michael@0 432 var attrs = accTree[prop][prevOffset];
michael@0 433 testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, charCount, true);
michael@0 434 }
michael@0 435
michael@0 436 break;
michael@0 437 }
michael@0 438
michael@0 439 default:
michael@0 440 if (prop.indexOf("todo_") == 0)
michael@0 441 todo(false, msg);
michael@0 442 else if (prop != "children")
michael@0 443 is(acc[prop], accTree[prop], msg);
michael@0 444 }
michael@0 445 }
michael@0 446
michael@0 447 // Test children.
michael@0 448 if ("children" in accTree && accTree["children"] instanceof Array) {
michael@0 449 var children = acc.children;
michael@0 450 var childCount = children.length;
michael@0 451
michael@0 452 is(childCount, accTree.children.length,
michael@0 453 "Different amount of expected children of " + prettyName(acc) + ".");
michael@0 454
michael@0 455 if (accTree.children.length == childCount) {
michael@0 456 if (aFlags & kSkipTreeFullCheck) {
michael@0 457 for (var i = 0; i < childCount; i++) {
michael@0 458 var child = children.queryElementAt(i, nsIAccessible);
michael@0 459 testAccessibleTree(child, accTree.children[i], aFlags);
michael@0 460 }
michael@0 461 return;
michael@0 462 }
michael@0 463
michael@0 464 // nsIAccessible::firstChild
michael@0 465 var expectedFirstChild = childCount > 0 ?
michael@0 466 children.queryElementAt(0, nsIAccessible) : null;
michael@0 467 var firstChild = null;
michael@0 468 try { firstChild = acc.firstChild; } catch (e) {}
michael@0 469 is(firstChild, expectedFirstChild,
michael@0 470 "Wrong first child of " + prettyName(acc));
michael@0 471
michael@0 472 // nsIAccessible::lastChild
michael@0 473 var expectedLastChild = childCount > 0 ?
michael@0 474 children.queryElementAt(childCount - 1, nsIAccessible) : null;
michael@0 475 var lastChild = null;
michael@0 476 try { lastChild = acc.lastChild; } catch (e) {}
michael@0 477 is(lastChild, expectedLastChild,
michael@0 478 "Wrong last child of " + prettyName(acc));
michael@0 479
michael@0 480 for (var i = 0; i < childCount; i++) {
michael@0 481 var child = children.queryElementAt(i, nsIAccessible);
michael@0 482
michael@0 483 // nsIAccessible::parent
michael@0 484 var parent = null;
michael@0 485 try { parent = child.parent; } catch (e) {}
michael@0 486 is(parent, acc, "Wrong parent of " + prettyName(child));
michael@0 487
michael@0 488 // nsIAccessible::indexInParent
michael@0 489 var indexInParent = -1;
michael@0 490 try { indexInParent = child.indexInParent; } catch(e) {}
michael@0 491 is(indexInParent, i,
michael@0 492 "Wrong index in parent of " + prettyName(child));
michael@0 493
michael@0 494 // nsIAccessible::nextSibling
michael@0 495 var expectedNextSibling = (i < childCount - 1) ?
michael@0 496 children.queryElementAt(i + 1, nsIAccessible) : null;
michael@0 497 var nextSibling = null;
michael@0 498 try { nextSibling = child.nextSibling; } catch (e) {}
michael@0 499 is(nextSibling, expectedNextSibling,
michael@0 500 "Wrong next sibling of " + prettyName(child));
michael@0 501
michael@0 502 // nsIAccessible::previousSibling
michael@0 503 var expectedPrevSibling = (i > 0) ?
michael@0 504 children.queryElementAt(i - 1, nsIAccessible) : null;
michael@0 505 var prevSibling = null;
michael@0 506 try { prevSibling = child.previousSibling; } catch (e) {}
michael@0 507 is(prevSibling, expectedPrevSibling,
michael@0 508 "Wrong previous sibling of " + prettyName(child));
michael@0 509
michael@0 510 // Go down through subtree
michael@0 511 testAccessibleTree(child, accTree.children[i], aFlags);
michael@0 512 }
michael@0 513 }
michael@0 514 }
michael@0 515 }
michael@0 516
michael@0 517 /**
michael@0 518 * Return true if accessible for the given node is in cache.
michael@0 519 */
michael@0 520 function isAccessibleInCache(aNodeOrId)
michael@0 521 {
michael@0 522 var node = getNode(aNodeOrId);
michael@0 523 return gAccRetrieval.getAccessibleFromCache(node) ? true : false;
michael@0 524 }
michael@0 525
michael@0 526 /**
michael@0 527 * Test accessible tree for defunct accessible.
michael@0 528 *
michael@0 529 * @param aAcc [in] the defunct accessible
michael@0 530 * @param aNodeOrId [in] the DOM node identifier for the defunct accessible
michael@0 531 */
michael@0 532 function testDefunctAccessible(aAcc, aNodeOrId)
michael@0 533 {
michael@0 534 if (aNodeOrId)
michael@0 535 ok(!isAccessible(aNodeOrId),
michael@0 536 "Accessible for " + aNodeOrId + " wasn't properly shut down!");
michael@0 537
michael@0 538 var msg = " doesn't fail for shut down accessible " + prettyName(aNodeOrId) + "!";
michael@0 539
michael@0 540 // firstChild
michael@0 541 var success = false;
michael@0 542 try {
michael@0 543 aAcc.firstChild;
michael@0 544 } catch (e) {
michael@0 545 success = (e.result == Components.results.NS_ERROR_FAILURE)
michael@0 546 }
michael@0 547 ok(success, "firstChild" + msg);
michael@0 548
michael@0 549 // lastChild
michael@0 550 success = false;
michael@0 551 try {
michael@0 552 aAcc.lastChild;
michael@0 553 } catch (e) {
michael@0 554 success = (e.result == Components.results.NS_ERROR_FAILURE)
michael@0 555 }
michael@0 556 ok(success, "lastChild" + msg);
michael@0 557
michael@0 558 // childCount
michael@0 559 success = false;
michael@0 560 try {
michael@0 561 aAcc.childCount;
michael@0 562 } catch (e) {
michael@0 563 success = (e.result == Components.results.NS_ERROR_FAILURE)
michael@0 564 }
michael@0 565 ok(success, "childCount" + msg);
michael@0 566
michael@0 567 // children
michael@0 568 success = false;
michael@0 569 try {
michael@0 570 aAcc.children;
michael@0 571 } catch (e) {
michael@0 572 success = (e.result == Components.results.NS_ERROR_FAILURE)
michael@0 573 }
michael@0 574 ok(success, "children" + msg);
michael@0 575
michael@0 576 // nextSibling
michael@0 577 success = false;
michael@0 578 try {
michael@0 579 aAcc.nextSibling;
michael@0 580 } catch (e) {
michael@0 581 success = (e.result == Components.results.NS_ERROR_FAILURE);
michael@0 582 }
michael@0 583 ok(success, "nextSibling" + msg);
michael@0 584
michael@0 585 // previousSibling
michael@0 586 success = false;
michael@0 587 try {
michael@0 588 aAcc.previousSibling;
michael@0 589 } catch (e) {
michael@0 590 success = (e.result == Components.results.NS_ERROR_FAILURE);
michael@0 591 }
michael@0 592 ok(success, "previousSibling" + msg);
michael@0 593
michael@0 594 // parent
michael@0 595 success = false;
michael@0 596 try {
michael@0 597 aAcc.parent;
michael@0 598 } catch (e) {
michael@0 599 success = (e.result == Components.results.NS_ERROR_FAILURE);
michael@0 600 }
michael@0 601 ok(success, "parent" + msg);
michael@0 602 }
michael@0 603
michael@0 604 /**
michael@0 605 * Convert role to human readable string.
michael@0 606 */
michael@0 607 function roleToString(aRole)
michael@0 608 {
michael@0 609 return gAccRetrieval.getStringRole(aRole);
michael@0 610 }
michael@0 611
michael@0 612 /**
michael@0 613 * Convert states to human readable string.
michael@0 614 */
michael@0 615 function statesToString(aStates, aExtraStates)
michael@0 616 {
michael@0 617 var list = gAccRetrieval.getStringStates(aStates, aExtraStates);
michael@0 618
michael@0 619 var str = "";
michael@0 620 for (var index = 0; index < list.length - 1; index++)
michael@0 621 str += list.item(index) + ", ";
michael@0 622
michael@0 623 if (list.length != 0)
michael@0 624 str += list.item(index)
michael@0 625
michael@0 626 return str;
michael@0 627 }
michael@0 628
michael@0 629 /**
michael@0 630 * Convert event type to human readable string.
michael@0 631 */
michael@0 632 function eventTypeToString(aEventType)
michael@0 633 {
michael@0 634 return gAccRetrieval.getStringEventType(aEventType);
michael@0 635 }
michael@0 636
michael@0 637 /**
michael@0 638 * Convert relation type to human readable string.
michael@0 639 */
michael@0 640 function relationTypeToString(aRelationType)
michael@0 641 {
michael@0 642 return gAccRetrieval.getStringRelationType(aRelationType);
michael@0 643 }
michael@0 644
michael@0 645 function getLoadContext() {
michael@0 646 const Ci = Components.interfaces;
michael@0 647 return window.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 648 .getInterface(Ci.nsIWebNavigation)
michael@0 649 .QueryInterface(Ci.nsILoadContext);
michael@0 650 }
michael@0 651
michael@0 652 /**
michael@0 653 * Return text from clipboard.
michael@0 654 */
michael@0 655 function getTextFromClipboard()
michael@0 656 {
michael@0 657 var clip = Components.classes["@mozilla.org/widget/clipboard;1"].
michael@0 658 getService(Components.interfaces.nsIClipboard);
michael@0 659 if (!clip)
michael@0 660 return "";
michael@0 661
michael@0 662 var trans = Components.classes["@mozilla.org/widget/transferable;1"].
michael@0 663 createInstance(Components.interfaces.nsITransferable);
michael@0 664 trans.init(getLoadContext());
michael@0 665 if (!trans)
michael@0 666 return "";
michael@0 667
michael@0 668 trans.addDataFlavor("text/unicode");
michael@0 669 clip.getData(trans, clip.kGlobalClipboard);
michael@0 670
michael@0 671 var str = new Object();
michael@0 672 var strLength = new Object();
michael@0 673 trans.getTransferData("text/unicode", str, strLength);
michael@0 674
michael@0 675 if (str)
michael@0 676 str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
michael@0 677 if (str)
michael@0 678 return str.data.substring(0, strLength.value / 2);
michael@0 679
michael@0 680 return "";
michael@0 681 }
michael@0 682
michael@0 683 /**
michael@0 684 * Return pretty name for identifier, it may be ID, DOM node or accessible.
michael@0 685 */
michael@0 686 function prettyName(aIdentifier)
michael@0 687 {
michael@0 688 if (aIdentifier instanceof Array) {
michael@0 689 var msg = "";
michael@0 690 for (var idx = 0; idx < aIdentifier.length; idx++) {
michael@0 691 if (msg != "")
michael@0 692 msg += ", ";
michael@0 693
michael@0 694 msg += prettyName(aIdentifier[idx]);
michael@0 695 }
michael@0 696 return msg;
michael@0 697 }
michael@0 698
michael@0 699 if (aIdentifier instanceof nsIAccessible) {
michael@0 700 var acc = getAccessible(aIdentifier);
michael@0 701 var msg = "[" + getNodePrettyName(acc.DOMNode);
michael@0 702 try {
michael@0 703 msg += ", role: " + roleToString(acc.role);
michael@0 704 if (acc.name)
michael@0 705 msg += ", name: '" + shortenString(acc.name) + "'";
michael@0 706 } catch (e) {
michael@0 707 msg += "defunct";
michael@0 708 }
michael@0 709
michael@0 710 if (acc)
michael@0 711 msg += ", address: " + getObjAddress(acc);
michael@0 712 msg += "]";
michael@0 713
michael@0 714 return msg;
michael@0 715 }
michael@0 716
michael@0 717 if (aIdentifier instanceof nsIDOMNode)
michael@0 718 return "[ " + getNodePrettyName(aIdentifier) + " ]";
michael@0 719
michael@0 720 return " '" + aIdentifier + "' ";
michael@0 721 }
michael@0 722
michael@0 723 /**
michael@0 724 * Shorten a long string if it exceeds MAX_TRIM_LENGTH.
michael@0 725 * @param aString the string to shorten.
michael@0 726 * @returns the shortened string.
michael@0 727 */
michael@0 728 function shortenString(aString, aMaxLength)
michael@0 729 {
michael@0 730 if (aString.length <= MAX_TRIM_LENGTH)
michael@0 731 return aString;
michael@0 732
michael@0 733 // Trim the string if its length is > MAX_TRIM_LENGTH characters.
michael@0 734 var trimOffset = MAX_TRIM_LENGTH / 2;
michael@0 735 return aString.substring(0, trimOffset - 1) + "..." +
michael@0 736 aString.substring(aString.length - trimOffset, aString.length);
michael@0 737 }
michael@0 738
michael@0 739 ////////////////////////////////////////////////////////////////////////////////
michael@0 740 // General Utils
michael@0 741 ////////////////////////////////////////////////////////////////////////////////
michael@0 742 /**
michael@0 743 * Return main chrome window (crosses chrome boundary)
michael@0 744 */
michael@0 745 function getMainChromeWindow(aWindow)
michael@0 746 {
michael@0 747 return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
michael@0 748 .getInterface(Components.interfaces.nsIWebNavigation)
michael@0 749 .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
michael@0 750 .rootTreeItem
michael@0 751 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
michael@0 752 .getInterface(Components.interfaces.nsIDOMWindow);
michael@0 753 }
michael@0 754
michael@0 755 /** Sets the test plugin(s) initially expected enabled state.
michael@0 756 * It will automatically be reset to it's previous value after the test
michael@0 757 * ends.
michael@0 758 * @param aNewEnabledState [in] the enabled state, e.g. SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED
michael@0 759 * @param aPluginName [in, optional] The name of the plugin, defaults to "Test Plug-in"
michael@0 760 */
michael@0 761 function setTestPluginEnabledState(aNewEnabledState, aPluginName)
michael@0 762 {
michael@0 763 var plugin = getTestPluginTag(aPluginName);
michael@0 764 var oldEnabledState = plugin.enabledState;
michael@0 765 plugin.enabledState = aNewEnabledState;
michael@0 766 SimpleTest.registerCleanupFunction(function() {
michael@0 767 getTestPluginTag(aPluginName).enabledState = oldEnabledState;
michael@0 768 });
michael@0 769 }
michael@0 770
michael@0 771 ////////////////////////////////////////////////////////////////////////////////
michael@0 772 // Private
michael@0 773 ////////////////////////////////////////////////////////////////////////////////
michael@0 774
michael@0 775 ////////////////////////////////////////////////////////////////////////////////
michael@0 776 // Accessible general
michael@0 777
michael@0 778 function getNodePrettyName(aNode)
michael@0 779 {
michael@0 780 try {
michael@0 781 var tag = "";
michael@0 782 if (aNode.nodeType == nsIDOMNode.DOCUMENT_NODE) {
michael@0 783 tag = "document";
michael@0 784 } else {
michael@0 785 tag = aNode.localName;
michael@0 786 if (aNode.nodeType == nsIDOMNode.ELEMENT_NODE && aNode.hasAttribute("id"))
michael@0 787 tag += "@id=\"" + aNode.getAttribute("id") + "\"";
michael@0 788 }
michael@0 789
michael@0 790 return "'" + tag + " node', address: " + getObjAddress(aNode);
michael@0 791 } catch (e) {
michael@0 792 return "' no node info '";
michael@0 793 }
michael@0 794 }
michael@0 795
michael@0 796 function getObjAddress(aObj)
michael@0 797 {
michael@0 798 var exp = /native\s*@\s*(0x[a-f0-9]+)/g;
michael@0 799 var match = exp.exec(aObj.toString());
michael@0 800 if (match)
michael@0 801 return match[1];
michael@0 802
michael@0 803 return aObj.toString();
michael@0 804 }
michael@0 805
michael@0 806 function getTestPluginTag(aPluginName)
michael@0 807 {
michael@0 808 var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
michael@0 809 .getService(SpecialPowers.Ci.nsIPluginHost);
michael@0 810 var tags = ph.getPluginTags();
michael@0 811 var name = aPluginName || "Test Plug-in";
michael@0 812 for (var tag of tags) {
michael@0 813 if (tag.name == name) {
michael@0 814 return tag;
michael@0 815 }
michael@0 816 }
michael@0 817
michael@0 818 ok(false, "Could not find plugin tag with plugin name '" + name + "'");
michael@0 819 return null;
michael@0 820 }

mercurial