tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_coalescence.html (27700B)


      1 <html>
      2 
      3 <head>
      4  <title>Accessible mutation events coalescence testing</title>
      5 
      6  <link rel="stylesheet" type="text/css"
      7        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
      8 
      9  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
     10  <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
     11 
     12  <script type="application/javascript"
     13          src="../common.js"></script>
     14  <script type="application/javascript"
     15          src="../states.js"></script>
     16  <script type="application/javascript"
     17          src="../events.js"></script>
     18 
     19  <script type="application/javascript">
     20 
     21    // //////////////////////////////////////////////////////////////////////////
     22    // Invoker base classes
     23 
     24    const kRemoveElm = 1;
     25    const kHideElm = 2;
     26    const kAddElm = 3;
     27    const kShowElm = 4;
     28 
     29    /**
     30     * Base class to test of mutation events coalescence.
     31     */
     32    function coalescenceBase(aChildAction, aParentAction,
     33                             aPerformActionOnChildInTheFirstPlace) {
     34      // Invoker interface
     35 
     36      this.invoke = function coalescenceBase_invoke() {
     37        if (aPerformActionOnChildInTheFirstPlace) {
     38          this.invokeAction(this.childNode, aChildAction);
     39          this.invokeAction(this.parentNode, aParentAction);
     40        } else {
     41          this.invokeAction(this.parentNode, aParentAction);
     42          this.invokeAction(this.childNode, aChildAction);
     43        }
     44      };
     45 
     46      this.getID = function coalescenceBase_getID() {
     47        var childAction = this.getActionName(aChildAction) + " child";
     48        var parentAction = this.getActionName(aParentAction) + " parent";
     49 
     50        if (aPerformActionOnChildInTheFirstPlace)
     51          return childAction + " and then " + parentAction;
     52 
     53        return parentAction + " and then " + childAction;
     54      };
     55 
     56      this.finalCheck = function coalescenceBase_check() {
     57        if (this.getEventType(aChildAction) == EVENT_HIDE) {
     58          testIsDefunct(this.child);
     59        }
     60        if (this.getEventType(aParentAction) == EVENT_HIDE) {
     61          testIsDefunct(this.parent);
     62        }
     63      };
     64 
     65      // Implementation details
     66 
     67      this.invokeAction = function coalescenceBase_invokeAction(aNode, aAction) {
     68        switch (aAction) {
     69          case kRemoveElm:
     70            aNode.remove();
     71            break;
     72 
     73          case kHideElm:
     74            aNode.style.display = "none";
     75            break;
     76 
     77          case kAddElm:
     78            if (aNode == this.parentNode)
     79              this.hostNode.appendChild(this.parentNode);
     80            else
     81              this.parentNode.appendChild(this.childNode);
     82            break;
     83 
     84          case kShowElm:
     85            aNode.style.display = "block";
     86            break;
     87 
     88          default:
     89            return INVOKER_ACTION_FAILED;
     90        }
     91        // 0 means the action succeeded.
     92        return 0;
     93      };
     94 
     95      this.getEventType = function coalescenceBase_getEventType(aAction) {
     96        switch (aAction) {
     97          case kRemoveElm: case kHideElm:
     98            return EVENT_HIDE;
     99          case kAddElm: case kShowElm:
    100            return EVENT_SHOW;
    101        }
    102        return 0;
    103      };
    104 
    105      this.getActionName = function coalescenceBase_getActionName(aAction) {
    106        switch (aAction) {
    107          case kRemoveElm:
    108            return "remove";
    109          case kHideElm:
    110            return "hide";
    111          case kAddElm:
    112            return "add";
    113          case kShowElm:
    114            return "show";
    115          default:
    116            return "??";
    117        }
    118      };
    119 
    120      this.initSequence = function coalescenceBase_initSequence() {
    121        // expected events
    122        var eventType = this.getEventType(aParentAction);
    123        this.eventSeq = [
    124          new invokerChecker(eventType, this.parentNode),
    125          new invokerChecker(EVENT_REORDER, this.hostNode),
    126        ];
    127 
    128        // unexpected events
    129        this.unexpectedEventSeq = [
    130          new invokerChecker(this.getEventType(aChildAction), this.childNode),
    131          new invokerChecker(EVENT_REORDER, this.parentNode),
    132        ];
    133      };
    134    }
    135 
    136    /**
    137     * Remove or hide mutation events coalescence testing.
    138     */
    139    function removeOrHideCoalescenceBase(aChildID, aParentID,
    140                                         aChildAction, aParentAction,
    141                                         aPerformActionOnChildInTheFirstPlace) {
    142      this.__proto__ = new coalescenceBase(aChildAction, aParentAction,
    143                                           aPerformActionOnChildInTheFirstPlace);
    144 
    145      this.init = function removeOrHideCoalescenceBase_init() {
    146        this.childNode = getNode(aChildID);
    147        this.parentNode = getNode(aParentID);
    148        this.child = getAccessible(this.childNode);
    149        this.parent = getAccessible(this.parentNode);
    150        this.hostNode = this.parentNode.parentNode;
    151      };
    152 
    153      // Initalization
    154 
    155      this.init();
    156      this.initSequence();
    157    }
    158 
    159    // //////////////////////////////////////////////////////////////////////////
    160    // Invokers
    161 
    162    /**
    163     * Remove child node and then its parent node from DOM tree.
    164     */
    165    function removeChildNParent(aChildID, aParentID) {
    166      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    167                                                       kRemoveElm, kRemoveElm,
    168                                                       true);
    169    }
    170 
    171    /**
    172     * Remove parent node and then its child node from DOM tree.
    173     */
    174    function removeParentNChild(aChildID, aParentID) {
    175      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    176                                                       kRemoveElm, kRemoveElm,
    177                                                       false);
    178    }
    179 
    180    /**
    181     * Hide child node and then its parent node.
    182     */
    183    function hideChildNParent(aChildID, aParentID) {
    184      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    185                                                       kHideElm, kHideElm,
    186                                                       true);
    187    }
    188 
    189    /**
    190     * Hide parent node and then its child node.
    191     */
    192    function hideParentNChild(aChildID, aParentID) {
    193      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    194                                                       kHideElm, kHideElm,
    195                                                       false);
    196    }
    197 
    198    /**
    199     * Hide child node and then remove its parent node.
    200     */
    201    function hideChildNRemoveParent(aChildID, aParentID) {
    202      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    203                                                       kHideElm, kRemoveElm,
    204                                                       true);
    205    }
    206 
    207    /**
    208     * Hide parent node and then remove its child node.
    209     */
    210    function hideParentNRemoveChild(aChildID, aParentID) {
    211      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    212                                                       kRemoveElm, kHideElm,
    213                                                       false);
    214    }
    215 
    216    /**
    217     * Remove child node and then hide its parent node.
    218     */
    219    function removeChildNHideParent(aChildID, aParentID) {
    220      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    221                                                       kRemoveElm, kHideElm,
    222                                                       true);
    223    }
    224 
    225    /**
    226     * Remove parent node and then hide its child node.
    227     */
    228    function removeParentNHideChild(aChildID, aParentID) {
    229      this.__proto__ = new removeOrHideCoalescenceBase(aChildID, aParentID,
    230                                                       kHideElm, kRemoveElm,
    231                                                       false);
    232    }
    233 
    234    /**
    235     * Create and append parent node and create and append child node to it.
    236     */
    237    function addParentNChild(aHostID, aPerformActionOnChildInTheFirstPlace) {
    238      this.init = function addParentNChild_init() {
    239        this.hostNode = getNode(aHostID);
    240        this.parentNode = document.createElement("select");
    241        this.childNode = document.createElement("option");
    242        this.childNode.textContent = "testing";
    243      };
    244 
    245      this.__proto__ = new coalescenceBase(kAddElm, kAddElm,
    246                                           aPerformActionOnChildInTheFirstPlace);
    247 
    248      this.init();
    249      this.initSequence();
    250    }
    251 
    252    /**
    253     * Show parent node and show child node to it.
    254     */
    255    function showParentNChild(aParentID, aChildID,
    256                              aPerformActionOnChildInTheFirstPlace) {
    257      this.init = function showParentNChild_init() {
    258        this.parentNode = getNode(aParentID);
    259        this.hostNode = this.parentNode.parentNode;
    260        this.childNode = getNode(aChildID);
    261      };
    262 
    263      this.__proto__ = new coalescenceBase(kShowElm, kShowElm,
    264                                           aPerformActionOnChildInTheFirstPlace);
    265 
    266      this.init();
    267      this.initSequence();
    268    }
    269 
    270    /**
    271     * Create and append child node to the DOM and then show parent node.
    272     */
    273    function showParentNAddChild(aParentID,
    274                                 aPerformActionOnChildInTheFirstPlace) {
    275      this.init = function showParentNAddChild_init() {
    276        this.parentNode = getNode(aParentID);
    277        this.hostNode = this.parentNode.parentNode;
    278        this.childNode = document.createElement("option");
    279        this.childNode.textContent = "testing";
    280      };
    281 
    282      this.__proto__ = new coalescenceBase(kAddElm, kShowElm,
    283                                           aPerformActionOnChildInTheFirstPlace);
    284 
    285      this.init();
    286      this.initSequence();
    287    }
    288 
    289    /**
    290     * Remove children and parent
    291     */
    292    function removeGrandChildrenNHideParent(aChild1Id, aChild2Id, aParentId) {
    293      this.child1 = getNode(aChild1Id);
    294      this.child2 = getNode(aChild2Id);
    295      this.parent = getNode(aParentId);
    296 
    297      this.eventSeq = [
    298        new invokerChecker(EVENT_HIDE, getAccessible(aParentId)),
    299        new invokerChecker(EVENT_REORDER, getNode(aParentId).parentNode),
    300        new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild1Id)),
    301        new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild2Id)),
    302        new unexpectedInvokerChecker(EVENT_REORDER, getAccessible(aParentId)),
    303      ];
    304 
    305      this.invoke = function removeGrandChildrenNHideParent_invoke() {
    306        this.child1.remove();
    307        this.child2.remove();
    308        this.parent.hidden = true;
    309      };
    310 
    311      this.getID = function removeGrandChildrenNHideParent_getID() {
    312        return "remove grand children of different parents and then hide their grand parent";
    313      };
    314    }
    315 
    316    /**
    317     * Remove a child, and then its parent.
    318     */
    319    function test3() {
    320      this.o = getAccessible("t3_o");
    321      this.ofc = getAccessible("t3_o").firstChild;
    322 
    323      this.eventSeq = [
    324        new invokerChecker(EVENT_HIDE, this.o),
    325        new invokerChecker(EVENT_REORDER, "t3_lb"),
    326        new unexpectedInvokerChecker(EVENT_HIDE, this.ofc),
    327        new unexpectedInvokerChecker(EVENT_REORDER, this.o),
    328      ];
    329 
    330      this.invoke = function test3_invoke() {
    331        getNode("t3_o").textContent = "";
    332        getNode("t3_lb").removeChild(getNode("t3_o"));
    333      };
    334 
    335      this.finalCheck = function test3_finalCheck() {
    336        testIsDefunct(this.o);
    337        testIsDefunct(this.ofc);
    338      };
    339 
    340      this.getID = function test3_getID() {
    341        return "remove a child, and then its parent";
    342      };
    343    }
    344 
    345    /**
    346     * Remove children, and then a parent of 2nd child.
    347     */
    348    function test4() {
    349      this.o1 = getAccessible("t4_o1");
    350      this.o1fc = this.o1.firstChild;
    351      this.o2 = getAccessible("t4_o2");
    352      this.o2fc = this.o2.firstChild;
    353 
    354      this.eventSeq = [
    355        new invokerChecker(EVENT_HIDE, this.o1fc),
    356        new invokerChecker(EVENT_HIDE, this.o2),
    357        new invokerChecker(EVENT_REORDER, "t4_lb"),
    358        new unexpectedInvokerChecker(EVENT_HIDE, this.o2fc),
    359        new unexpectedInvokerChecker(EVENT_REORDER, this.o1),
    360        new unexpectedInvokerChecker(EVENT_REORDER, this.o2),
    361      ];
    362 
    363      this.invoke = function test4_invoke() {
    364        getNode("t4_o1").textContent = "";
    365        getNode("t4_o2").textContent = "";
    366        getNode("t4_lb").removeChild(getNode("t4_o2"));
    367      };
    368 
    369      this.finalCheck = function test4_finalCheck() {
    370        testIsDefunct(this.o1fc);
    371        testIsDefunct(this.o2);
    372        testIsDefunct(this.o2fc);
    373      };
    374 
    375      this.getID = function test4_getID() {
    376        return "remove children, and then a parent of 2nd child";
    377      };
    378    }
    379 
    380    /**
    381     * Remove a child, remove a parent sibling, remove the parent
    382     */
    383    function test5() {
    384      this.o = getAccessible("t5_o");
    385      this.ofc = this.o.firstChild;
    386      this.b = getAccessible("t5_b");
    387      this.lb = getAccessible("t5_lb");
    388 
    389      this.eventSeq = [
    390        new invokerChecker(EVENT_HIDE, this.b),
    391        new invokerChecker(EVENT_HIDE, this.o),
    392        new invokerChecker(EVENT_REORDER, "t5"),
    393        new unexpectedInvokerChecker(EVENT_HIDE, this.ofc),
    394        new unexpectedInvokerChecker(EVENT_REORDER, this.o),
    395        new unexpectedInvokerChecker(EVENT_REORDER, this.lb),
    396      ];
    397 
    398      this.invoke = function test5_invoke() {
    399        getNode("t5_o").textContent = "";
    400        getNode("t5").removeChild(getNode("t5_b"));
    401        getNode("t5_lb").removeChild(getNode("t5_o"));
    402      };
    403 
    404      this.finalCheck = function test5_finalCheck() {
    405        testIsDefunct(this.ofc);
    406        testIsDefunct(this.o);
    407        testIsDefunct(this.b);
    408      };
    409 
    410      this.getID = function test5_getID() {
    411        return "remove a child, remove a parent sibling, remove the parent";
    412      };
    413    }
    414 
    415    /**
    416     * Insert accessibles with a child node moved by aria-owns
    417     * Markup:
    418     * <div id="t6_fc">
    419     *   <div id="t6_owns"></div>
    420     * </div>
    421     * <div id="t6_sc" aria-owns="t6_owns"></div>
    422     */
    423    function test6() {
    424      this.parent = getNode("t6");
    425      this.fc = document.createElement("div");
    426      this.fc.setAttribute("id", "t6_fc");
    427      this.owns = document.createElement("div");
    428      this.owns.setAttribute("id", "t6_owns");
    429      this.sc = document.createElement("div");
    430      this.sc.setAttribute("id", "t6_sc");
    431 
    432      this.eventSeq = [
    433        new invokerChecker(EVENT_SHOW, this.fc),
    434        new invokerChecker(EVENT_SHOW, this.sc),
    435        new invokerChecker(EVENT_REORDER, this.parent),
    436        new unexpectedInvokerChecker(EVENT_REORDER, this.fc),
    437        new unexpectedInvokerChecker(EVENT_REORDER, this.sc),
    438        new unexpectedInvokerChecker(EVENT_HIDE, this.owns),
    439        new unexpectedInvokerChecker(EVENT_SHOW, this.owns),
    440      ];
    441 
    442      this.invoke = function test6_invoke() {
    443        getNode("t6").appendChild(this.fc);
    444        getNode("t6_fc").appendChild(this.owns);
    445        getNode("t6").appendChild(this.sc);
    446        getNode("t6_sc").setAttribute("aria-owns", "t6_owns");
    447      };
    448 
    449      this.getID = function test6_getID() {
    450        return "Insert accessibles with a child node moved by aria-owns";
    451      };
    452    }
    453 
    454    /**
    455     * Insert text nodes under direct and grand children, and then hide
    456     * their container by means of aria-owns.
    457     *
    458     * Markup:
    459     * <div id="t7_moveplace" aria-owns="t7_c"></div>
    460     * <div id="t7_c">
    461     *   <div id="t7_c_directchild">ha</div>
    462     *   <div><div id="t7_c_grandchild">ha</div></div>
    463     * </div>
    464     */
    465    function test7() {
    466      this.eventSeq = [
    467        new invokerChecker(EVENT_HIDE, getNode("t7_c")),
    468        new invokerChecker(EVENT_SHOW, getNode("t7_c")),
    469        new invokerChecker(EVENT_REORDER, getNode("t7")),
    470        new unexpectedInvokerChecker(EVENT_REORDER, getNode("t7_c_directchild")),
    471        new unexpectedInvokerChecker(EVENT_REORDER, getNode("t7_c_grandchild")),
    472        new unexpectedInvokerChecker(EVENT_SHOW, () => getNode("t7_c_directchild").firstChild),
    473        new unexpectedInvokerChecker(EVENT_SHOW, () => getNode("t7_c_grandchild").firstChild),
    474      ];
    475 
    476      this.invoke = function test7_invoke() {
    477        getNode("t7_c_directchild").textContent = "ha";
    478        getNode("t7_c_grandchild").textContent = "ha";
    479        getNode("t7_moveplace").setAttribute("aria-owns", "t7_c");
    480      };
    481 
    482      this.getID = function test7_getID() {
    483        return "Show child accessibles and then hide their container";
    484      };
    485    }
    486 
    487    /**
    488     * Move a node by aria-owns from right to left in the tree, so that
    489     * the eventing looks this way:
    490     * reorder for 't8_c1'
    491     *   hide for 't8_c1_child'
    492     *   show for 't8_c2_moved'
    493     * reorder for 't8_c2'
    494     *   hide for 't8_c2_moved'
    495     *
    496     * The hide event should be delivered before the paired show event.
    497     */
    498    function test8() {
    499      this.eventSeq = [
    500        new invokerChecker(EVENT_HIDE, getNode("t8_c1_child")),
    501        new invokerChecker(EVENT_HIDE, "t8_c2_moved"),
    502        new invokerChecker(EVENT_SHOW, "t8_c2_moved"),
    503        new invokerChecker(EVENT_REORDER, "t8_c2"),
    504        new invokerChecker(EVENT_REORDER, "t8_c1"),
    505      ];
    506 
    507      this.invoke = function test8_invoke() {
    508        // Remove a node from 't8_c1' container to give the event tree a
    509        // desired structure (the 't8_c1' container node goes first in the event
    510        // tree)
    511        getNode("t8_c1_child").remove();
    512        // then move 't8_c2_moved' from 't8_c2' to 't8_c1'.
    513        getNode("t8_c1").setAttribute("aria-owns", "t8_c2_moved");
    514      };
    515 
    516      this.getID = function test8_getID() {
    517        return "Move a node by aria-owns to left within the tree";
    518      };
    519    }
    520 
    521    /**
    522     * Move 't9_c3_moved' node under 't9_c2_moved', and then move 't9_c2_moved'
    523     * node by aria-owns (same as test10 but has different aria-owns
    524     * ordering), the eventing looks same way as in test10:
    525     * reorder for 't9_c1'
    526     *   hide for 't9_c1_child'
    527     *   show for 't9_c2_moved'
    528     * reorder for 't9_c2'
    529    *    hide for 't9_c2_child'
    530     *   hide for 't9_c2_moved'
    531     * reorder for 't9_c3'
    532     *   hide for 't9_c3_moved'
    533     *
    534     * The hide events for 't9_c2_moved' and 't9_c3_moved' should be delivered
    535     * before the show event for 't9_c2_moved'.
    536     */
    537    function test9() {
    538      this.eventSeq = [
    539        new invokerChecker(EVENT_HIDE, getNode("t9_c1_child")),
    540        new invokerChecker(EVENT_HIDE, getNode("t9_c2_child")),
    541        new invokerChecker(EVENT_HIDE, "t9_c3_moved"),
    542        new invokerChecker(EVENT_HIDE, "t9_c2_moved"),
    543        new invokerChecker(EVENT_SHOW, "t9_c2_moved"),
    544        new invokerChecker(EVENT_REORDER, "t9_c3"),
    545        new invokerChecker(EVENT_REORDER, "t9_c2"),
    546        new invokerChecker(EVENT_REORDER, "t9_c1"),
    547        new unexpectedInvokerChecker(EVENT_SHOW, "t9_c3_moved"),
    548      ];
    549 
    550      this.invoke = function test9_invoke() {
    551        // Remove child nodes from 't9_c1' and 't9_c2' containers to give
    552        // the event tree a needed structure ('t9_c1' and 't9_c2' nodes go
    553        // first in the event tree),
    554        getNode("t9_c1_child").remove();
    555        getNode("t9_c2_child").remove();
    556        // then do aria-owns magic.
    557        getNode("t9_c2_moved").setAttribute("aria-owns", "t9_c3_moved");
    558        getNode("t9_c1").setAttribute("aria-owns", "t9_c2_moved");
    559      };
    560 
    561      this.getID = function test9_getID() {
    562        return "Move node #1 by aria-owns and then move node #2 into node #1";
    563      };
    564    }
    565 
    566    /**
    567     * Move a node 't10_c3_moved' by aria-owns under a node 't10_c2_moved',
    568     * moved by under 't10_1', so that the eventing looks this way:
    569     * reorder for 't10_c1'
    570     *   hide for 't10_c1_child'
    571     *   show for 't10_c2_moved'
    572     * reorder for 't10_c2'
    573     *   hide for 't10_c2_child'
    574     *   hide for 't10_c2_moved'
    575     * reorder for 't10_c3'
    576     *   hide for 't10_c3_moved'
    577     *
    578     * The hide events for 't10_c2_moved' and 't10_c3_moved' should be delivered
    579     * before the show event for 't10_c2_moved'.
    580     */
    581    function test10() {
    582      this.eventSeq = [
    583        new invokerChecker(EVENT_HIDE, getNode("t10_c1_child")),
    584        new invokerChecker(EVENT_HIDE, getNode("t10_c2_child")),
    585        new invokerChecker(EVENT_HIDE, getNode("t10_c2_moved")),
    586        new invokerChecker(EVENT_HIDE, getNode("t10_c3_moved")),
    587        new invokerChecker(EVENT_SHOW, getNode("t10_c2_moved")),
    588        new invokerChecker(EVENT_REORDER, "t10_c2"),
    589        new invokerChecker(EVENT_REORDER, "t10_c1"),
    590        new invokerChecker(EVENT_REORDER, "t10_c3"),
    591      ];
    592 
    593      this.invoke = function test10_invoke() {
    594        // Remove child nodes from 't10_c1' and 't10_c2' containers to give
    595        // the event tree a needed structure ('t10_c1' and 't10_c2' nodes go first
    596        // in the event tree),
    597        getNode("t10_c1_child").remove();
    598        getNode("t10_c2_child").remove();
    599        // then do aria-owns stuff.
    600        getNode("t10_c1").setAttribute("aria-owns", "t10_c2_moved");
    601        getNode("t10_c2_moved").setAttribute("aria-owns", "t10_c3_moved");
    602      };
    603 
    604      this.getID = function test10_getID() {
    605        return "Move a node by aria-owns into a node moved by aria-owns to left within the tree";
    606      };
    607    }
    608 
    609    /**
    610     * Move a node by aria-owns from right to left in the tree, and then
    611     * move its parent too by aria-owns. No hide event should be fired for
    612     * original node.
    613     */
    614    function test11() {
    615      this.eventSeq = [
    616        new invokerChecker(EVENT_HIDE, getNode("t11_c1_child")),
    617        new invokerChecker(EVENT_HIDE, getNode("t11_c2")),
    618        new orderChecker(),
    619        new asyncInvokerChecker(EVENT_SHOW, "t11_c2_child"),
    620        new asyncInvokerChecker(EVENT_SHOW, "t11_c2"),
    621        new orderChecker(),
    622        new invokerChecker(EVENT_REORDER, "t11"),
    623        new unexpectedInvokerChecker(EVENT_HIDE, "t11_c2_child"),
    624        new unexpectedInvokerChecker(EVENT_REORDER, "t11_c1"),
    625        new unexpectedInvokerChecker(EVENT_REORDER, "t11_c2"),
    626        new unexpectedInvokerChecker(EVENT_REORDER, "t11_c3"),
    627      ];
    628 
    629      this.invoke = function test11_invoke() {
    630        // Remove a node from 't11_c1' container to give the event tree a
    631        // desired structure (the 't11_c1' container node goes first in
    632        // the event tree),
    633        getNode("t11_c1_child").remove();
    634        // then move 't11_c2_moved' from 't11_c2' to 't11_c1', and then move
    635        // 't11_c2' to 't11_c3'.
    636        getNode("t11_c1").setAttribute("aria-owns", "t11_c2_child");
    637        getNode("t11_c3").setAttribute("aria-owns", "t11_c2");
    638      };
    639 
    640      this.getID = function test11_getID() {
    641        return "Move a node by aria-owns to left within the tree";
    642      };
    643    }
    644 
    645    // //////////////////////////////////////////////////////////////////////////
    646    // Do tests.
    647 
    648    gA11yEventDumpToConsole = true; // debug stuff
    649    // enableLogging("eventTree");
    650 
    651    var gQueue = null;
    652    function doTests() {
    653      gQueue = new eventQueue();
    654 
    655      gQueue.push(new removeChildNParent("option1", "select1"));
    656      gQueue.push(new removeParentNChild("option2", "select2"));
    657      gQueue.push(new hideChildNParent("option3", "select3"));
    658      gQueue.push(new hideParentNChild("option4", "select4"));
    659      gQueue.push(new hideChildNRemoveParent("option5", "select5"));
    660      gQueue.push(new hideParentNRemoveChild("option6", "select6"));
    661      gQueue.push(new removeChildNHideParent("option7", "select7"));
    662      gQueue.push(new removeParentNHideChild("option8", "select8"));
    663 
    664      gQueue.push(new addParentNChild("testContainer", false));
    665      gQueue.push(new addParentNChild("testContainer", true));
    666      gQueue.push(new showParentNChild("select9", "option9", false));
    667      gQueue.push(new showParentNChild("select10", "option10", true));
    668      gQueue.push(new showParentNAddChild("select11", false));
    669      gQueue.push(new showParentNAddChild("select12", true));
    670 
    671      gQueue.push(new removeGrandChildrenNHideParent("t1_child1", "t1_child2", "t1_parent"));
    672      gQueue.push(new test3());
    673      gQueue.push(new test4());
    674      gQueue.push(new test5());
    675      gQueue.push(new test6());
    676      gQueue.push(new test7());
    677      gQueue.push(new test8());
    678      gQueue.push(new test9());
    679      gQueue.push(new test10());
    680      gQueue.push(new test11());
    681 
    682      gQueue.invoke(); // Will call SimpleTest.finish();
    683    }
    684 
    685    SimpleTest.waitForExplicitFinish();
    686    addA11yLoadEvent(doTests);
    687  </script>
    688 </head>
    689 
    690 <body>
    691 
    692  <a target="_blank"
    693     href="https://bugzilla.mozilla.org/show_bug.cgi?id=513213"
    694     title="coalesce events when new event is appended to the queue">
    695    Mozilla Bug 513213
    696  </a><br>
    697  <a target="_blank"
    698     title="Rework accessible tree update code"
    699     href="https://bugzilla.mozilla.org/show_bug.cgi?id=570275">
    700    Mozilla Bug 570275
    701  </a>
    702 
    703  <p id="display"></p>
    704  <div id="content" style="display: none"></div>
    705  <pre id="test">
    706  </pre>
    707 
    708  <div id="testContainer">
    709    <select id="select1">
    710      <option id="option1">option</option>
    711    </select>
    712    <select id="select2">
    713      <option id="option2">option</option>
    714    </select>
    715    <select id="select3">
    716      <option id="option3">option</option>
    717    </select>
    718    <select id="select4">
    719      <option id="option4">option</option>
    720    </select>
    721    <select id="select5">
    722      <option id="option5">option</option>
    723    </select>
    724    <select id="select6">
    725      <option id="option6">option</option>
    726    </select>
    727    <select id="select7">
    728      <option id="option7">option</option>
    729    </select>
    730    <select id="select8">
    731      <option id="option8">option</option>
    732    </select>
    733 
    734    <select id="select9" style="display: none">
    735      <option id="option9" style="display: none">testing</option>
    736    </select>
    737    <select id="select10" style="display: none">
    738      <option id="option10" style="display: none">testing</option>
    739    </select>
    740    <select id="select11" style="display: none"></select>
    741    <select id="select12" style="display: none"></select>
    742  </div>
    743 
    744  <div id="testContainer2">
    745    <div id="t1_parent">
    746      <div id="t1_mid1"><div id="t1_child1"></div></div>
    747      <div id="t1_mid2"><div id="t1_child2"></div></div>
    748    </div>
    749  </div>
    750 
    751  <div id="t3">
    752    <div role="listbox" id="t3_lb">
    753      <div role="option" id="t3_o">opt</div>
    754    </div>
    755  </div>
    756 
    757  <div id="t4">
    758    <div role="listbox" id="t4_lb">
    759      <div role="option" id="t4_o1">opt1</div>
    760      <div role="option" id="t4_o2">opt2</div>
    761    </div>
    762  </div>
    763 
    764  <div id="t5">
    765    <div role="button" id="t5_b">btn</div>
    766    <div role="listbox" id="t5_lb">
    767      <div role="option" id="t5_o">opt</div>
    768    </div>
    769  </div>
    770 
    771  <div id="t6">
    772  </div>
    773 
    774  <div id="t7">
    775    <div id="t7_moveplace"></div>
    776    <div id="t7_c">
    777      <div><div id="t7_c_grandchild"></div></div>
    778      <div id="t7_c_directchild"></div>
    779    </div>
    780  </div>
    781 
    782  <div id="t8">
    783    <div id="t8_c1"><div id="t8_c1_child"></div></div>
    784    <div id="t8_c2">
    785      <div id="t8_c2_moved"></div>
    786    </div>
    787  </div>
    788 
    789  <div id="t9">
    790    <div id="t9_c1"><div id="t9_c1_child"></div></div>
    791    <div id="t9_c2">
    792      <div id="t9_c2_child"></div>
    793      <div id="t9_c2_moved"></div>
    794    </div>
    795    <div id="t9_c3">
    796      <div id="t9_c3_moved"></div>
    797    </div>
    798  </div>
    799 
    800  <div id="t10">
    801    <div id="t10_c1"><div id="t10_c1_child"></div></div>
    802    <div id="t10_c2">
    803      <div id="t10_c2_child"></div>
    804      <div id="t10_c2_moved"></div>
    805    </div>
    806    <div id="t10_c3">
    807      <div id="t10_c3_moved"></div>
    808    </div>
    809  </div>
    810 
    811  <div id="t11">
    812    <div id="t11_c1"><div id="t11_c1_child"></div></div>
    813    <div id="t11_c2"><div id="t11_c2_child"></div></div>
    814    <div id="t11_c3"></div>
    815  </div>
    816 </body>
    817 </html>