tor-browser

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

browser_relations_general_002.js (11791B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 requestLongerTimeout(2);
      7 
      8 /* import-globals-from ../../mochitest/role.js */
      9 loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
     10 /* import-globals-from ../../mochitest/states.js */
     11 loadScripts({ name: "states.js", dir: MOCHITESTS_DIR });
     12 
     13 /**
     14 * Test MEMBER_OF relation caching on HTML radio buttons
     15 */
     16 addAccessibleTask(
     17  `
     18  <input type="radio" id="r1">I have no name<br>
     19  <input type="radio" id="r2">I also have no name<br>
     20  <input type="radio" id="r3" name="n">I have a name<br>
     21  <input type="radio" id="r4" name="a">I have a different name<br>
     22  <fieldset role="radiogroup">
     23    <input type="radio" id="r5" name="n">I have an already used name
     24     and am in a different part of the tree
     25    <input type="radio" id="r6" name="r">I have a different name but am
     26     in the same group
     27  </fieldset>`,
     28  async function (browser, accDoc) {
     29    const r1 = findAccessibleChildByID(accDoc, "r1");
     30    const r2 = findAccessibleChildByID(accDoc, "r2");
     31    const r3 = findAccessibleChildByID(accDoc, "r3");
     32    const r4 = findAccessibleChildByID(accDoc, "r4");
     33    const r5 = findAccessibleChildByID(accDoc, "r5");
     34    const r6 = findAccessibleChildByID(accDoc, "r6");
     35 
     36    await testCachedRelation(r1, RELATION_MEMBER_OF, []);
     37    await testCachedRelation(r2, RELATION_MEMBER_OF, []);
     38    await testCachedRelation(r3, RELATION_MEMBER_OF, [r3, r5]);
     39    await testCachedRelation(r4, RELATION_MEMBER_OF, r4);
     40    await testCachedRelation(r5, RELATION_MEMBER_OF, [r3, r5]);
     41    await testCachedRelation(r6, RELATION_MEMBER_OF, r6);
     42 
     43    await invokeContentTask(browser, [], () => {
     44      content.document.getElementById("r5").name = "a";
     45    });
     46 
     47    await testCachedRelation(r3, RELATION_MEMBER_OF, r3);
     48    await testCachedRelation(r4, RELATION_MEMBER_OF, [r5, r4]);
     49    await testCachedRelation(r5, RELATION_MEMBER_OF, [r5, r4]);
     50  },
     51  { chrome: true, iframe: true, remoteIframe: true }
     52 );
     53 
     54 /*
     55 * Test MEMBER_OF relation caching on aria radio buttons
     56 */
     57 addAccessibleTask(
     58  `
     59  <div role="radio" id="r1">I have no radio group</div><br>
     60  <fieldset role="radiogroup" id="fs">
     61    <div role="radio" id="r2">hello</div><br>
     62    <div role="radio" id="r3">world</div><br>
     63  </fieldset>`,
     64  async function (browser, accDoc) {
     65    const r1 = findAccessibleChildByID(accDoc, "r1");
     66    const r2 = findAccessibleChildByID(accDoc, "r2");
     67    let r3 = findAccessibleChildByID(accDoc, "r3");
     68 
     69    await testCachedRelation(r1, RELATION_MEMBER_OF, []);
     70    await testCachedRelation(r2, RELATION_MEMBER_OF, [r2, r3]);
     71    await testCachedRelation(r3, RELATION_MEMBER_OF, [r2, r3]);
     72    const r = waitForEvent(EVENT_INNER_REORDER, "fs");
     73    await invokeContentTask(browser, [], () => {
     74      let innerRadio = content.document.getElementById("r3");
     75      content.document.body.appendChild(innerRadio);
     76    });
     77    await r;
     78 
     79    r3 = findAccessibleChildByID(accDoc, "r3");
     80    await testCachedRelation(r1, RELATION_MEMBER_OF, []);
     81    await testCachedRelation(r2, RELATION_MEMBER_OF, r2);
     82    await testCachedRelation(r3, RELATION_MEMBER_OF, []);
     83  },
     84  {
     85    chrome: true,
     86    iframe: true,
     87    remoteIframe: true,
     88  }
     89 );
     90 
     91 /*
     92 * Test mutation of LABEL relations via DOM ID reuse.
     93 */
     94 addAccessibleTask(
     95  `
     96  <div id="label">before</div><input id="input" aria-labelledby="label">
     97  `,
     98  async function (browser, accDoc) {
     99    let label = findAccessibleChildByID(accDoc, "label");
    100    const input = findAccessibleChildByID(accDoc, "input");
    101 
    102    await testCachedRelation(label, RELATION_LABEL_FOR, input);
    103    await testCachedRelation(input, RELATION_LABELLED_BY, label);
    104 
    105    const r = waitForEvent(EVENT_REORDER, accDoc);
    106    await invokeContentTask(browser, [], () => {
    107      content.document.getElementById("label").remove();
    108      let l = content.document.createElement("div");
    109      l.id = "label";
    110      l.textContent = "after";
    111      content.document.body.insertBefore(
    112        l,
    113        content.document.getElementById("input")
    114      );
    115    });
    116    await r;
    117    label = findAccessibleChildByID(accDoc, "label");
    118    await testCachedRelation(label, RELATION_LABEL_FOR, input);
    119    await testCachedRelation(input, RELATION_LABELLED_BY, label);
    120  },
    121  {
    122    chrome: true,
    123    iframe: true,
    124    remoteIframe: true,
    125  }
    126 );
    127 
    128 /*
    129 * Test LINKS_TO relation caching an anchor with multiple hashes
    130 */
    131 addAccessibleTask(
    132  `
    133  <a id="link" href="#foo#bar">Origin</a><br>
    134  <a id="anchor" name="foo#bar">Destination`,
    135  async function (browser, accDoc) {
    136    const link = findAccessibleChildByID(accDoc, "link");
    137    const anchor = findAccessibleChildByID(accDoc, "anchor");
    138 
    139    await testCachedRelation(link, RELATION_LINKS_TO, anchor);
    140  },
    141  {
    142    chrome: true,
    143    // IA2 doesn't have a LINKS_TO relation and Windows non-cached
    144    // RemoteAccessible uses IA2, so we can't run these tests in this case.
    145    topLevel: true,
    146    iframe: true,
    147    remoteIframe: true,
    148  }
    149 );
    150 
    151 /*
    152 * Test mutation of LABEL relations via accessible shutdown.
    153 */
    154 addAccessibleTask(
    155  `
    156  <input id="d"></input>
    157  <label id="l">
    158    <select id="s"></select>
    159  </label>
    160  `,
    161  async function (browser, accDoc) {
    162    const label = findAccessibleChildByID(accDoc, "l");
    163    const select = findAccessibleChildByID(accDoc, "s");
    164    const input = findAccessibleChildByID(accDoc, "d");
    165 
    166    await testCachedRelation(label, RELATION_LABEL_FOR, select);
    167    await testCachedRelation(select, RELATION_LABELLED_BY, label);
    168    await testCachedRelation(input, RELATION_LABELLED_BY, []);
    169    await untilCacheOk(() => {
    170      if (!browser.isRemoteBrowser) {
    171        return true;
    172      }
    173 
    174      try {
    175        // We should get an acc ID back from this, but we don't have a way of
    176        // verifying its correctness -- it should be the ID of the select.
    177        return label.cache.getStringProperty("for");
    178      } catch (e) {
    179        ok(false, "Exception thrown while trying to read from the cache");
    180        return false;
    181      }
    182    }, "Label for relation exists");
    183 
    184    const r = waitForEvent(EVENT_INNER_REORDER, "l");
    185    await invokeContentTask(browser, [], () => {
    186      content.document.getElementById("s").remove();
    187    });
    188    await r;
    189    await untilCacheOk(() => {
    190      if (!browser.isRemoteBrowser) {
    191        return true;
    192      }
    193 
    194      try {
    195        label.cache.getStringProperty("for");
    196      } catch (e) {
    197        // This property should no longer exist in the cache, so we should
    198        // get an exception if we try to fetch it.
    199        return true;
    200      }
    201      return false;
    202    }, "Label for relation exists");
    203 
    204    await invokeContentTask(browser, [], () => {
    205      const l = content.document.getElementById("l");
    206      l.htmlFor = "d";
    207    });
    208    await testCachedRelation(label, RELATION_LABEL_FOR, input);
    209    await testCachedRelation(input, RELATION_LABELLED_BY, label);
    210  },
    211  {
    212    chrome: true,
    213    iframe: true,
    214    remoteIframe: true,
    215    topLevel: true,
    216  }
    217 );
    218 
    219 /**
    220 * Test label relations on HTML figure/figcaption.
    221 */
    222 addAccessibleTask(
    223  `
    224 <figure id="figure1">
    225  before
    226  <figcaption id="caption1">caption1</figcaption>
    227  after
    228 </figure>
    229 <figure id="figure2" aria-labelledby="label">
    230  <figcaption id="caption2">caption2</figure>
    231 </figure>
    232 <div id="label">label</div>
    233  `,
    234  async function (browser, docAcc) {
    235    const figure1 = findAccessibleChildByID(docAcc, "figure1");
    236    let caption1 = findAccessibleChildByID(docAcc, "caption1");
    237    await testCachedRelation(figure1, RELATION_LABELLED_BY, caption1);
    238    await testCachedRelation(caption1, RELATION_LABEL_FOR, figure1);
    239 
    240    info("Hiding caption1");
    241    let mutated = waitForEvent(EVENT_HIDE, caption1);
    242    await invokeContentTask(browser, [], () => {
    243      content.document.getElementById("caption1").hidden = true;
    244    });
    245    await mutated;
    246    await testCachedRelation(figure1, RELATION_LABELLED_BY, []);
    247 
    248    info("Showing caption1");
    249    mutated = waitForEvent(EVENT_SHOW, "caption1");
    250    await invokeContentTask(browser, [], () => {
    251      content.document.getElementById("caption1").hidden = false;
    252    });
    253    caption1 = (await mutated).accessible;
    254    await testCachedRelation(figure1, RELATION_LABELLED_BY, caption1);
    255    await testCachedRelation(caption1, RELATION_LABEL_FOR, figure1);
    256 
    257    const figure2 = findAccessibleChildByID(docAcc, "figure2");
    258    const caption2 = findAccessibleChildByID(docAcc, "caption2");
    259    const label = findAccessibleChildByID(docAcc, "label");
    260    await testCachedRelation(figure2, RELATION_LABELLED_BY, [label, caption2]);
    261    await testCachedRelation(caption2, RELATION_LABEL_FOR, figure2);
    262    await testCachedRelation(label, RELATION_LABEL_FOR, figure2);
    263  },
    264  { chrome: true, topLevel: true }
    265 );
    266 
    267 /**
    268 * Test aria-owns morphs to controls relationship when container is combobox.
    269 */
    270 addAccessibleTask(
    271  `
    272  <div id="box" role="combobox"
    273         aria-owns="listbox"
    274         aria-expanded="true"
    275         aria-haspopup="listbox"
    276         aria-autocomplete="list"
    277         contenteditable="true"></div>
    278  <ul role="listbox" id="listbox">
    279    <li role="option">apple</li>
    280    <li role="option">peach</li>
    281  </ul>
    282 `,
    283  async (browser, accDoc) => {
    284    const combobox = findAccessibleChildByID(accDoc, "box");
    285    const listbox = findAccessibleChildByID(accDoc, "listbox");
    286 
    287    testStates(combobox, 0, EXT_STATE_EDITABLE, 0, 0);
    288    is(combobox.childCount, 0, "combobox has no children");
    289    await testCachedRelation(combobox, RELATION_CONTROLLER_FOR, [listbox]);
    290    await testCachedRelation(listbox, RELATION_CONTROLLED_BY, [combobox]);
    291 
    292    let expectedEvents = Promise.all([
    293      waitForStateChange(combobox, EXT_STATE_EDITABLE, false, true),
    294      waitForEvent(EVENT_REORDER, accDoc),
    295    ]);
    296    await invokeContentTask(browser, [], () => {
    297      content.document.getElementById("box").contentEditable = false;
    298    });
    299    await expectedEvents;
    300    await testCachedRelation(combobox, RELATION_CONTROLLER_FOR, []);
    301    await testCachedRelation(listbox, RELATION_CONTROLLED_BY, []);
    302    is(combobox.childCount, 1, "combobox has listbox");
    303  }
    304 );
    305 
    306 /*
    307 * Test relocated child preserves relation.
    308 */
    309 addAccessibleTask(
    310  `
    311  <div id="relocated">World</div>
    312  <div id="owner" aria-owns="relocated"></div>
    313  <button id="btn" aria-labelledby="relocated">Hello</button>
    314  `,
    315  async function testRelocationRelation(browser, docAcc) {
    316    const btn = findAccessibleChildByID(docAcc, "btn");
    317    const relocated = findAccessibleChildByID(docAcc, "relocated");
    318 
    319    await testCachedRelation(btn, RELATION_LABELLED_BY, relocated);
    320    await testCachedRelation(relocated, RELATION_LABEL_FOR, btn);
    321  },
    322  { chrome: true, topLevel: true }
    323 );
    324 
    325 /**
    326 * Test table caption.
    327 */
    328 addAccessibleTask(
    329  `
    330 <table id="table">
    331  <caption id="caption">caption</caption>
    332  <tr><th>a</th></tr>
    333 </table>
    334  `,
    335  async function testTableCaption(browser, docAcc) {
    336    const table = findAccessibleChildByID(docAcc, "table");
    337 
    338    const caption = findAccessibleChildByID(docAcc, "caption");
    339    await testCachedRelation(table, RELATION_LABELLED_BY, caption);
    340    await testCachedRelation(caption, RELATION_LABEL_FOR, table);
    341  },
    342  { chrome: true, topLevel: true }
    343 );
    344 
    345 /**
    346 * Test elements that are not label by spec do not get LABEL relations
    347 */
    348 addAccessibleTask(
    349  `
    350  <label id="label" for="btn">label</label>
    351  <div role="button" id="btn"></div>
    352  `,
    353  async function testLabelOnDiv(browser, docAcc) {
    354    const btn = findAccessibleChildByID(docAcc, "btn");
    355 
    356    const label = findAccessibleChildByID(docAcc, "label");
    357    await testCachedRelation(btn, RELATION_LABELLED_BY, []);
    358    await testCachedRelation(label, RELATION_LABEL_FOR, []);
    359  },
    360  { chrome: true, topLevel: true }
    361 );