tor-browser

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

browser_outline.js (15904B)


      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 
      7 /* import-globals-from ../../mochitest/states.js */
      8 loadScripts({ name: "states.js", dir: MOCHITESTS_DIR });
      9 
     10 /**
     11 * Test outline, outline rows with computed properties
     12 */
     13 addAccessibleTask(
     14  `
     15  <h3 id="tree1">
     16    Foods
     17  </h3>
     18  <ul role="tree" aria-labelledby="tree1" id="outline">
     19    <li role="treeitem" aria-expanded="false">
     20      <span>
     21        Fruits
     22      </span>
     23      <ul>
     24        <li role="none">Oranges</li>
     25        <li role="treeitem" aria-expanded="true">
     26          <span>
     27            Apples
     28          </span>
     29          <ul role="group">
     30            <li role="none">Honeycrisp</li>
     31            <li role="none">Granny Smith</li>
     32          </ul>
     33        </li>
     34      </ul>
     35    </li>
     36    <li id="vegetables" role="treeitem" aria-expanded="false">
     37      <span>
     38        Vegetables
     39      </span>
     40      <ul role="group">
     41        <li role="treeitem" aria-expanded="true">
     42          <span>
     43            Podded Vegetables
     44          </span>
     45          <ul role="group">
     46            <li role="none">Lentil</li>
     47            <li role="none">Pea</li>
     48          </ul>
     49        </li>
     50      </ul>
     51    </li>
     52  </ul>
     53  `,
     54  async (browser, accDoc) => {
     55    const outline = getNativeInterface(accDoc, "outline");
     56    is(
     57      outline.getAttributeValue("AXRole"),
     58      "AXOutline",
     59      "Correct role for outline"
     60    );
     61 
     62    const outChildren = outline.getAttributeValue("AXChildren");
     63    is(outChildren.length, 2, "Outline has two direct children");
     64    is(outChildren[0].getAttributeValue("AXSubrole"), "AXOutlineRow");
     65    is(outChildren[1].getAttributeValue("AXSubrole"), "AXOutlineRow");
     66 
     67    const outRows = outline.getAttributeValue("AXRows");
     68    is(outRows.length, 4, "Outline has four rows");
     69    is(
     70      outRows[0].getAttributeValue("AXDisclosing"),
     71      0,
     72      "Row is not disclosing"
     73    );
     74    is(
     75      outRows[0].getAttributeValue("AXDisclosedByRow"),
     76      null,
     77      "Row is direct child of outline"
     78    );
     79    is(
     80      outRows[0].getAttributeValue("AXDisclosedRows").length,
     81      0,
     82      "Row has no row children, only group"
     83    );
     84    is(
     85      outRows[0].getAttributeValue("AXDisclosureLevel"),
     86      0,
     87      "Row is level zero"
     88    );
     89 
     90    is(outRows[1].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
     91    is(
     92      outRows[1].getAttributeValue("AXDisclosedByRow"),
     93      null,
     94      "Row is direct child of group"
     95    );
     96    is(
     97      outRows[1].getAttributeValue("AXDisclosedRows").length,
     98      0,
     99      "Row has no row children"
    100    );
    101    is(
    102      outRows[1].getAttributeValue("AXDisclosureLevel"),
    103      0,
    104      "Row is level zero"
    105    );
    106 
    107    is(
    108      outRows[2].getAttributeValue("AXDisclosing"),
    109      0,
    110      "Row is not disclosing"
    111    );
    112    is(
    113      outRows[2].getAttributeValue("AXDisclosedByRow"),
    114      null,
    115      "Row is direct child of outline"
    116    );
    117    is(
    118      outRows[2].getAttributeValue("AXDisclosedRows").length,
    119      1,
    120      "Row has one row child"
    121    );
    122    is(
    123      outRows[2].getAttributeValue("AXDisclosureLevel"),
    124      0,
    125      "Row is level zero"
    126    );
    127 
    128    is(outRows[3].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
    129    is(
    130      outRows[3]
    131        .getAttributeValue("AXDisclosedByRow")
    132        .getAttributeValue("AXDescription"),
    133      outRows[2].getAttributeValue("AXDescription"),
    134      "Row is direct child of row[2]"
    135    );
    136    is(
    137      outRows[3].getAttributeValue("AXDisclosedRows").length,
    138      0,
    139      "Row has no row children"
    140    );
    141    is(
    142      outRows[3].getAttributeValue("AXDisclosureLevel"),
    143      1,
    144      "Row is level one"
    145    );
    146 
    147    let evt = waitForMacEvent("AXRowExpanded", "vegetables");
    148    await SpecialPowers.spawn(browser, [], () => {
    149      content.document
    150        .getElementById("vegetables")
    151        .setAttribute("aria-expanded", "true");
    152    });
    153    await evt;
    154    is(
    155      outRows[2].getAttributeValue("AXDisclosing"),
    156      1,
    157      "Row is disclosing after being expanded"
    158    );
    159 
    160    evt = waitForMacEvent("AXRowCollapsed", "vegetables");
    161    await SpecialPowers.spawn(browser, [], () => {
    162      content.document
    163        .getElementById("vegetables")
    164        .setAttribute("aria-expanded", "false");
    165    });
    166    await evt;
    167    is(
    168      outRows[2].getAttributeValue("AXDisclosing"),
    169      0,
    170      "Row is not disclosing after being collapsed again"
    171    );
    172  }
    173 );
    174 
    175 /**
    176 * Test outline, outline rows with declared properties
    177 */
    178 addAccessibleTask(
    179  `
    180  <h3 id="tree1">
    181  Foods
    182  </h3>
    183  <ul role="tree" aria-labelledby="tree1" id="outline">
    184    <li role="treeitem"
    185        aria-level="1"
    186        aria-setsize="2"
    187        aria-posinset="1"
    188        aria-expanded="false">
    189      <span>
    190        Fruits
    191      </span>
    192      <ul>
    193        <li role="treeitem"
    194             aria-level="3"
    195             aria-setsize="2"
    196             aria-posinset="1">
    197            Oranges
    198        </li>
    199        <li role="treeitem"
    200            aria-level="2"
    201            aria-setsize="2"
    202            aria-posinset="2"
    203            aria-expanded="true">
    204          <span>
    205            Apples
    206          </span>
    207          <ul role="group">
    208            <li role="treeitem"
    209                 aria-level="3"
    210                 aria-setsize="2"
    211                 aria-posinset="1">
    212                Honeycrisp
    213            </li>
    214            <li role="treeitem"
    215                 aria-level="3"
    216                 aria-setsize="2"
    217                 aria-posinset="2">
    218               Granny Smith
    219            </li>
    220          </ul>
    221        </li>
    222      </ul>
    223    </li>
    224    <li role="treeitem"
    225        aria-level="1"
    226        aria-setsize="2"
    227        aria-posinset="2"
    228        aria-expanded="false">
    229      <span>
    230        Vegetables
    231      </span>
    232      <ul role="group">
    233        <li role="treeitem"
    234            aria-level="2"
    235            aria-setsize="1"
    236            aria-posinset="1"
    237            aria-expanded="true">
    238          <span>
    239            Podded Vegetables
    240          </span>
    241          <ul role="group">
    242            <li role="treeitem"
    243                 aria-level="3"
    244                 aria-setsize="2"
    245                 aria-posinset="1">
    246               Lentil
    247            </li>
    248            <li role="treeitem"
    249                 aria-level="3"
    250                 aria-setsize="2"
    251                 aria-posinset="2">
    252                 Pea
    253            </li>
    254          </ul>
    255        </li>
    256      </ul>
    257    </li>
    258  </ul>
    259  `,
    260  async (browser, accDoc) => {
    261    const outline = getNativeInterface(accDoc, "outline");
    262    is(
    263      outline.getAttributeValue("AXRole"),
    264      "AXOutline",
    265      "Correct role for outline"
    266    );
    267 
    268    const outChildren = outline.getAttributeValue("AXChildren");
    269    is(outChildren.length, 2, "Outline has two direct children");
    270    is(outChildren[0].getAttributeValue("AXSubrole"), "AXOutlineRow");
    271    is(outChildren[1].getAttributeValue("AXSubrole"), "AXOutlineRow");
    272 
    273    const outRows = outline.getAttributeValue("AXRows");
    274    is(outRows.length, 9, "Outline has nine rows");
    275    is(
    276      outRows[0].getAttributeValue("AXDisclosing"),
    277      0,
    278      "Row is not disclosing"
    279    );
    280    is(
    281      outRows[0].getAttributeValue("AXDisclosedByRow"),
    282      null,
    283      "Row is direct child of outline"
    284    );
    285    is(
    286      outRows[0].getAttributeValue("AXDisclosedRows").length,
    287      0,
    288      "Row has no direct row children, has list"
    289    );
    290    is(
    291      outRows[0].getAttributeValue("AXDisclosureLevel"),
    292      0,
    293      "Row is level zero"
    294    );
    295 
    296    is(outRows[2].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
    297    is(
    298      outRows[2].getAttributeValue("AXDisclosedByRow"),
    299      null,
    300      "Row is direct child of group"
    301    );
    302    is(
    303      outRows[2].getAttributeValue("AXDisclosedRows").length,
    304      2,
    305      "Row has two row children"
    306    );
    307    is(
    308      outRows[2].getAttributeValue("AXDisclosureLevel"),
    309      1,
    310      "Row is level one"
    311    );
    312 
    313    is(
    314      outRows[3].getAttributeValue("AXDisclosing"),
    315      0,
    316      "Row is not disclosing"
    317    );
    318    is(
    319      outRows[3]
    320        .getAttributeValue("AXDisclosedByRow")
    321        .getAttributeValue("AXDescription"),
    322      outRows[2].getAttributeValue("AXDescription"),
    323      "Row is direct child of row 2"
    324    );
    325 
    326    is(
    327      outRows[3].getAttributeValue("AXDisclosedRows").length,
    328      0,
    329      "Row has no row children"
    330    );
    331    is(
    332      outRows[3].getAttributeValue("AXDisclosureLevel"),
    333      2,
    334      "Row is level two"
    335    );
    336 
    337    is(
    338      outRows[5].getAttributeValue("AXDisclosing"),
    339      0,
    340      "Row is not disclosing"
    341    );
    342    is(
    343      outRows[5].getAttributeValue("AXDisclosedByRow"),
    344      null,
    345      "Row is direct child of outline"
    346    );
    347    is(
    348      outRows[5].getAttributeValue("AXDisclosedRows").length,
    349      1,
    350      "Row has no one row child"
    351    );
    352    is(
    353      outRows[5].getAttributeValue("AXDisclosureLevel"),
    354      0,
    355      "Row is level zero"
    356    );
    357 
    358    is(outRows[6].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
    359    is(
    360      outRows[6]
    361        .getAttributeValue("AXDisclosedByRow")
    362        .getAttributeValue("AXDescription"),
    363      outRows[5].getAttributeValue("AXDescription"),
    364      "Row is direct child of row 5"
    365    );
    366    is(
    367      outRows[6].getAttributeValue("AXDisclosedRows").length,
    368      2,
    369      "Row has two row children"
    370    );
    371    is(
    372      outRows[6].getAttributeValue("AXDisclosureLevel"),
    373      1,
    374      "Row is level one"
    375    );
    376 
    377    is(
    378      outRows[7].getAttributeValue("AXDisclosing"),
    379      0,
    380      "Row is not disclosing"
    381    );
    382    is(
    383      outRows[7]
    384        .getAttributeValue("AXDisclosedByRow")
    385        .getAttributeValue("AXDescription"),
    386      outRows[6].getAttributeValue("AXDescription"),
    387      "Row is direct child of row 6"
    388    );
    389    is(
    390      outRows[7].getAttributeValue("AXDisclosedRows").length,
    391      0,
    392      "Row has no row children"
    393    );
    394    is(
    395      outRows[7].getAttributeValue("AXDisclosureLevel"),
    396      2,
    397      "Row is level two"
    398    );
    399  }
    400 );
    401 
    402 // Test outline that isn't built with li/uls gets correct desc
    403 addAccessibleTask(
    404  `
    405  <div role="tree" id="tree" tabindex="0" aria-label="My drive" aria-activedescendant="myfiles">
    406    <div id="myfiles" role="treeitem" aria-label="My files" aria-selected="true" aria-expanded="false">My files</div>
    407    <div role="treeitem" aria-label="Shared items" aria-selected="false" aria-expanded="false">Shared items</div>
    408  </div>
    409  `,
    410  async (browser, accDoc) => {
    411    const tree = getNativeInterface(accDoc, "tree");
    412    is(tree.getAttributeValue("AXRole"), "AXOutline", "Correct role for tree");
    413 
    414    const treeItems = tree.getAttributeValue("AXChildren");
    415    is(treeItems.length, 2, "Outline has two direct children");
    416    is(treeItems[0].getAttributeValue("AXSubrole"), "AXOutlineRow");
    417    is(treeItems[1].getAttributeValue("AXSubrole"), "AXOutlineRow");
    418 
    419    const outRows = tree.getAttributeValue("AXRows");
    420    is(outRows.length, 2, "Outline has two rows");
    421 
    422    is(
    423      outRows[0].getAttributeValue("AXDescription"),
    424      "My files",
    425      "files labelled correctly"
    426    );
    427    is(
    428      outRows[1].getAttributeValue("AXDescription"),
    429      "Shared items",
    430      "shared items labelled correctly"
    431    );
    432  }
    433 );
    434 
    435 // Test outline registers AXDisclosed attr as settable
    436 addAccessibleTask(
    437  `
    438  <div role="tree" id="tree" tabindex="0" aria-label="My drive" aria-activedescendant="myfiles">
    439    <div id="myfiles" role="treeitem" aria-label="My files" aria-selected="true" aria-expanded="false">My files</div>
    440    <div role="treeitem" aria-label="Shared items" aria-selected="false" aria-expanded="true">Shared items</div>
    441  </div>
    442  `,
    443  async (browser, accDoc) => {
    444    const tree = getNativeInterface(accDoc, "tree");
    445    const treeItems = tree.getAttributeValue("AXChildren");
    446 
    447    is(treeItems.length, 2, "Outline has two direct children");
    448    is(treeItems[0].getAttributeValue("AXDisclosing"), 0);
    449    is(treeItems[1].getAttributeValue("AXDisclosing"), 1);
    450 
    451    is(treeItems[0].isAttributeSettable("AXDisclosing"), true);
    452    is(treeItems[1].isAttributeSettable("AXDisclosing"), true);
    453 
    454    // attempt to change attribute values
    455    treeItems[0].setAttributeValue("AXDisclosing", 1);
    456    treeItems[0].setAttributeValue("AXDisclosing", 0);
    457 
    458    // verify they're unchanged
    459    is(treeItems[0].getAttributeValue("AXDisclosing"), 0);
    460    is(treeItems[1].getAttributeValue("AXDisclosing"), 1);
    461  }
    462 );
    463 
    464 // Test outline rows correctly expose checkable, checked/unchecked/mixed status
    465 addAccessibleTask(
    466  `
    467  <div role="tree" id="tree">
    468    <div role="treeitem" aria-checked="false" id="l1">
    469      Leaf 1
    470    </div>
    471    <div role="treeitem" aria-checked="true" id="l2">
    472      Leaf 2
    473    </div>
    474    <div role="treeitem" id="l3">
    475      Leaf 3
    476    </div>
    477    <div role="treeitem" aria-checked="mixed" id="l4">
    478      Leaf 4
    479    </div>
    480  </div>
    481 
    482  `,
    483  async (browser, accDoc) => {
    484    const tree = getNativeInterface(accDoc, "tree");
    485    const treeItems = tree.getAttributeValue("AXChildren");
    486 
    487    is(treeItems.length, 4, "Outline has four direct children");
    488    is(
    489      treeItems[0].getAttributeValue("AXValue"),
    490      0,
    491      "Child one is not checked"
    492    );
    493    is(treeItems[1].getAttributeValue("AXValue"), 1, "Child two is checked");
    494    is(
    495      treeItems[2].getAttributeValue("AXValue"),
    496      null,
    497      "Child three is not checkable and has no val"
    498    );
    499    is(treeItems[3].getAttributeValue("AXValue"), 2, "Child four is mixed");
    500 
    501    let stateChanged = Promise.all([
    502      waitForMacEvent("AXValueChanged", "l1"),
    503      waitForStateChange("l1", STATE_CHECKED, true),
    504    ]);
    505    // We should get a state change event for checked.
    506    await SpecialPowers.spawn(browser, [], () => {
    507      content.document
    508        .getElementById("l1")
    509        .setAttribute("aria-checked", "true");
    510    });
    511    await stateChanged;
    512    is(treeItems[0].getAttributeValue("AXValue"), 1, "Child one is checked");
    513 
    514    stateChanged = Promise.all([
    515      waitForMacEvent("AXValueChanged", "l2"),
    516      waitForMacEvent("AXValueChanged", "l2"),
    517      waitForStateChange("l2", STATE_CHECKED, false),
    518      waitForStateChange("l2", STATE_CHECKABLE, false),
    519    ]);
    520    // We should get a state change event for both checked and checkable,
    521    // and value changes for both.
    522    await SpecialPowers.spawn(browser, [], () => {
    523      content.document.getElementById("l2").removeAttribute("aria-checked");
    524    });
    525    await stateChanged;
    526    is(
    527      treeItems[1].getAttributeValue("AXValue"),
    528      null,
    529      "Child two is not checkable and has no val"
    530    );
    531 
    532    stateChanged = Promise.all([
    533      waitForMacEvent("AXValueChanged", "l3"),
    534      waitForMacEvent("AXValueChanged", "l3"),
    535      waitForStateChange("l3", STATE_CHECKED, true),
    536      waitForStateChange("l3", STATE_CHECKABLE, true),
    537    ]);
    538    // We should get a state change event for both checked and checkable,
    539    // and value changes for each.
    540    await SpecialPowers.spawn(browser, [], () => {
    541      content.document
    542        .getElementById("l3")
    543        .setAttribute("aria-checked", "true");
    544    });
    545    await stateChanged;
    546    is(treeItems[2].getAttributeValue("AXValue"), 1, "Child three is checked");
    547 
    548    stateChanged = Promise.all([
    549      waitForMacEvent("AXValueChanged", "l4"),
    550      waitForMacEvent("AXValueChanged", "l4"),
    551      waitForStateChange("l4", STATE_MIXED, false),
    552      waitForStateChange("l4", STATE_CHECKABLE, false),
    553    ]);
    554    // We should get a state change event for both mixed and checkable,
    555    // and value changes for each.
    556    await SpecialPowers.spawn(browser, [], () => {
    557      content.document.getElementById("l4").removeAttribute("aria-checked");
    558    });
    559    await stateChanged;
    560    is(
    561      treeItems[3].getAttributeValue("AXValue"),
    562      null,
    563      "Child four is not checkable and has no value"
    564    );
    565  }
    566 );