tor-browser

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

browser_name_markup.js (40375B)


      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 /**
     16 * Rules for name tests that are inspired by
     17 *   accessible/tests/mochitest/name/markuprules.xul
     18 *
     19 * Each element in the list of rules represents a name calculation rule for a
     20 * particular test case.
     21 *
     22 * The rules have the following format:
     23 *   { attr } - calculated from attribute
     24 *   { elm } - calculated from another element
     25 *   { fromsubtree } - calculated from element's subtree
     26 *
     27 */
     28 const ARIARule = [{ attr: "aria-labelledby" }, { attr: "aria-label" }];
     29 const HTMLControlHeadRule = [...ARIARule, { elm: "label" }];
     30 const rules = {
     31  CSSContent: [{ elm: "style" }, { fromsubtree: true }],
     32  HTMLCell: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
     33  HTMLControl: [
     34    ...HTMLControlHeadRule,
     35    { fromsubtree: true },
     36    { attr: "title" },
     37  ],
     38  HTMLElm: [...ARIARule, { attr: "title" }],
     39  HTMLImg: [...ARIARule, { attr: "alt" }, { attr: "title" }],
     40  HTMLImgEmptyAlt: [...ARIARule, { attr: "title" }, { attr: "alt" }],
     41  HTMLInputButton: [
     42    ...HTMLControlHeadRule,
     43    { attr: "value" },
     44    { attr: "title" },
     45  ],
     46  HTMLInputImage: [
     47    ...HTMLControlHeadRule,
     48    { attr: "alt" },
     49    { attr: "value" },
     50    { attr: "title" },
     51  ],
     52  HTMLInputImageNoValidSrc: [
     53    ...HTMLControlHeadRule,
     54    { attr: "alt" },
     55    { attr: "value" },
     56  ],
     57  HTMLInputReset: [...HTMLControlHeadRule, { attr: "value" }],
     58  HTMLInputSubmit: [...HTMLControlHeadRule, { attr: "value" }],
     59  HTMLLink: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
     60  HTMLLinkImage: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
     61  HTMLOption: [
     62    ...ARIARule,
     63    { attr: "label" },
     64    { fromsubtree: true },
     65    { attr: "title" },
     66  ],
     67  HTMLTable: [
     68    ...ARIARule,
     69    { elm: "caption" },
     70    { attr: "summary" },
     71    { attr: "title" },
     72  ],
     73 };
     74 
     75 const markupTests = [
     76  {
     77    id: "btn",
     78    ruleset: "HTMLControl",
     79    markup: `
     80    <span id="l1">test2</span>
     81    <span id="l2">test3</span>
     82    <label for="btn">test4</label>
     83    <button id="btn"
     84            aria-label="test1"
     85            aria-labelledby="l1 l2"
     86            title="test5">press me</button>`,
     87    expected: ["test2 test3", "test1", "test4", "press me", "test5"],
     88  },
     89  {
     90    id: "btn",
     91    ruleset: "HTMLInputButton",
     92    markup: `
     93    <span id="l1">test2</span>
     94    <span id="l2">test3</span>
     95    <label for="btn">test4</label>
     96    <input id="btn"
     97           type="button"
     98           aria-label="test1"
     99           aria-labelledby="l1 l2"
    100           value="name from value"
    101           alt="no name from al"
    102           src="no name from src"
    103           data="no name from data"
    104           title="name from title"/>`,
    105    expected: [
    106      "test2 test3",
    107      "test1",
    108      "test4",
    109      "name from value",
    110      "name from title",
    111    ],
    112  },
    113  {
    114    id: "btn-submit",
    115    ruleset: "HTMLInputSubmit",
    116    markup: `
    117    <span id="l1">test2</span>
    118    <span id="l2">test3</span>
    119    <label for="btn-submit">test4</label>
    120    <input id="btn-submit"
    121           type="submit"
    122           aria-label="test1"
    123           aria-labelledby="l1 l2"
    124           value="name from value"
    125           alt="no name from atl"
    126           src="no name from src"
    127           data="no name from data"
    128           title="no name from title"/>`,
    129    expected: ["test2 test3", "test1", "test4", "name from value"],
    130  },
    131  {
    132    id: "btn-reset",
    133    ruleset: "HTMLInputReset",
    134    markup: `
    135    <span id="l1">test2</span>
    136    <span id="l2">test3</span>
    137    <label for="btn-reset">test4</label>
    138    <input id="btn-reset"
    139           type="reset"
    140           aria-label="test1"
    141           aria-labelledby="l1 l2"
    142           value="name from value"
    143           alt="no name from alt"
    144           src="no name from src"
    145           data="no name from data"
    146           title="no name from title"/>`,
    147    expected: ["test2 test3", "test1", "test4", "name from value"],
    148  },
    149  {
    150    id: "btn-image",
    151    ruleset: "HTMLInputImage",
    152    markup: `
    153    <span id="l1">test2</span>
    154    <span id="l2">test3</span>
    155    <label for="btn-image">test4</label>
    156    <input id="btn-image"
    157           type="image"
    158           aria-label="test1"
    159           aria-labelledby="l1 l2"
    160           alt="name from alt"
    161           value="name from value"
    162           src="http://example.com/a11y/accessible/tests/mochitest/moz.png"
    163           data="no name from data"
    164           title="name from title"/>`,
    165    expected: [
    166      "test2 test3",
    167      "test1",
    168      "test4",
    169      "name from alt",
    170      "name from value",
    171      "name from title",
    172    ],
    173  },
    174  {
    175    id: "btn-image",
    176    ruleset: "HTMLInputImageNoValidSrc",
    177    markup: `
    178    <span id="l1">test2</span>
    179    <span id="l2">test3</span>
    180    <label for="btn-image">test4</label>
    181    <input id="btn-image"
    182           type="image"
    183           aria-label="test1"
    184           aria-labelledby="l1 l2"
    185           alt="name from alt"
    186           value="name from value"
    187           data="no name from data"
    188           title="no name from title"/>`,
    189    expected: [
    190      "test2 test3",
    191      "test1",
    192      "test4",
    193      "name from alt",
    194      "name from value",
    195    ],
    196  },
    197  {
    198    id: "opt",
    199    ruleset: "HTMLOption",
    200    markup: `
    201    <span id="l1">test2</span>
    202    <span id="l2">test3</span>
    203    <select>
    204      <option id="opt"
    205              aria-label="test1"
    206              aria-labelledby="l1 l2"
    207              label="test4"
    208              title="test5">option1</option>
    209      <option>option2</option>
    210    </select>`,
    211    expected: ["test2 test3", "test1", "test4", "option1", "test5"],
    212  },
    213  {
    214    id: "img",
    215    ruleset: "HTMLImg",
    216    markup: `
    217    <span id="l1">test2</span>
    218    <span id="l2">test3</span>
    219    <img id="img"
    220         aria-label="Logo of Mozilla"
    221         aria-labelledby="l1 l2"
    222         alt="Mozilla logo"
    223         title="This is a logo"
    224         src="http://example.com/a11y/accessible/tests/mochitest/moz.png"/>`,
    225    expected: [
    226      "test2 test3",
    227      "Logo of Mozilla",
    228      "Mozilla logo",
    229      "This is a logo",
    230    ],
    231  },
    232  {
    233    id: "tc",
    234    ruleset: "HTMLCell",
    235    markup: `
    236    <span id="l1">test2</span>
    237    <span id="l2">test3</span>
    238    <label for="tc">test4</label>
    239    <table>
    240      <tr>
    241        <td id="tc"
    242            aria-label="test1"
    243            aria-labelledby="l1 l2"
    244            title="test5">
    245          <p>This is a paragraph</p>
    246          <a href="#">This is a link</a>
    247          <ul>
    248            <li>This is a list</li>
    249          </ul>
    250        </td>
    251      </tr>
    252    </table>`,
    253    expected: [
    254      "test2 test3",
    255      "test1",
    256      "This is a paragraph This is a link \u2022 This is a list",
    257      "test5",
    258    ],
    259  },
    260  {
    261    id: "gc",
    262    ruleset: "HTMLCell",
    263    markup: `
    264    <span id="l1">test2</span>
    265    <span id="l2">test3</span>
    266    <label for="gc">test4</label>
    267    <table>
    268      <tr>
    269        <td id="gc"
    270            role="gridcell"
    271            aria-label="test1"
    272            aria-labelledby="l1 l2"
    273            title="This is a paragraph This is a link This is a list">
    274          <p>This is a paragraph</p>
    275          <a href="#">This is a link</a>
    276          <ul>
    277            <li>Listitem1</li>
    278            <li>Listitem2</li>
    279          </ul>
    280        </td>
    281      </tr>
    282    </table>`,
    283    expected: [
    284      "test2 test3",
    285      "test1",
    286      "This is a paragraph This is a link \u2022 Listitem1 \u2022 Listitem2",
    287      "This is a paragraph This is a link This is a list",
    288    ],
    289  },
    290  {
    291    id: "t",
    292    ruleset: "HTMLTable",
    293    markup: `
    294    <span id="l1">lby_tst6_1</span>
    295    <span id="l2">lby_tst6_2</span>
    296    <label for="t">label_tst6</label>
    297    <table id="t"
    298           aria-label="arialabel_tst6"
    299           aria-labelledby="l1 l2"
    300           summary="summary_tst6"
    301           title="title_tst6">
    302      <caption>caption_tst6</caption>
    303      <tr>
    304        <td>cell1</td>
    305        <td>cell2</td>
    306      </tr>
    307    </table>`,
    308    expected: [
    309      "lby_tst6_1 lby_tst6_2",
    310      "arialabel_tst6",
    311      "caption_tst6",
    312      "summary_tst6",
    313      "title_tst6",
    314    ],
    315  },
    316  {
    317    id: "btn",
    318    ruleset: "CSSContent",
    319    markup: `
    320    <div role="main">
    321      <style>
    322        button::before {
    323          content: "do not ";
    324        }
    325      </style>
    326      <button id="btn">press me</button>
    327    </div>`,
    328    expected: ["do not press me", "press me"],
    329  },
    330  {
    331    // TODO: uncomment when Bug-1256382 is resoved.
    332    // id: 'li',
    333    // ruleset: 'CSSContent',
    334    // markup: `
    335    //   <style>
    336    //     ul {
    337    //       list-style-type: decimal;
    338    //     }
    339    //   </style>
    340    //   <ul id="ul">
    341    //     <li id="li">Listitem</li>
    342    //   </ul>`,
    343    // expected: ['1. Listitem', `${String.fromCharCode(0x2022)} Listitem`]
    344    // }, {
    345    id: "a",
    346    ruleset: "HTMLLink",
    347    markup: `
    348    <span id="l1">test2</span>
    349    <span id="l2">test3</span>
    350    <a id="a"
    351       href=""
    352       aria-label="test1"
    353       aria-labelledby="l1 l2"
    354       title="test4">test5</a>`,
    355    expected: ["test2 test3", "test1", "test5", "test4"],
    356  },
    357  {
    358    id: "a-img",
    359    ruleset: "HTMLLinkImage",
    360    markup: `
    361    <span id="l1">test2</span>
    362    <span id="l2">test3</span>
    363    <a id="a-img"
    364       href=""
    365       aria-label="test1"
    366       aria-labelledby="l1 l2"
    367       title="test4"><img alt="test5"/></a>`,
    368    expected: ["test2 test3", "test1", "test5", "test4"],
    369  },
    370 ];
    371 
    372 /**
    373 * Test accessible name that is calculated from an attribute, remove the
    374 * attribute before proceeding to the next name test. If attribute removal
    375 * results in a reorder or text inserted event - wait for it. If accessible
    376 * becomes defunct, update its reference using the one that is attached to one
    377 * of the above events.
    378 *
    379 * @param {object} browser      current "tabbrowser" element
    380 * @param {object} target       { acc, id } structure that contains an
    381 *                               accessible and its content element
    382 *                               id.
    383 * @param {object} rule         current attr rule for name calculation
    384 * @param {[type]} expected     expected name value
    385 */
    386 async function testAttrRule(browser, target, rule, expected) {
    387  let { id, acc } = target;
    388  let { attr } = rule;
    389 
    390  testName(acc, expected);
    391 
    392  let nameChange = waitForEvent(EVENT_NAME_CHANGE, id);
    393  await invokeContentTask(browser, [id, attr], (contentId, contentAttr) => {
    394    content.document.getElementById(contentId).removeAttribute(contentAttr);
    395  });
    396  let event = await nameChange;
    397 
    398  // Update accessible just in case it is now defunct.
    399  target.acc = findAccessibleChildByID(event.accessible, id);
    400 }
    401 
    402 /**
    403 * Test accessible name that is calculated from an element name, remove the
    404 * element before proceeding to the next name test. If element removal results
    405 * in a reorder event - wait for it. If accessible becomes defunct, update its
    406 * reference using the one that is attached to a possible reorder event.
    407 *
    408 * @param {object} browser      current "tabbrowser" element
    409 * @param {object} target       { acc, id } structure that contains an
    410 *                               accessible and its content element
    411 *                               id.
    412 * @param {object} rule         current elm rule for name calculation
    413 * @param {[type]} expected     expected name value
    414 */
    415 async function testElmRule(browser, target, rule, expected) {
    416  let { id, acc } = target;
    417  let { elm } = rule;
    418 
    419  testName(acc, expected);
    420  let nameChange = waitForEvent(EVENT_NAME_CHANGE, id);
    421 
    422  await invokeContentTask(browser, [elm], contentElm => {
    423    content.document.querySelector(`${contentElm}`).remove();
    424  });
    425  let event = await nameChange;
    426 
    427  // Update accessible just in case it is now defunct.
    428  target.acc = findAccessibleChildByID(event.accessible, id);
    429 }
    430 
    431 /**
    432 * Test accessible name that is calculated from its subtree, remove the subtree
    433 * and wait for a reorder event before proceeding to the next name test. If
    434 * accessible becomes defunct, update its reference using the one that is
    435 * attached to a reorder event.
    436 *
    437 * @param {object} browser      current "tabbrowser" element
    438 * @param {object} target       { acc, id } structure that contains an
    439 *                               accessible and its content element
    440 *                               id.
    441 * @param {object} rule         current subtree rule for name calculation
    442 * @param {[type]} expected     expected name value
    443 */
    444 async function testSubtreeRule(browser, target, rule, expected) {
    445  let { id, acc } = target;
    446 
    447  testName(acc, expected);
    448  let nameChange = waitForEvent(EVENT_NAME_CHANGE, id);
    449 
    450  await invokeContentTask(browser, [id], contentId => {
    451    let elm = content.document.getElementById(contentId);
    452    while (elm.firstChild) {
    453      elm.firstChild.remove();
    454    }
    455  });
    456  let event = await nameChange;
    457 
    458  // Update accessible just in case it is now defunct.
    459  target.acc = findAccessibleChildByID(event.accessible, id);
    460 }
    461 
    462 /**
    463 * Iterate over a list of rules and test accessible names for each one of the
    464 * rules.
    465 *
    466 * @param {object} browser      current "tabbrowser" element
    467 * @param {object} target       { acc, id } structure that contains an
    468 *                               accessible and its content element
    469 *                               id.
    470 * @param {Array}  ruleset      A list of rules to test a target with
    471 * @param {Array}  expected     A list of expected name value for each rule
    472 */
    473 async function testNameRule(browser, target, ruleset, expected) {
    474  for (let i = 0; i < ruleset.length; ++i) {
    475    let rule = ruleset[i];
    476    let testFn;
    477    if (rule.attr) {
    478      testFn = testAttrRule;
    479    } else if (rule.elm) {
    480      testFn = testElmRule;
    481    } else if (rule.fromsubtree) {
    482      testFn = testSubtreeRule;
    483    }
    484    await testFn(browser, target, rule, expected[i]);
    485  }
    486 }
    487 
    488 markupTests.forEach(({ id, ruleset, markup, expected }) =>
    489  addAccessibleTask(
    490    markup,
    491    async function (browser, accDoc) {
    492      const observer = {
    493        observe(subject) {
    494          const event = subject.QueryInterface(nsIAccessibleEvent);
    495          console.log(eventToString(event));
    496        },
    497      };
    498      Services.obs.addObserver(observer, "accessible-event");
    499      // Find a target accessible from an accessible subtree.
    500      let acc = findAccessibleChildByID(accDoc, id);
    501      let target = { id, acc };
    502      await testNameRule(browser, target, rules[ruleset], expected);
    503      Services.obs.removeObserver(observer, "accessible-event");
    504    },
    505    { iframe: true, remoteIframe: true }
    506  )
    507 );
    508 
    509 /**
    510 * Generic test cases ported from mochitest/name/test_general.html
    511 */
    512 addAccessibleTask(
    513  `
    514  <!-- aria-label, simple label -->
    515  <span id="btn_simple_aria_label" role="button" aria-label="I am a button"/>
    516  <br/>
    517  <!-- aria-label plus aria-labelledby -->
    518  <span id="btn_both_aria_labels" role="button" aria-label="I am a button, two"
    519        aria-labelledby="labelledby_text btn_both_aria_labels"/>
    520  <br/>
    521 
    522  <!-- aria-labelledby, single relation -->
    523  <span id="labelledby_text">text</span>
    524  <button id="btn_labelledby_text"
    525          aria-labelledby="labelledby_text">1</button>
    526  <br/>
    527 
    528  <!-- aria-labelledby, multiple relations -->
    529  <span id="labelledby_text1">text1</span>
    530  <span id="labelledby_text2">text2</span>
    531  <button id="btn_labelledby_texts"
    532          aria-labelledby="labelledby_text1 labelledby_text2">2</button>
    533  <br/>
    534 
    535  <!-- name from named accessible -->
    536  <input id="labelledby_namedacc" type="checkbox"
    537         aria-label="Data" />
    538  <input id="input_labelledby_namedacc"
    539          aria-labelledby="labelledby_namedacc" />
    540 
    541  <!-- the name from subtree, mixed content -->
    542  <span id="labelledby_mixed">no<span>more text</span></span>
    543  <button id="btn_labelledby_mixed"
    544          aria-labelledby="labelledby_mixed">3</button>
    545  <br/>
    546 
    547  <!-- the name from subtree, mixed/hidden content -->
    548  <span id="labelledby_mixed_hidden_child">
    549    no<span>more
    550      <span style="display: none;">hidden</span>
    551      text2
    552      <span style="visibility: hidden">hidden2</span>
    553    </span>
    554  </span>
    555  <button id="btn_labelledby_mixed_hidden_child"
    556          aria-labelledby="labelledby_mixed_hidden_child">3.1</button>
    557  <br/>
    558 
    559  <!-- the name from subtree, mixed/completely hidden content -->
    560  <span id="labelledby_mixed_hidden"
    561        style="display: none;">lala <span>more hidden </span>text</span>
    562  <button id="btn_labelledby_mixed_hidden"
    563          aria-labelledby="labelledby_mixed_hidden">3.2</button>
    564  <br/>
    565 
    566  <!-- the name from subtree, mixed content, block structure -->
    567  <div id="labelledby_mixed_block"><div>text</div>more text</div></div>
    568  <button id="btn_labelledby_mixed_block"
    569          aria-labelledby="labelledby_mixed_block">4</button>
    570  <br/>
    571 
    572  <!-- the name from subtree, mixed content, table structure -->
    573  <table><tr>
    574    <td id="labelledby_mixed_table">text<span>TEXT</span>text</td>
    575  </tr></table>
    576  <button id="btn_labelledby_mixed_table"
    577          aria-labelledby="labelledby_mixed_table">5</button>
    578  <br/>
    579 
    580  <!-- the name from subtree, child img -->
    581  <span id="labelledby_mixed_img">text<img alt="image"/></span>
    582  <button id="btn_labelledby_mixed_img"
    583          aria-labelledby="labelledby_mixed_img">6</button>
    584  <br/>
    585 
    586  <!-- the name from subtree, child inputs -->
    587  <span id="labelledby_mixed_input">
    588    <input type="button" id="input_button" title="input button"/>
    589    <input type="submit" id="input_submit"/>
    590    <input type="reset" id="input_reset"/>
    591    <input type="image" id="input_image" title="input image"/>
    592  </span>
    593  <button id="btn_labelledby_mixed_input"
    594          aria-labelledby="labelledby_mixed_input">7</button>
    595  <br/>
    596 
    597  <!-- the name from subtree, child object -->
    598  <span id="labelledby_mixed_object">
    599    <object data="about:blank" title="object"></object>
    600  </span>
    601  <button id="btn_labelledby_mixed_object"
    602          aria-labelledby="labelledby_mixed_object">8</button>
    603  <br/>
    604 
    605  <!-- the name from subtree, child br -->
    606  <span id="labelledby_mixed_br">text<br/>text</span>
    607  <button id="btn_labelledby_mixed_br"
    608          aria-labelledby="labelledby_mixed_br">9</button>
    609  <br/>
    610 
    611  <!-- the name from subtree, name from label content rather than from its title
    612    attribute -->
    613  <label  for="from_label_ignoretitle"
    614          title="Select your country of origin">Country:</label>
    615  <select id="from_label_ignoretitle">
    616    <option>Germany</option>
    617    <option>Russia</option>
    618  </select>
    619 
    620  <!-- the name from subtree, name from html:p content rather than from its
    621    title attribute -->
    622  <p id="p_ignoretitle"
    623     title="Select your country of origin">Choose country from.</p>
    624  <select id="from_p_ignoretitle" aria-labelledby="p_ignoretitle">
    625    <option>Germany</option>
    626    <option>Russia</option>
    627  </select>
    628 
    629  <!-- the name from subtree, name from html:input value rather than from its
    630    title attribute -->
    631  <p id="from_input_ignoretitle" aria-labelledby="input_ignoretitle">Country</p>
    632  <input id="input_ignoretitle"
    633         value="Custom country"
    634         title="Input your country of origin"/>
    635 
    636  <!-- name from subtree, surround control by spaces to not jam the text -->
    637  <label id="insert_spaces_around_control">
    638    start<input value="value">end
    639  </label>
    640 
    641  <!-- no name from subtree because it holds whitespaces only -->
    642  <a id="from_label_ignore_ws_subtree" href="about:mozilla" title="about">&nbsp;&nbsp;  </a>
    643 
    644  <!-- Don't use subtree unless referenced by aria-labelledby. -->
    645  <div id="alert" role="alert">Error</div>
    646  <input type="text" id="inputLabelledByAlert" aria-labelledby="alert">
    647 
    648  <!-- label element, label contains control -->
    649  <label>text<button id="btn_label_inside">10</button>text</label>
    650  <br/>
    651 
    652  <!-- label element, label and the button are in the same form -->
    653  <form>
    654    <label for="btn_label_inform">in form</label>
    655    <button id="btn_label_inform">11</button>
    656  </form>
    657 
    658  <!-- label element, label is outside of the form of the button -->
    659  <label for="btn_label_outform">out form</label>
    660  <form>
    661    <button id="btn_label_outform">12</button>
    662  </form>
    663 
    664  <!-- label element, label and the button are in the same document -->
    665  <label for="btn_label_indocument">in document</label>
    666  <button id="btn_label_indocument">13</button>
    667 
    668  <!-- multiple label elements for single button -->
    669  <label for="btn_label_multi">label1</label>
    670  <label for="btn_label_multi">label2</label>
    671  <button id="btn_label_multi">button</button>
    672 
    673  <!-- a label containing more than one controls -->
    674  <label>
    675    Enable <input id="ctrl_in_label_1" type="checkbox"> a
    676    <input id="ctrl_in_label_2" type="button" value="button"> control
    677  </label>
    678 
    679  <!-- name from children -->
    680  <span id="btn_children" role="button">14</span>
    681 
    682  <!-- no name from content, ARIA role overrides this rule -->
    683  <button id="btn_nonamefromcontent" role="img">1</button>
    684 
    685  <!-- name from children, hidden children -->
    686  <div role="listbox" tabindex="0">
    687    <div id="lb_opt1_children_hidden" role="option" tabindex="0">
    688      <span>i am visible</span>
    689      <span style="display:none">i am hidden</span>
    690    </div>
    691  </div>
    692 
    693  <table role="menu">
    694    <tr role="menuitem" id="tablemenuitem">
    695      <td>menuitem 1</td>
    696    </tr>
    697    <tr role="menuitem">
    698      <td>menuitem 2</td>
    699    </tr>
    700  </table>
    701 
    702  <label id="label_with_acronym">
    703    <acronym title="O A T F">OATF</acronym>
    704    <abbr title="World Wide Web">WWW</abbr>
    705  </label>
    706 
    707  <div id="testArticle" role="article" title="Test article">
    708    <p>This is a paragraph inside the article.</p>
    709  </div>
    710 
    711  <h1 id="h1" title="oops">heading</h1>
    712  <div role="heading" id="aria_heading">aria_heading</div>
    713 
    714  <!-- name from title attribute -->
    715  <span id="btn_title" role="group" title="title">15</span>
    716 
    717  <!-- A textarea nested in a label with a text child (bug #453371). -->
    718  <form>
    719    <label>Story
    720      <textarea id="textareawithchild" name="name">Foo</textarea>
    721      is ended.
    722    </label>
    723  </form>
    724 
    725  <!-- controls having a value used as part of computed name -->
    726  <input type="checkbox" id="ctrlvalue_progressbar:input">
    727  <label for="ctrlvalue_progressbar:input">
    728    foo <span role="progressbar"
    729               aria-valuenow="5" aria-valuemin="1"
    730               aria-valuemax="10">5</span> baz
    731  </label>
    732 
    733  <input type="checkbox" id="ctrlvalue_scrollbar:input" />
    734  <label for="ctrlvalue_scrollbar:input">
    735    foo <span role="scrollbar"
    736              aria-valuenow="5" aria-valuemin="1"
    737              aria-valuemax="10">5</span> baz
    738  </label>
    739 
    740  <input type="checkbox" id="ctrlvalue_slider:input">
    741  <label for="ctrlvalue_slider:input">
    742    foo <input role="slider" type="range"
    743               value="5" min="1" max="10"
    744               aria-valuenow="5" aria-valuemin="1"
    745               aria-valuemax="10"> baz
    746  </label>
    747 
    748  <input type="checkbox" id="ctrlvalue_spinbutton:input">
    749  <label for="ctrlvalue_spinbutton:input">
    750    foo <input role="spinbutton" type="number"
    751               value="5" min="1" max="10"
    752               aria-valuenow="5" aria-valuemin="1"
    753               aria-valuemax="10">
    754    baz
    755  </label>
    756 
    757  <input type="checkbox" id="ctrlvalue_combobox:input">
    758  <label for="ctrlvalue_combobox:input">
    759    foo
    760    <div role="combobox">
    761      <div role="textbox"></div>
    762      <ul role="listbox" style="list-style-type: none;">
    763        <li role="option">1</li>
    764        <li role="option" aria-selected="true">5</li>
    765        <li role="option">3</li>
    766      </ul>
    767    </div>
    768    baz
    769  </label>
    770 
    771  <input type="checkbox" id="ctrlvalue_meter:input">
    772  <label for="ctrlvalue_meter:input">
    773    foo
    774    <meter>5</meter>
    775    baz
    776  </label>
    777 
    778  <!-- a label with a nested control in the start, middle and end -->
    779  <form>
    780    <!-- at the start (without and with whitespaces) -->
    781    <label id="comboinstart"><select id="combo3">
    782        <option>One</option>
    783        <option>Two</option>
    784      </select>
    785      day(s).
    786    </label>
    787 
    788    <label id="textboxinstart">
    789      <input id="textbox1" value="Two">
    790      days.
    791    </label>
    792 
    793    <!-- in the middle -->
    794    <label id="comboinmiddle">
    795      Subscribe to
    796      <select id="combo4" name="occupation">
    797        <option>ATOM</option>
    798        <option>RSS</option>
    799      </select>
    800      feed.
    801    </label>
    802 
    803    <label id="comboinmiddle2" for="checkbox">Play the
    804      <select id="combo5">
    805        <option>Haliluya</option>
    806        <option>Hurra</option>
    807      </select>
    808      sound when new mail arrives
    809    </label>
    810    <input id="checkbox" type="checkbox" />
    811 
    812    <label id="comboinmiddle3" for="combo6">Play the
    813      <select id="combo6">
    814        <option>Haliluya</option>
    815        <option>Hurra</option>
    816      </select>
    817      sound when new mail arrives
    818    </label>
    819 
    820    <!-- at the end (without and with whitespaces) -->
    821    <label id="comboinend">
    822      This day was
    823      <select id="combo7" name="occupation">
    824        <option>sunny</option>
    825        <option>rainy</option>
    826      </select></label>
    827 
    828    <label id="textboxinend">
    829      This day was
    830      <input id="textbox2" value="sunny">
    831    </label>
    832  </form>
    833 
    834  <!-- placeholder  -->
    835  <input id="ph_password" type="password" value="" placeholder="a placeholder" />
    836  <input id="ph_text" type="text" placeholder="a placeholder" />
    837  <textarea id="ph_textarea" cols="5" placeholder="a placeholder"></textarea>
    838 
    839  <!-- placeholder does not win -->
    840  <input id="ph_text2" type="text" aria-label="a label" placeholder="meh" />
    841  <textarea id="ph_textarea2" cols="5" aria-labelledby="ph_text2"
    842            placeholder="meh"></textarea>
    843 
    844  <label for="ph_text3">a label</label>
    845  <input id="ph_text3" placeholder="meh" />
    846 
    847  <p>Image:
    848    <img id="img_eq" role="math" src="foo" alt="x^2 + y^2 + z^2">
    849    <input type="image"  id="input_img_eq" src="foo" alt="x^2 + y^2 + z^2">
    850  </p>
    851 
    852  <p>Text:
    853    <span id="txt_eq" role="math" title="x^2 + y^2 + z^2">x<sup>2</sup> +
    854      y<sup>2</sup> + z<sup>2</sup></span>
    855  </p>
    856 
    857  <!-- duplicate announcement -->
    858  <div id="test_note" role="note">subtree</div>
    859 
    860  <!-- No name for tr from its sub tree -->
    861  <table><tr id="NoNameForTR"><th>a</th><td>b</td></tr></table>
    862  <table style="display: block;">
    863    <tr id="NoNameForNonStandardTR" style="display:block;">
    864      <th>a</th><td>b</td>
    865    </tr>
    866  </table>
    867 
    868  <!-- Name from sub tree of tr, because it has a strong ARIA role -->
    869  <table><tr id="NameForTRBecauseStrongARIA" role="row"><th>a</th><td>b</td></tr></table>
    870 
    871  <!-- No name for tr because of weak (landmark) role -->
    872  <table><tr id="NoNameForTRBecauseWeakARIA" role="main"><th>a</th><td>b</td></tr></table>
    873 
    874  <!-- Name from subtree of grouping if requested by other object -->
    875  <div id="grouping" role="group">label</div>
    876  <button id="requested_name_from_grouping" aria-labelledby="grouping"></button>
    877  <!-- Name from sub tree of tbody marked as display:block;, which is also a grouping -->
    878  <div role="list">
    879    <div id="listitem_containing_block_tbody" role="listitem">
    880      <table>
    881        <tbody style="display: block;">
    882          <tr><td>label</td></tr>
    883        </tbody>
    884      </table>
    885    </div>
    886  </div>
    887  <!-- Name from subtree of treeitem containing grouping -->
    888  <div role="tree">
    889    <div id="treeitem_containing_grouping" role="treeitem" aria-level="1" aria-expanded="true">root
    890      <div role="group">
    891        <div role="treeitem" aria-level="2">sub</div>
    892      </div>
    893    </div>
    894  </div>
    895 
    896  <!-- Name from subtree of grouping labelled by an ancestor. -->
    897  <div id="grouping_ancestor_label">label
    898    <div id="grouping_labelledby_ancestor" role="group" aria-labelledby="grouping_ancestor_label">
    899      This content should not be included in the grouping's label.
    900    </div>
    901  </div>
    902 
    903  <!-- Text nodes and inline elements. -->
    904  <div role="listbox">
    905    <div id="container_text_inline" role="option">a<strong>b</strong>c</div>
    906    <!-- Text nodes and block elements. -->
    907    <div id="container_text_block" role="option">a<p>b</p>c</div>
    908    <!-- Text nodes and empty block elements. -->
    909    <div id="container_text_emptyblock" role="option">a<p></p><p></p>b</div>
    910  </div>
    911 
    912  <!-- aria-labelledby referring to a slot -->
    913  <div id="shadowHost">
    914    shadowButtonVisibleText
    915    <span slot="hiddenSlot">shadowButtonHiddenText</span>
    916  </div>
    917  <template id="shadowTemplate">
    918    <input type="button" id="shadowButtonVisibleText" aria-labelledby="visibleSlot">
    919    <slot id="visibleSlot"></slot>
    920    <input type="button" id="shadowButtonHiddenText" aria-labelledby="hiddenSlot">
    921    <slot id="hiddenSlot" name="hiddenSlot" hidden></slot>
    922  </template>
    923 
    924  <!-- aria-labelledby referring to a hidden container with script/style -->
    925  <button id="buttonScriptStyle" aria-labelledby="hiddenScriptStyle"></button>
    926  <div id="hiddenScriptStyle" hidden>
    927    <script> 42; </script>
    928    <style> .noOp {} </style>
    929    <span>content</span>
    930  </div>
    931 
    932  <!-- Name from subtree on link including <code>, etc. -->
    933  <a id="linkWithCodeSupSubInsDel" href="#">
    934    before
    935    <code>code</code>
    936    <sup>sup</sup>
    937    <sub>sub</sub>
    938    <ins>ins</ins>
    939    <del>del</del>
    940    after
    941  </a>
    942 `,
    943  async function testGeneric(browser, docAcc) {
    944    // aria-label
    945    function testName_(id, expectedName) {
    946      const acc = findAccessibleChildByID(docAcc, id);
    947      testName(acc, expectedName);
    948    }
    949 
    950    // Simple label provided via ARIA
    951    testName_("btn_simple_aria_label", "I am a button");
    952 
    953    // aria-label and aria-labelledby, expect aria-labelledby
    954    testName_("btn_both_aria_labels", "text I am a button, two");
    955 
    956    // ////////////////////////////////////////////////////////////////////////
    957    // aria-labelledby
    958 
    959    // Single relation. The value of 'aria-labelledby' contains the ID of
    960    // an element. Gets the name from text node of that element.
    961    testName_("btn_labelledby_text", "text");
    962 
    963    // Multiple relations. The value of 'aria-labelledby' contains the IDs
    964    // of elements. Gets the name from text nodes of those elements.
    965    testName_("btn_labelledby_texts", "text1 text2");
    966 
    967    // ////////////////////////////////////////////////////////////////////////
    968    // Name from named accessible
    969 
    970    testName_("input_labelledby_namedacc", "Data");
    971 
    972    // ////////////////////////////////////////////////////////////////////////
    973    // Name from subtree (single relation labelled_by).
    974 
    975    // Gets the name from text nodes contained by nested elements
    976    testName_("btn_labelledby_mixed", "nomore text");
    977 
    978    // Gets the name from text nodes contained by nested elements, ignores
    979    // hidden elements (bug 443081).
    980    testName_("btn_labelledby_mixed_hidden_child", "nomore text2");
    981 
    982    // Gets the name from hidden text nodes contained by nested elements,
    983    // (label element is hidden entirely), (bug 443081).
    984    testName_("btn_labelledby_mixed_hidden", "lala more hidden text");
    985 
    986    // Gets the name from text nodes contained by nested elements having block
    987    // representation (every text node value in the name should be divided by
    988    // spaces)
    989    testName_("btn_labelledby_mixed_block", "text more text");
    990 
    991    // Gets the name from text nodes contained by html:td. The text nodes
    992    // should not be divided by spaces.
    993    testName_("btn_labelledby_mixed_table", "textTEXTtext");
    994 
    995    // Gets the name from image accessible.
    996    testName_("btn_labelledby_mixed_img", "text image");
    997 
    998    // Gets the name from input accessibles
    999    // Note: if input have label elements then the name isn't calculated
   1000    // from them.
   1001    testName_(
   1002      "btn_labelledby_mixed_input",
   1003      "input button Submit Query Reset Submit Query"
   1004    );
   1005 
   1006    // Gets the name from the title of object element.
   1007    testName_("btn_labelledby_mixed_object", "object");
   1008 
   1009    // Gets the name from text nodes. Element br adds space between them.
   1010    testName_("btn_labelledby_mixed_br", "text text");
   1011 
   1012    // Gets the name from label content which allows name from subtree,
   1013    // ignore @title attribute on label
   1014    testName_("from_label_ignoretitle", "Country:");
   1015 
   1016    // Gets the name from html:p content, which doesn't allow name from
   1017    // subtree, ignore @title attribute on label
   1018    testName_("from_p_ignoretitle", "Choose country from.");
   1019 
   1020    // Gets the name from html:input value, ignore @title attribute on input
   1021    testName_("from_input_ignoretitle", "Custom country");
   1022 
   1023    // Insert spaces around the control's value to not jam sibling text nodes
   1024    testName_("insert_spaces_around_control", "start value end");
   1025 
   1026    // Gets the name from @title, ignore whitespace content
   1027    testName_("from_label_ignore_ws_subtree", "about");
   1028 
   1029    // role="alert" doesn't get name from subtree...
   1030    testName_("alert", null);
   1031    // but the subtree is used if referenced by aria-labelledby.
   1032    testName_("inputLabelledByAlert", "Error");
   1033 
   1034    // ////////////////////////////////////////////////////////////////////////
   1035    // label element
   1036 
   1037    // The label element contains the button. The name of the button is
   1038    // calculated from the content of the label.
   1039    // Note: the name does not contain the content of the button.
   1040    testName_("btn_label_inside", "texttext");
   1041 
   1042    // The label element and the button are placed in the same form. Gets
   1043    // the name from the label subtree.
   1044    testName_("btn_label_inform", "in form");
   1045 
   1046    // The label element is placed outside of form where the button is.
   1047    // Take into account the label.
   1048    testName_("btn_label_outform", "out form");
   1049 
   1050    // The label element and the button are in the same document. Gets the
   1051    // name from the label subtree.
   1052    testName_("btn_label_indocument", "in document");
   1053 
   1054    // Multiple label elements for single button
   1055    testName_("btn_label_multi", "label1 label2");
   1056 
   1057    // Multiple controls inside a label element
   1058    testName_("ctrl_in_label_1", "Enable a button control");
   1059    testName_("ctrl_in_label_2", "button");
   1060 
   1061    // ////////////////////////////////////////////////////////////////////////
   1062    // name from children
   1063 
   1064    // ARIA role button is presented allowing the name calculation from
   1065    // children.
   1066    testName_("btn_children", "14");
   1067 
   1068    // html:button, no name from content
   1069    testName_("btn_nonamefromcontent", null);
   1070 
   1071    // ARIA role option is presented allowing the name calculation from
   1072    // visible children (bug 443081).
   1073    testName_("lb_opt1_children_hidden", "i am visible");
   1074 
   1075    // Get the name from subtree of menuitem crossing role nothing to get
   1076    // the name from its children.
   1077    testName_("tablemenuitem", "menuitem 1");
   1078 
   1079    // Get the name from child acronym title attribute rather than from
   1080    // acronym content.
   1081    testName_("label_with_acronym", "O A T F World Wide Web");
   1082 
   1083    testName_("testArticle", "Test article");
   1084 
   1085    testName_("h1", "heading");
   1086    testName_("aria_heading", "aria_heading");
   1087 
   1088    // ////////////////////////////////////////////////////////////////////////
   1089    // title attribute
   1090 
   1091    // If nothing is left. Let's try title attribute.
   1092    testName_("btn_title", "title");
   1093 
   1094    // ////////////////////////////////////////////////////////////////////////
   1095    // textarea name
   1096 
   1097    // textarea's name should not have the value, which initially is specified
   1098    // by a text child.
   1099    testName_("textareawithchild", "Story is ended.");
   1100 
   1101    // new textarea name should not reflect the value change.
   1102    let valueChanged = waitForEvent(
   1103      EVENT_TEXT_VALUE_CHANGE,
   1104      "textareawithchild"
   1105    );
   1106    await invokeContentTask(browser, [], () => {
   1107      content.document.getElementById("textareawithchild").value = "Bar";
   1108    });
   1109    await valueChanged;
   1110 
   1111    testName_("textareawithchild", "Story is ended.");
   1112 
   1113    // ////////////////////////////////////////////////////////////////////////
   1114    // controls having a value used as a part of computed name
   1115 
   1116    testName_("ctrlvalue_progressbar:input", "foo 5 baz");
   1117    testName_("ctrlvalue_scrollbar:input", "foo 5 baz");
   1118    testName_("ctrlvalue_slider:input", "foo 5 baz");
   1119    testName_("ctrlvalue_spinbutton:input", "foo 5 baz");
   1120    testName_("ctrlvalue_combobox:input", "foo 5 baz");
   1121    testName_("ctrlvalue_meter:input", "foo 5 baz");
   1122 
   1123    // ///////////////////////////////////////////////////////////////////////
   1124    // label with nested combobox (test for 'f' item of name computation guide)
   1125 
   1126    testName_("comboinstart", "One day(s).");
   1127    testName_("combo3", "day(s).");
   1128 
   1129    testName_("textboxinstart", "Two days.");
   1130    testName_("textbox1", "days.");
   1131 
   1132    testName_("comboinmiddle", "Subscribe to ATOM feed.");
   1133    testName_("combo4", "Subscribe to feed.");
   1134 
   1135    testName_(
   1136      "comboinmiddle2",
   1137      "Play the Haliluya sound when new mail arrives"
   1138    );
   1139    testName_("combo5", null); // label isn't used as a name for control
   1140    testName_("checkbox", "Play the Haliluya sound when new mail arrives");
   1141    testName_(
   1142      "comboinmiddle3",
   1143      "Play the Haliluya sound when new mail arrives"
   1144    );
   1145    testName_("combo6", "Play the sound when new mail arrives");
   1146 
   1147    testName_("comboinend", "This day was sunny");
   1148    testName_("combo7", "This day was");
   1149 
   1150    testName_("textboxinend", "This day was sunny");
   1151    testName_("textbox2", "This day was");
   1152 
   1153    // placeholder
   1154    testName_("ph_password", "a placeholder");
   1155    testName_("ph_text", "a placeholder");
   1156    testName_("ph_textarea", "a placeholder");
   1157    testName_("ph_text2", "a label");
   1158    testName_("ph_textarea2", "a label");
   1159    testName_("ph_text3", "a label");
   1160 
   1161    // Test equation image
   1162    testName_("img_eq", "x^2 + y^2 + z^2");
   1163    testName_("input_img_eq", "x^2 + y^2 + z^2");
   1164    testName_("txt_eq", "x^2 + y^2 + z^2");
   1165 
   1166    // //////////////////////////////////////////////////////////////////////
   1167    // tests for duplicate announcement of content
   1168 
   1169    testName_("test_note", null);
   1170 
   1171    // //////////////////////////////////////////////////////////////////////
   1172    // Tests for name from sub tree of tr element.
   1173 
   1174    // By default, we want no name.
   1175    testName_("NoNameForTR", null);
   1176    testName_("NoNameForNonStandardTR", null);
   1177 
   1178    // But we want it if the tr has an ARIA role.
   1179    testName_("NameForTRBecauseStrongARIA", "a b");
   1180 
   1181    // But not if it is a weak (landmark) ARIA role
   1182    testName_("NoNameForTRBecauseWeakARIA", null);
   1183 
   1184    // Name from sub tree of grouping if requested by other accessible.
   1185    testName_("grouping", null);
   1186    testName_("requested_name_from_grouping", "label");
   1187    testName_("listitem_containing_block_tbody", "label");
   1188    // Groupings shouldn't be included when calculating from the subtree of
   1189    // a treeitem.
   1190    testName_("treeitem_containing_grouping", "root");
   1191 
   1192    // Name from subtree of grouping labelled by an ancestor.
   1193    testName_("grouping_labelledby_ancestor", "label");
   1194 
   1195    // Name from subtree of a container containing text nodes and inline
   1196    // elements. There should be no spaces because everything is inline.
   1197    testName_("container_text_inline", "abc");
   1198    // Name from subtree of a container containing text nodes and block
   1199    // elements. There should be a space on both sides of the block.
   1200    testName_("container_text_block", "a b c");
   1201    // Name from subtree of a container containing text nodes and empty
   1202    // block elements. There should be space on either side of the blocks, but
   1203    // not a double space.
   1204    testName_("container_text_emptyblock", "a b");
   1205 
   1206    let reordered = waitForEvent(EVENT_REORDER, "shadowHost");
   1207    await invokeContentTask(browser, [], () => {
   1208      const shadowHost = content.document.getElementById("shadowHost");
   1209      const shadowRoot = shadowHost.attachShadow({ mode: "open" });
   1210      shadowRoot.append(
   1211        content.document
   1212          .getElementById("shadowTemplate")
   1213          .content.cloneNode(true)
   1214      );
   1215    });
   1216    await reordered;
   1217 
   1218    const shadowRoot = findAccessibleChildByID(docAcc, "shadowHost");
   1219    testName(shadowRoot.firstChild, "shadowButtonVisibleText");
   1220    testName(shadowRoot.lastChild, "shadowButtonHiddenText");
   1221 
   1222    // Label from a hidden element containing script and style elements.
   1223    testName_("buttonScriptStyle", "content");
   1224 
   1225    // Name from subtree on a link containing <code>, etc.
   1226    testName_("linkWithCodeSupSubInsDel", "before code sup sub ins del after");
   1227  },
   1228  { topLevel: true, chrome: true }
   1229 );