tor-browser

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

browser_name_general.js (10457B)


      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/name.js */
      9 /* import-globals-from ../../mochitest/attributes.js */
     10 loadScripts(
     11  { name: "name.js", dir: MOCHITESTS_DIR },
     12  { name: "attributes.js", dir: MOCHITESTS_DIR }
     13 );
     14 /**
     15 * Test caching of the document title.
     16 */
     17 addAccessibleTask(
     18  ``,
     19  async function (browser, docAcc) {
     20    let nameChanged = waitForEvent(EVENT_NAME_CHANGE, docAcc);
     21    await invokeContentTask(browser, [], () => {
     22      content.document.title = "new title";
     23    });
     24    await nameChanged;
     25    testName(docAcc, "new title");
     26  },
     27  { chrome: true, topLevel: true, iframe: true, remoteIframe: true }
     28 );
     29 
     30 /**
     31 * Test that the name is updated when the content of a hidden aria-labelledby
     32 * subtree changes.
     33 */
     34 addAccessibleTask(
     35  `
     36 <button id="button" aria-labelledby="label"></button>
     37 <div id="label" hidden>a</div>
     38  `,
     39  async function (browser, docAcc) {
     40    const button = findAccessibleChildByID(docAcc, "button");
     41    testName(button, "a");
     42    info("Changing label textContent");
     43    let nameChanged = waitForEvent(EVENT_NAME_CHANGE, button);
     44    await invokeContentTask(browser, [], () => {
     45      content.document.getElementById("label").textContent = "c";
     46    });
     47    await nameChanged;
     48    testName(button, "c");
     49    info("Change label text node's data");
     50    nameChanged = waitForEvent(EVENT_NAME_CHANGE, button);
     51    await invokeContentTask(browser, [], () => {
     52      content.document.getElementById("label").firstChild.data = "d";
     53    });
     54    await nameChanged;
     55    testName(button, "d");
     56    info("Prepending text node to label");
     57    nameChanged = waitForEvent(EVENT_NAME_CHANGE, button);
     58    await invokeContentTask(browser, [], () => {
     59      content.document
     60        .getElementById("label")
     61        .prepend(content.document.createTextNode("b"));
     62    });
     63    await nameChanged;
     64    testName(button, "bd");
     65  },
     66  { chrome: true, topLevel: true, iframe: true, remoteIframe: true }
     67 );
     68 
     69 /**
     70 * Test that the name does not include aria-actions targets of itself.
     71 */
     72 addAccessibleTask(
     73  `<div role="tablist">
     74    <div role="tab" id="tab" aria-actions="close pin">Title
     75      <button id="close">Close</button>
     76      <button id="pin">Pin</button>
     77    </div>
     78  </div>`,
     79  async function testAriaActionInSubtree(browser, docAcc) {
     80    const tab = findAccessibleChildByID(docAcc, "tab");
     81    testName(tab, "Title");
     82 
     83    let nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
     84    invokeSetAttribute(browser, "tab", "aria-actions", "pin");
     85    await nameChanged;
     86    testName(tab, "Title Close");
     87 
     88    nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
     89    invokeSetAttribute(browser, "pin", "id", "broken-pin");
     90    await nameChanged;
     91    testName(tab, "Title Close Pin");
     92 
     93    nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
     94    invokeSetAttribute(browser, "tab", "aria-actions", "close pin");
     95    await nameChanged;
     96    testName(tab, "Title Pin");
     97 
     98    nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab);
     99    invokeSetAttribute(browser, "broken-pin", "id", "pin");
    100    await nameChanged;
    101    testName(tab, "Title");
    102  },
    103  { chrome: true, topLevel: true }
    104 );
    105 
    106 /**
    107 * Test abbr name change notification
    108 */
    109 addAccessibleTask(
    110  `<abbr id="abbr" title="JavaScript Object Notation">JSON</abbr>
    111   <abbr id="labelled-abbr" aria-label="YML"
    112         title="Yet Another Markup Language">YAML</abbr>`,
    113  async function testAbbrName(browser, docAcc) {
    114    const abbr = findAccessibleChildByID(docAcc, "abbr");
    115    testName(abbr, "JavaScript Object Notation");
    116 
    117    let nameChanged = waitForEvent(EVENT_NAME_CHANGE, abbr);
    118    invokeSetAttribute(browser, "abbr", "title", "Jason's Other Nettle");
    119    await nameChanged;
    120    testName(abbr, "Jason's Other Nettle");
    121 
    122    nameChanged = waitForEvent(EVENT_NAME_CHANGE, abbr);
    123    invokeSetAttribute(browser, "abbr", "title");
    124    await nameChanged;
    125    testName(abbr, null);
    126 
    127    const labelledAbbr = findAccessibleChildByID(docAcc, "labelled-abbr");
    128    testName(labelledAbbr, "YML");
    129 
    130    let events = waitForEvents({
    131      expected: [[EVENT_DESCRIPTION_CHANGE, labelledAbbr]],
    132      unexpected: [[EVENT_NAME_CHANGE, labelledAbbr]],
    133    });
    134    invokeSetAttribute(
    135      browser,
    136      "labelled-abbr",
    137      "title",
    138      "Your Another Marker Lye"
    139    );
    140    await events;
    141    testName(labelledAbbr, "YML");
    142    is(labelledAbbr.description, "Your Another Marker Lye");
    143 
    144    events = waitForEvents([
    145      [EVENT_NAME_CHANGE, labelledAbbr],
    146      // Bug 1997464 - When losing ARIA name, we lose the description that is used
    147      // now for the name.
    148      // [EVENT_DESCRIPTION_CHANGE, labelledAbbr],
    149    ]);
    150    invokeSetAttribute(browser, "labelled-abbr", "aria-label");
    151    await events;
    152    testName(labelledAbbr, "Your Another Marker Lye");
    153  },
    154  { chrome: true, topLevel: true }
    155 );
    156 
    157 /**
    158 * Test consistent doc name for remote and local docs.
    159 */
    160 addAccessibleTask(
    161  `<iframe id="iframe"></iframe>`,
    162  async function testDocName(browser, docAcc) {
    163    const iframe = findAccessibleChildByID(docAcc, "iframe");
    164    info("Setting iframe src");
    165    // This iframe won't finish loading. Thus, it will get the stale state and
    166    // won't fire a document load complete event. We use the reorder event on
    167    // the iframe to know when the document has been created.
    168    let reordered = waitForEvent(EVENT_REORDER, iframe);
    169    await invokeContentTask(browser, [], () => {
    170      content.document.getElementById("iframe").src =
    171        `data:text/html,<html><body>hey</body></html>`;
    172    });
    173    let iframeDoc = (await reordered).accessible.firstChild;
    174    is(iframeDoc.name, null, "Doc should have 'null' name");
    175    testAbsentAttrs(iframeDoc, { "explicit-name": "true" });
    176 
    177    reordered = waitForEvent(EVENT_REORDER, iframe);
    178    await invokeContentTask(browser, [], () => {
    179      content.document.getElementById("iframe").src =
    180        `data:text/html,<html><title>hello</title><body>hey</body></html>`;
    181    });
    182    iframeDoc = (await reordered).accessible.firstChild;
    183    is(iframeDoc.name, "hello", "Doc should have name");
    184    testAttrs(iframeDoc, { "explicit-name": "true" }, true);
    185  },
    186  { topLevel: true, chrome: true }
    187 );
    188 
    189 /*
    190 * All test cases taken from https://www.w3.org/TR/accname-1.1/
    191 * These were especially called out to demonstrate edge cases.
    192 * (migrated from mochitest/name/test_ARIACore_examples.html)
    193 */
    194 addAccessibleTask(
    195  `
    196  <!-- el1 should be labeled, el2 should not. -->
    197  <div id="el1" aria-labelledby="el3"></div>
    198  <div id="el2" aria-labelledby="el1"></div>
    199  <div id="el3"> hello </div>
    200 
    201  <!-- The buttons should be labeled by themselves and the referenced link -->
    202  <ul>
    203    <li>
    204      <a id="file_row1" href="./files/Documentation.pdf">Documentation.pdf</a>
    205      <span role="button" tabindex="0" id="del_row1" aria-label="Delete"
    206            aria-labelledby="del_row1 file_row1"></span>
    207    </li>
    208    <li>
    209      <a id="file_row2" href="./files/HolidayLetter.pdf">HolidayLetter.pdf</a>
    210      <span role="button" tabindex="0" id="del_row2" aria-label="Delete"
    211            aria-labelledby="del_row2 file_row2"></span>
    212    </li>
    213  </ul>
    214 
    215  <!-- Label from combined text and subtree -->
    216  <div id="chkbx" role="checkbox" aria-checked="false">Flash the screen
    217       <span role="textbox" aria-multiline="false"> 5 </span> times</div>
    218 
    219  <!-- Label with name from content should include table -->
    220  <input id="input_with_html_label" />
    221  <label for="input_with_html_label" id="label">
    222    <div>foo</div>
    223    <table><tr><td>bar</td></tr></table>
    224    <div>baz</div>
    225  </label>
    226 `,
    227  async function testARIACoreExamples(browser, docAcc) {
    228    function testName_(id, expected, cached) {
    229      const acc = findAccessibleChildByID(docAcc, id);
    230      if (browser.isRemoteBrowser) {
    231        is(
    232          acc.cache.has("name"),
    233          cached,
    234          `Name should ${cached ? "" : "not "}be in cache for '${id}'`
    235        );
    236      }
    237      testName(acc, expected);
    238    }
    239    // Example 1 from section 4.3.1 under 2.B.
    240    // Element1 should get its name from the text in element3.
    241    // Element2 should not get its name from element1 because that already
    242    // gets its name from another element.
    243    testName_("el1", "hello", false);
    244    testName_("el2", null, false);
    245 
    246    // Example 2 from section 4.3.1 under 2.C.
    247    // The buttons should get their name from their labels and the links.
    248    testName_("del_row1", "Delete Documentation.pdf", true);
    249    testName_("del_row2", "Delete HolidayLetter.pdf", true);
    250 
    251    // Example 3 from section 4.3.1 under 2.F.
    252    // Name should be own content text plus the value of the input plus
    253    // more own inner text, separated by 1 space.
    254    testName_("chkbx", "Flash the screen 5 times", false);
    255 
    256    // Example 4 from section 4.3.1 under 2.F.
    257    // Name from content should include all the child nodes, including
    258    // table cells.
    259    testName_("input_with_html_label", "foo bar baz", false);
    260  },
    261  { topLevel: true, chrome: true }
    262 );
    263 
    264 /*
    265 * Test labels that use ARIA naming in different ways.
    266 */
    267 addAccessibleTask(
    268  `<div id="label1">bye <a href="#" aria-labelledby="btn1">world</a></div>
    269   <button aria-labelledby="label1" id="btn1">hello</button>
    270   <div id="label2">bye <a href="#" aria-label="mars">world</a></div>
    271   <button aria-labelledby="label2" id="btn2">hello</button>
    272   <div id="label3" aria-label="mars">bye</div>
    273   <button aria-labelledby="label3" id="btn3">hello</button>`,
    274  async function testSomeInterestingLabels(browser, docAcc) {
    275    const btn1 = findAccessibleChildByID(docAcc, "btn1");
    276    const btn2 = findAccessibleChildByID(docAcc, "btn2");
    277    const btn3 = findAccessibleChildByID(docAcc, "btn3");
    278    // A button whose label subtree references the button
    279    testName(btn1, "bye world");
    280    // A button whose label subtree has an explicit aria-label
    281    testName(btn2, "bye mars");
    282    // A button whose label has an explicit aria-label of its own
    283    testName(btn3, "mars");
    284  },
    285  { topLevel: true, chrome: true }
    286 );
    287 
    288 addAccessibleTask(
    289  `<input id="input" type="text" title="title" placeholder="placeholder"></input>`,
    290  async function testInputPlaceHolder(browser, docAcc) {
    291    const input = findAccessibleChildByID(docAcc, "input");
    292    testName(input, "title");
    293  },
    294  { topLevel: true, chrome: true }
    295 );