tor-browser

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

test_delayed_removal.html (15196B)


      1 <!DOCTYPE html>
      2 <html>
      3 
      4 <head>
      5  <title>Test accessible delayed removal</title>
      6 
      7  <link rel="stylesheet" type="text/css"
      8        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
      9 
     10  <style>
     11    .gentext:before {
     12      content: "START"
     13    }
     14    .gentext:after {
     15      content: "END"
     16    }
     17  </style>
     18 
     19  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
     20 
     21  <script type="application/javascript"
     22          src="../common.js"></script>
     23  <script type="application/javascript"
     24          src="../role.js"></script>
     25  <script type="application/javascript"
     26          src="../promisified-events.js"></script>
     27 
     28  <script type="application/javascript">
     29 
     30    async function hideDivFromInsideSpan() {
     31      let msg = "hideDivFromInsideSpan";
     32      info(msg);
     33      let events = waitForOrderedEvents([
     34        [EVENT_HIDE, "div1"], [EVENT_TEXT_REMOVED, "span1"],
     35        [EVENT_REORDER, "span1"]
     36      ], msg);
     37      document.body.offsetTop; // Flush layout.
     38      getNode("div1").style.display = "none";
     39      await events;
     40 
     41      testAccessibleTree("c1", { SECTION: [ { REGION: [] }, ] });
     42    }
     43 
     44    async function showDivFromInsideSpan() {
     45      let msg = "showDivFromInsideSpan";
     46      info(msg);
     47      let events = waitForOrderedEvents(
     48        [[EVENT_SHOW, "div2"], [EVENT_REORDER, "span2"]], msg);
     49      document.body.offsetTop; // Flush layout.
     50      getNode("div2").style.display = "block";
     51      await events;
     52 
     53      testAccessibleTree("c2",
     54        { SECTION: [ { REGION: [{ SECTION: [ { TEXT_LEAF: [] } ] }] }, ] });
     55    }
     56 
     57    async function removeDivFromInsideSpan() {
     58      let msg = "removeDivFromInsideSpan";
     59      info(msg);
     60      let events = waitForOrderedEvents([
     61        [EVENT_HIDE, getNode("div3")], [EVENT_TEXT_REMOVED, "span3"],
     62        [EVENT_REORDER, "span3"]
     63      ], msg);
     64      document.body.offsetTop; // Flush layout.
     65      getNode("div3").remove();
     66      await events;
     67 
     68      testAccessibleTree("c3", { SECTION: [ { REGION: [] }, ] });
     69    }
     70 
     71    // Test to see that generated content is inserted
     72    async function addCSSGeneratedContent() {
     73      let msg = "addCSSGeneratedContent";
     74      let c4_child = getAccessible("c4_child");
     75      info(msg);
     76      let events = waitForOrderedEvents([
     77        [EVENT_SHOW, evt => evt.accessible == c4_child.firstChild],
     78        [EVENT_SHOW, evt => evt.accessible == c4_child.lastChild],
     79        [EVENT_REORDER, c4_child]], msg);
     80      document.body.offsetTop; // Flush layout.
     81      getNode("c4_child").classList.add('gentext');
     82      await events;
     83 
     84      testAccessibleTree("c4", { SECTION: [ // container
     85            { SECTION: [ // inserted node
     86              { STATICTEXT: [] }, // :before
     87              { TEXT_LEAF: [] }, // primary text
     88              { STATICTEXT: [] }, // :after
     89            ] },
     90          ] });
     91    }
     92 
     93    // Test to see that generated content gets removed
     94    async function removeCSSGeneratedContent() {
     95      let msg = "removeCSSGeneratedContent";
     96      let c5_child = getAccessible("c5_child");
     97      info(msg);
     98      let events = waitForEvents([
     99        [EVENT_HIDE, c5_child.firstChild],
    100        [EVENT_HIDE, c5_child.lastChild],
    101        [EVENT_REORDER, c5_child]], msg);
    102      document.body.offsetTop; // Flush layout.
    103      getNode("c5_child").classList.remove('gentext');
    104      await events;
    105 
    106      testAccessibleTree("c5",{ SECTION: [ // container
    107            { SECTION: [ // inserted node
    108              { TEXT_LEAF: [] }, // primary text
    109            ] },
    110          ] });
    111    }
    112 
    113    // Test to see that a non-accessible intermediate container gets its accessible
    114    // descendants removed and inserted correctly.
    115    async function intermediateNonAccessibleContainers() {
    116      let msg = "intermediateNonAccessibleContainers";
    117      info(msg);
    118 
    119      testAccessibleTree("c6",{ SECTION: [
    120            { SECTION: [
    121              { role: ROLE_PUSHBUTTON, name: "Hello" },
    122            ] },
    123          ] });
    124 
    125      let events = waitForOrderedEvents(
    126        [[EVENT_HIDE, "b1"], [EVENT_SHOW, "b2"], [EVENT_REORDER, "scrollarea"]], msg);
    127      document.body.offsetTop; // Flush layout.
    128      getNode("scrollarea").style.overflow = "auto";
    129      document.querySelector("#scrollarea > div > div:first-child").style.display = "none";
    130      document.querySelector("#scrollarea > div > div:last-child").style.display = "block";
    131      await events;
    132 
    133      testAccessibleTree("c6",{ SECTION: [
    134            { SECTION: [
    135              { role: ROLE_PUSHBUTTON, name: "Goodbye" },
    136            ] },
    137          ] });
    138    }
    139 
    140    // Test to see that the button gets reparented into the new accessible container.
    141    async function intermediateNonAccessibleContainerBecomesAccessible() {
    142      let msg = "intermediateNonAccessibleContainerBecomesAccessible";
    143      info(msg);
    144 
    145      testAccessibleTree("c7",{ SECTION: [
    146        { role: ROLE_PUSHBUTTON, name: "Hello" },
    147      ] });
    148 
    149      let events = waitForOrderedEvents(
    150        [[EVENT_HIDE, "b3"],
    151          // b3 show event coalesced into its new container
    152         [EVENT_SHOW, evt => evt.DOMNode.classList.contains('intermediate')],
    153         [EVENT_REORDER, "c7"]], msg);
    154      document.body.offsetTop; // Flush layout.
    155      document.querySelector("#c7 > div").style.display = "block";
    156      await events;
    157 
    158      testAccessibleTree("c7",{ SECTION: [
    159        { SECTION: [ { role: ROLE_PUSHBUTTON, name: "Hello" } ] }
    160      ] });
    161    }
    162 
    163    // Test to ensure that relocated accessibles are removed when a DOM
    164    // ancestor is hidden.
    165    async function removeRelocatedWhenDomAncestorHidden() {
    166      info("removeRelocatedWhenDomAncestorHidden");
    167 
    168      testAccessibleTree("c8",{ SECTION: [
    169        { EDITCOMBOBOX: [ // c8_owner
    170          { COMBOBOX_LIST: [] }, // c8_owned
    171        ]},
    172        { SECTION: [] }, // c8_owned_container
    173      ] });
    174 
    175      let events = waitForOrderedEvents([
    176        [EVENT_HIDE, "c8_owned_container"],
    177        [EVENT_HIDE, "c8_owned"],
    178        [EVENT_REORDER, "c8"],
    179      ], "removeRelocatedWhenDomAncestorHidden");
    180      document.body.offsetTop; // Flush layout.
    181      getNode("c8_owned_container").hidden = true;
    182      await events;
    183 
    184      testAccessibleTree("c8",{ SECTION: [
    185        { EDITCOMBOBOX: [] }, // c8_owner
    186      ] });
    187    }
    188 
    189    // Bug 1572829
    190    async function removeShadowRootHost() {
    191      info("removeShadowRootHost");
    192      document.body.offsetTop; // Flush layout.
    193 
    194      let event = waitForEvent(EVENT_REORDER, "c9", "removeShadowRootHost");
    195      getNode("c9").firstElementChild.attachShadow({mode: "open"});
    196      getNode("c9").firstElementChild.replaceWith("");
    197 
    198      await event;
    199    }
    200 
    201    function listItemReframe() {
    202      testAccessibleTree("li",{ LISTITEM: [
    203        { LISTITEM_MARKER: [] },
    204        { TEXT_LEAF: [] },
    205      ] });
    206 
    207      getNode("li").style.listStylePosition = "inside";
    208      document.body.offsetTop; // Flush layout.
    209      window.windowUtils.advanceTimeAndRefresh(100);
    210 
    211      testAccessibleTree("li",{ LISTITEM: [
    212        { LISTITEM_MARKER: [] },
    213        { TEXT_LEAF: [] },
    214      ] });
    215 
    216      window.windowUtils.restoreNormalRefresh();
    217    }
    218 
    219    // Check to see that a reframed body gets its children pruned correctly.
    220    async function bodyReframe() {
    221      // Load sub-document in iframe.
    222      let event = waitForEvent(EVENT_REORDER, "iframe", "bodyReframe");
    223      getNode("iframe").src =
    224        `data:text/html,<div>Hello</div><div style="display: none">World</div>`;
    225      await event;
    226 
    227      // Initial tree should have one section leaf.
    228      testAccessibleTree("c10",{ SECTION: [
    229        { INTERNAL_FRAME: [
    230          { DOCUMENT: [
    231            { SECTION: [
    232              { role: ROLE_TEXT_LEAF, name: "Hello" }
    233            ] }
    234          ]}
    235        ] }
    236      ] });
    237 
    238 
    239      let iframeDoc = getNode("iframe").contentWindow.document;
    240 
    241      // Trigger coalesced reframing. Both the body node and its children
    242      // will need reframing.
    243      event = waitForEvent(EVENT_REORDER, iframeDoc, "bodyReframe");
    244      iframeDoc.body.style.display = "inline-block";
    245      iframeDoc.querySelector("div:first-child").style.display = "none";
    246      iframeDoc.querySelector("div:last-child").style.display = "block";
    247 
    248      await event;
    249 
    250      // Only the second section should be showing
    251      testAccessibleTree("c10",{ SECTION: [
    252        { INTERNAL_FRAME: [
    253          { DOCUMENT: [
    254            { SECTION: [
    255              { role: ROLE_TEXT_LEAF, name: "World" }
    256            ] }
    257          ]}
    258        ] }
    259      ] });
    260    }
    261 
    262    // Ensure that embed elements recreate their Accessible if they started
    263    // without an src and then an src is set later.
    264    async function embedBecomesOuterDoc() {
    265      let msg = "embedBecomesOuterDoc";
    266      info(msg);
    267 
    268      testAccessibleTree("c12", { SECTION: [
    269        { TEXT: [] }
    270      ] });
    271 
    272      let events = waitForOrderedEvents([
    273          [EVENT_HIDE, "embed"],
    274          [EVENT_SHOW, "embed"],
    275          [EVENT_REORDER, "c12"],
    276        ], msg);
    277      getNode("embed").src = "data:text/html,";
    278      await events;
    279 
    280      testAccessibleTree("c12", { SECTION: [
    281        { INTERNAL_FRAME: [
    282          { DOCUMENT: [] }
    283        ] }
    284      ] });
    285    }
    286 
    287    // Test that we get a text removed event when removing generated content from a button
    288    async function testCSSGeneratedContentRemovedFromButton() {
    289      let msg = "testCSSGeneratedContentRemovedFromButton";
    290      info(msg);
    291 
    292      testAccessibleTree("c13", { SECTION: [
    293        { role: ROLE_PUSHBUTTON, name: "beforego",
    294          children: [{ STATICTEXT: [] }, { TEXT_LEAF: [] }] }
    295      ] });
    296 
    297      let events = waitForOrderedEvents([
    298          [EVENT_HIDE, evt => evt.accessible.name == "before"],
    299          [EVENT_TEXT_REMOVED, evt => evt.accessible.role == ROLE_PUSHBUTTON],
    300          [EVENT_SHOW, evt => evt.DOMNode.tagName == "HR"],
    301          [EVENT_REORDER, "c13"],
    302        ], msg);
    303      getNode("b13").click();
    304      await events;
    305 
    306      testAccessibleTree("c13", { SECTION: [
    307        { role: ROLE_PUSHBUTTON, name: "go",
    308          children: [{ TEXT_LEAF: [] }] },
    309        { SEPARATOR: [] }
    310      ] });
    311    }
    312 
    313    // Slack seems to often restyle containers and change children
    314    // simultaneously, this results in an insertion queue filled with
    315    // redundant insertions and unparented nodes.
    316    // This test duplicates some of this.
    317    async function testSlack() {
    318      let msg = "testSlack";
    319      info(msg);
    320 
    321      window.windowUtils.advanceTimeAndRefresh(100);
    322      let event = waitForEvent(EVENT_REORDER, "c14", "testSlack");
    323 
    324      let keyContainer = document.querySelector("#c14 .intermediate");
    325      keyContainer.style.display = "inline-block";
    326      document.body.offsetTop; // Flush layout.
    327 
    328      let one = document.querySelector("#c14 [aria-label='one']");
    329      let three = document.querySelector("#c14 [aria-label='three']");
    330      one.remove();
    331      three.remove();
    332      // insert one first
    333      keyContainer.firstChild.before(one.cloneNode());
    334      // insert three last
    335      keyContainer.lastChild.after(three.cloneNode());
    336 
    337      keyContainer.style.display = "flex";
    338      document.body.offsetTop; // Flush layout.
    339 
    340      window.windowUtils.restoreNormalRefresh();
    341 
    342      await event;
    343 
    344      is(getAccessible("c14").name, "one two three", "subtree has correct order");
    345    }
    346 
    347    // Ensure that a node is removed when visibility: hidden is set but the
    348    // layout frame is reconstructed; e.g. because of position: fixed. Also
    349    // ensure that visible children aren't clobbered.
    350    async function visibilityHiddenWithReframe() {
    351      let msg = "visibilityHiddenWithReframe";
    352      info(msg);
    353 
    354      testAccessibleTree("c15", { SECTION: [ // c15
    355        { SECTION: [ // c15_inner
    356          { TEXT_LEAF: [] }, // Text
    357          { PARAGRAPH: [
    358            { TEXT_LEAF: [] } // Para
    359          ] },
    360          { HEADING: [ // c15_visible
    361            { TEXT_LEAF: [] } // Visible
    362          ] }, // c15_visible
    363        ] } // c15_inner
    364      ] });
    365 
    366      let events = waitForOrderedEvents([
    367          [EVENT_HIDE, "c15_inner"],
    368          [EVENT_SHOW, "c15_visible"],
    369          [EVENT_REORDER, "c15"],
    370        ], msg);
    371      getNode("c15_inner").style = "visibility: hidden; position: fixed;";
    372      await events;
    373 
    374      testAccessibleTree("c15", { SECTION: [ // c15
    375        { HEADING: [ // c15_visible
    376          { TEXT_LEAF: [] } // Visible
    377        ] }, // c15_visible
    378      ] });
    379    }
    380 
    381    async function doTest() {
    382      await hideDivFromInsideSpan();
    383 
    384      await showDivFromInsideSpan();
    385 
    386      await removeDivFromInsideSpan();
    387 
    388      await addCSSGeneratedContent();
    389 
    390      await removeCSSGeneratedContent();
    391 
    392      await intermediateNonAccessibleContainers();
    393 
    394      await intermediateNonAccessibleContainerBecomesAccessible();
    395 
    396      await removeRelocatedWhenDomAncestorHidden();
    397 
    398      await removeShadowRootHost();
    399 
    400      listItemReframe();
    401 
    402      await bodyReframe();
    403 
    404      await embedBecomesOuterDoc();
    405 
    406      await testCSSGeneratedContentRemovedFromButton();
    407 
    408      await testSlack();
    409 
    410      await visibilityHiddenWithReframe();
    411 
    412      SimpleTest.finish();
    413    }
    414 
    415    SimpleTest.waitForExplicitFinish();
    416    addA11yLoadEvent(doTest);
    417  </script>
    418 </head>
    419 <body>
    420 
    421  <p id="display"></p>
    422  <div id="content" style="display: none"></div>
    423  <pre id="test">
    424  </pre>
    425 
    426  <div id="c1">
    427    <span role="region" id="span1" aria-label="region"><div id="div1">hello</div></span>
    428  </div>
    429 
    430  <div id="c2">
    431    <span role="region" id="span2" aria-label="region"><div id="div2" style="display: none">hello</div></span>
    432  </div>
    433 
    434  <div id="c3">
    435    <span role="region" id="span3" aria-label="region"><div id="div3">hello</div></span>
    436  </div>
    437 
    438  <div id="c4"><div id="c4_child">text</div></div>
    439 
    440  <div id="c5"><div id="c5_child" class="gentext">text</div></div>
    441 
    442  <div id="c6">
    443    <div id="scrollarea" style="overflow:hidden;">
    444      <div><div role="none"><button id="b1">Hello</button></div><div role="none" style="display: none"><button id="b2">Goodbye</button></div></div>
    445    </div>
    446  </div>
    447 
    448  <div id="c7">
    449    <div style="display: inline;" class="intermediate">
    450      <button id="b3">Hello</button>
    451    </div>
    452  </div>
    453 
    454  <div id="c8">
    455    <div id="c8_owner" role="combobox" aria-owns="c8_owned"></div>
    456    <div id="c8_owned_container">
    457      <div id="c8_owned" role="listbox"></div>
    458    </div>
    459  </div>
    460 
    461  <div id="c9">
    462    <div><dir>a</dir></div>
    463  </div>
    464 
    465  <div id="c11">
    466    <ul>
    467        <li id="li">Test</li>
    468    </ul>
    469  </div>
    470 
    471  <div id="c12"><embed id="embed"></embed></div>
    472 
    473  <div id="c10">
    474    <iframe id="iframe"></iframe>
    475  </div>
    476 
    477  <div id="c13">
    478    <style>
    479    .before::before { content: 'before' }
    480    </style>
    481    <button id="b13" class="before" onclick="this.className = ''; this.insertAdjacentElement('afterend', document.createElement('hr'))">go</button>
    482  </div>
    483 
    484  <div role="heading" id="c14" data-qa="virtual-list-item">
    485    <div class="intermediate">
    486      <div role="img" aria-label="one"></div> two <div role="img"
    487        aria-label="three"></div>
    488    </div>
    489  </div>
    490 
    491  <div id="c15"><div id="c15_inner">
    492    Text
    493    <p>Para</p>
    494    <h1 id="c15_visible" style="visibility: visible;">Visible</h1>
    495  </div></div>
    496 
    497  <div id="eventdump"></div>
    498 </body>
    499 </html>