tor-browser

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

browser_selectables.js (16830B)


      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/role.js */
      8 /* import-globals-from ../../mochitest/states.js */
      9 loadScripts(
     10  { name: "role.js", dir: MOCHITESTS_DIR },
     11  { name: "states.js", dir: MOCHITESTS_DIR }
     12 );
     13 
     14 function getSelectedIds(selectable) {
     15  return selectable
     16    .getAttributeValue("AXSelectedChildren")
     17    .map(c => c.getAttributeValue("AXDOMIdentifier"));
     18 }
     19 
     20 /**
     21 * Test aria tabs
     22 */
     23 addAccessibleTask("mac/doc_aria_tabs.html", async (browser, accDoc) => {
     24  let tablist = getNativeInterface(accDoc, "tablist");
     25  is(
     26    tablist.getAttributeValue("AXRole"),
     27    "AXTabGroup",
     28    "Correct role for tablist"
     29  );
     30 
     31  let tabMacAccs = tablist.getAttributeValue("AXTabs");
     32  is(tabMacAccs.length, 3, "3 items in AXTabs");
     33 
     34  let selectedTabs = tablist.getAttributeValue("AXSelectedChildren");
     35  is(selectedTabs.length, 1, "one selected tab");
     36 
     37  let tab = selectedTabs[0];
     38  is(tab.getAttributeValue("AXRole"), "AXRadioButton", "Correct role for tab");
     39  is(
     40    tab.getAttributeValue("AXSubrole"),
     41    "AXTabButton",
     42    "Correct subrole for tab"
     43  );
     44  is(tab.getAttributeValue("AXTitle"), "First Tab", "Correct title for tab");
     45 
     46  let tabToSelect = tabMacAccs[1];
     47  is(
     48    tabToSelect.getAttributeValue("AXTitle"),
     49    "Second Tab",
     50    "Correct title for tab"
     51  );
     52 
     53  let actions = tabToSelect.actionNames;
     54  ok(true, actions);
     55  ok(actions.includes("AXPress"), "Has switch action");
     56 
     57  let evt = waitForMacEvent("AXSelectedChildrenChanged");
     58  tabToSelect.performAction("AXPress");
     59  await evt;
     60 
     61  selectedTabs = tablist.getAttributeValue("AXSelectedChildren");
     62  is(selectedTabs.length, 1, "one selected tab");
     63  is(
     64    selectedTabs[0].getAttributeValue("AXTitle"),
     65    "Second Tab",
     66    "Correct title for tab"
     67  );
     68 });
     69 
     70 addAccessibleTask('<p id="p">hello</p>', async (browser, accDoc) => {
     71  let p = getNativeInterface(accDoc, "p");
     72  ok(
     73    p.attributeNames.includes("AXSelected"),
     74    "html element includes 'AXSelected' attribute"
     75  );
     76  is(p.getAttributeValue("AXSelected"), 0, "AX selected is 'false'");
     77 });
     78 
     79 addAccessibleTask(
     80  `<select id="select" aria-label="Choose a number" multiple>
     81    <option id="one" selected>One</option>
     82    <option id="two">Two</option>
     83    <option id="three">Three</option>
     84    <option id="four" disabled>Four</option>
     85  </select>`,
     86  async (browser, accDoc) => {
     87    let select = getNativeInterface(accDoc, "select");
     88    let one = getNativeInterface(accDoc, "one");
     89    let two = getNativeInterface(accDoc, "two");
     90    let three = getNativeInterface(accDoc, "three");
     91    let four = getNativeInterface(accDoc, "four");
     92 
     93    is(
     94      select.getAttributeValue("AXDescription"),
     95      "Choose a number",
     96      "Select titled correctly"
     97    );
     98    ok(
     99      select.attributeNames.includes("AXOrientation"),
    100      "Have orientation attribute"
    101    );
    102    ok(
    103      select.isAttributeSettable("AXSelectedChildren"),
    104      "Select can have AXSelectedChildren set"
    105    );
    106 
    107    is(one.getAttributeValue("AXTitle"), "", "Option should not have a title");
    108    is(
    109      one.getAttributeValue("AXValue"),
    110      "One",
    111      "Option should have correct value"
    112    );
    113    is(
    114      one.getAttributeValue("AXRole"),
    115      "AXStaticText",
    116      "Options should have AXStaticText role"
    117    );
    118    ok(one.isAttributeSettable("AXSelected"), "Option can have AXSelected set");
    119 
    120    is(select.getAttributeValue("AXSelectedChildren").length, 1);
    121    let evt = waitForMacEvent("AXSelectedChildrenChanged");
    122    one.setAttributeValue("AXSelected", false);
    123    await evt;
    124    is(select.getAttributeValue("AXSelectedChildren").length, 0);
    125    evt = waitForMacEvent("AXSelectedChildrenChanged");
    126    three.setAttributeValue("AXSelected", true);
    127    await evt;
    128    is(select.getAttributeValue("AXSelectedChildren").length, 1);
    129    ok(getSelectedIds(select).includes("three"), "'three' is selected");
    130    evt = waitForMacEvent("AXSelectedChildrenChanged");
    131    select.setAttributeValue("AXSelectedChildren", [one, two]);
    132    await evt;
    133    await untilCacheOk(() => {
    134      let ids = getSelectedIds(select);
    135      return ids[0] == "one" && ids[1] == "two";
    136    }, "Got correct selected children");
    137 
    138    evt = waitForMacEvent("AXSelectedChildrenChanged");
    139    select.setAttributeValue("AXSelectedChildren", [three, two, four]);
    140    await evt;
    141    await untilCacheOk(() => {
    142      let ids = getSelectedIds(select);
    143      return ids[0] == "two" && ids[1] == "three";
    144    }, "Got correct selected children");
    145 
    146    ok(!four.getAttributeValue("AXEnabled"), "Disabled option is disabled");
    147  }
    148 );
    149 
    150 addAccessibleTask(
    151  `<select id="select" aria-label="Choose a thing" multiple>
    152    <optgroup label="Fruits">
    153      <option id="banana" selected>Banana</option>
    154      <option id="apple">Apple</option>
    155      <option id="orange">Orange</option>
    156    </optgroup>
    157    <optgroup label="Vegetables">
    158      <option id="lettuce" selected>Lettuce</option>
    159      <option id="tomato">Tomato</option>
    160      <option id="onion">Onion</option>
    161    </optgroup>
    162    <optgroup label="Spices">
    163      <option id="cumin">Cumin</option>
    164      <option id="coriander">Coriander</option>
    165      <option id="allspice" selected>Allspice</option>
    166    </optgroup>
    167    <option id="everything">Everything</option>
    168  </select>`,
    169  async (browser, accDoc) => {
    170    let select = getNativeInterface(accDoc, "select");
    171 
    172    is(
    173      select.getAttributeValue("AXDescription"),
    174      "Choose a thing",
    175      "Select titled correctly"
    176    );
    177    ok(
    178      select.attributeNames.includes("AXOrientation"),
    179      "Have orientation attribute"
    180    );
    181    ok(
    182      select.isAttributeSettable("AXSelectedChildren"),
    183      "Select can have AXSelectedChildren set"
    184    );
    185    let childValueSelectablePairs = select
    186      .getAttributeValue("AXChildren")
    187      .map(c => [
    188        c.getAttributeValue("AXValue"),
    189        c.isAttributeSettable("AXSelected"),
    190        c.getAttributeValue("AXEnabled"),
    191      ]);
    192    [
    193      ["​", false, 0],
    194      ["Fruits", false, 0],
    195      ["Banana", true, 1],
    196      ["Apple", true, 1],
    197      ["Orange", true, 1],
    198      ["​", false, 0],
    199      ["Vegetables", false, 0],
    200      ["Lettuce", true, 1],
    201      ["Tomato", true, 1],
    202      ["Onion", true, 1],
    203      ["​", false, 0],
    204      ["Spices", false, 0],
    205      ["Cumin", true, 1],
    206      ["Coriander", true, 1],
    207      ["Allspice", true, 1],
    208      ["Everything", true, 1],
    209    ];
    210    Assert.deepEqual(
    211      childValueSelectablePairs,
    212      [
    213        ["​", false, false],
    214        ["Fruits", false, false],
    215        ["Banana", true, true],
    216        ["Apple", true, true],
    217        ["Orange", true, true],
    218        ["​", false, false],
    219        ["Vegetables", false, false],
    220        ["Lettuce", true, true],
    221        ["Tomato", true, true],
    222        ["Onion", true, true],
    223        ["​", false, false],
    224        ["Spices", false, false],
    225        ["Cumin", true, true],
    226        ["Coriander", true, true],
    227        ["Allspice", true, true],
    228        ["Everything", true, true],
    229      ],
    230      "Options are selectable, group labels are not"
    231    );
    232 
    233    let allspice = getNativeInterface(accDoc, "allspice");
    234    is(
    235      allspice.getAttributeValue("AXTitle"),
    236      "",
    237      "Option should not have a title"
    238    );
    239    is(
    240      allspice.getAttributeValue("AXValue"),
    241      "Allspice",
    242      "Option should have a value"
    243    );
    244    is(
    245      allspice.getAttributeValue("AXRole"),
    246      "AXStaticText",
    247      "Options should have AXStaticText role"
    248    );
    249    ok(
    250      allspice.isAttributeSettable("AXSelected"),
    251      "Option can have AXSelected set"
    252    );
    253    is(
    254      allspice
    255        .getAttributeValue("AXParent")
    256        .getAttributeValue("AXDOMIdentifier"),
    257      "select",
    258      "Select is direct parent of nested option"
    259    );
    260 
    261    let groupLabel = select.getAttributeValue("AXChildren")[1];
    262    ok(
    263      !groupLabel.isAttributeSettable("AXSelected"),
    264      "Group label should not be selectable"
    265    );
    266    is(
    267      groupLabel.getAttributeValue("AXValue"),
    268      "Fruits",
    269      "Group label should have a value"
    270    );
    271    is(
    272      groupLabel.getAttributeValue("AXTitle"),
    273      null,
    274      "Group label should not have a title"
    275    );
    276    is(
    277      groupLabel.getAttributeValue("AXRole"),
    278      "AXStaticText",
    279      "Group label should have AXStaticText role"
    280    );
    281    is(
    282      groupLabel
    283        .getAttributeValue("AXParent")
    284        .getAttributeValue("AXDOMIdentifier"),
    285      "select",
    286      "Select is direct parent of group label"
    287    );
    288 
    289    Assert.deepEqual(getSelectedIds(select), ["banana", "lettuce", "allspice"]);
    290  }
    291 );
    292 
    293 addAccessibleTask(
    294  `<div role="listbox" id="select" aria-label="Choose a number" aria-multiselectable="true">
    295    <div role="option" id="one" aria-selected="true">One</div>
    296    <div role="option" id="two">Two</div>
    297    <div role="option" id="three">Three</div>
    298    <div role="option" id="four" aria-disabled="true">Four</div>
    299 </div>`,
    300  async (browser, accDoc) => {
    301    let select = getNativeInterface(accDoc, "select");
    302    let one = getNativeInterface(accDoc, "one");
    303 
    304    is(
    305      select.getAttributeValue("AXDescription"),
    306      "Choose a number",
    307      "Select titled correctly"
    308    );
    309    ok(
    310      select.attributeNames.includes("AXOrientation"),
    311      "Have orientation attribute"
    312    );
    313    ok(
    314      select.isAttributeSettable("AXSelectedChildren"),
    315      "Select can have AXSelectedChildren set"
    316    );
    317 
    318    is(one.getAttributeValue("AXTitle"), "", "Option should not have a title");
    319    is(
    320      one.getAttributeValue("AXValue"),
    321      "One",
    322      "Option should have correct value"
    323    );
    324    is(
    325      one.getAttributeValue("AXRole"),
    326      "AXStaticText",
    327      "Options should have AXStaticText role"
    328    );
    329    ok(one.isAttributeSettable("AXSelected"), "Option can have AXSelected set");
    330 
    331    is(select.getAttributeValue("AXSelectedChildren").length, 1);
    332    let evt = waitForMacEvent("AXSelectedChildrenChanged");
    333    // Change selection from content.
    334    await SpecialPowers.spawn(browser, [], () => {
    335      content.document.getElementById("one").removeAttribute("aria-selected");
    336    });
    337    await evt;
    338    is(select.getAttributeValue("AXSelectedChildren").length, 0);
    339  }
    340 );
    341 
    342 addAccessibleTask(
    343  `<div role="listbox" id="select" aria-label="Choose a number">
    344    <div id="groupOne" role="group">
    345      <div role="option" id="one" aria-selected="true">One</div>
    346    </div>
    347    <div id="groupTwo" role="group">
    348      <div role="option" id="two" aria-selected="false">Two</div>
    349    </div>
    350    <div id="groupThree" role="group">
    351      <div role="option" id="three" aria-selected="false">Three</div>
    352    </div>
    353  </div>`,
    354  async function testGroupedListbox(browser, accDoc) {
    355    let select = getNativeInterface(accDoc, "select");
    356    let one = getNativeInterface(accDoc, "one");
    357    let two = getNativeInterface(accDoc, "two");
    358 
    359    // Check the listbox
    360    is(
    361      select.getAttributeValue("AXDescription"),
    362      "Choose a number",
    363      "Select titled correctly"
    364    );
    365    ok(
    366      select.isAttributeSettable("AXSelectedChildren"),
    367      "Select can have AXSelectedChildren set"
    368    );
    369    // Check the first option
    370    is(
    371      one.getAttributeValue("AXValue"),
    372      "One",
    373      "First option has correct value"
    374    );
    375    is(
    376      one.getAttributeValue("AXSelected"),
    377      1,
    378      "The first option has selected state"
    379    );
    380    // Check the second option
    381    is(
    382      two.getAttributeValue("AXValue"),
    383      "Two",
    384      "Second option has correct value"
    385    );
    386    is(
    387      two.getAttributeValue("AXSelected"),
    388      0,
    389      "The second option has no selected state"
    390    );
    391    // Check the relationship between the listbox and its selected children
    392    is(
    393      select.getAttributeValue("AXSelectedChildren").length,
    394      1,
    395      "Listbox has one selected child"
    396    );
    397    let selectedChild = select.getAttributeValue("AXSelectedChildren")[0];
    398    is(
    399      selectedChild.getAttributeValue("AXValue"),
    400      "One",
    401      "The first option is the selected child"
    402    );
    403 
    404    let evt = waitForMacEvent("AXSelectedChildrenChanged");
    405    // Remove all selection.
    406    await SpecialPowers.spawn(browser, [], () => {
    407      content.document
    408        .getElementById("one")
    409        .setAttribute("aria-selected", "false");
    410    });
    411    await evt;
    412    // Check the relationship between the listbox and its selected children
    413    // after removing all selection.
    414    is(
    415      select.getAttributeValue("AXSelectedChildren").length,
    416      0,
    417      "Listbox has no selected child"
    418    );
    419    is(
    420      one.getAttributeValue("AXSelected"),
    421      0,
    422      "The first option has no selected state"
    423    );
    424 
    425    evt = waitForMacEvent("AXSelectedChildrenChanged");
    426    // Modify listbox so the second item is selected.
    427    await SpecialPowers.spawn(browser, [], () => {
    428      content.document
    429        .getElementById("two")
    430        .setAttribute("aria-selected", "true");
    431    });
    432    await evt;
    433    // Check the relationship between the listbox and its selected children
    434    // after selecting the second option.
    435    is(
    436      select.getAttributeValue("AXSelectedChildren").length,
    437      1,
    438      "Listbox has one selected child"
    439    );
    440    selectedChild = select.getAttributeValue("AXSelectedChildren")[0];
    441    is(
    442      selectedChild.getAttributeValue("AXValue"),
    443      "Two",
    444      "The second option is the selected child"
    445    );
    446    is(
    447      two.getAttributeValue("AXSelected"),
    448      1,
    449      "The second option has selected state"
    450    );
    451  }
    452 );
    453 
    454 addAccessibleTask(
    455  `
    456  <div role="listbox" id="listbox">
    457    <div role="group">
    458      <div role="group">
    459        <div role="option" id="optionA" aria-selected="true">
    460          <div role="group">
    461            <button id="one">hi</button>
    462          </div>
    463        </div>
    464        <div role="option" id="optionB" aria-selected="false">
    465          <div role="group">
    466            <button id="two">hello</button>
    467          </div>
    468        </div>
    469      </div>
    470    </div>
    471    `,
    472  async function testMultiGroupedListbox(browser, accDoc) {
    473    let listbox = getNativeInterface(accDoc, "listbox");
    474    let optionA = getNativeInterface(accDoc, "optionA");
    475    let optionB = getNativeInterface(accDoc, "optionB");
    476 
    477    ok(
    478      listbox.isAttributeSettable("AXSelectedChildren"),
    479      "Select can have AXSelectedChildren set"
    480    );
    481    // Check the first option
    482    is(
    483      optionA.getAttributeValue("AXValue"),
    484      "hi",
    485      "First option has correct value"
    486    );
    487    is(
    488      optionA.getAttributeValue("AXSelected"),
    489      1,
    490      "The first option has selected state"
    491    );
    492    // Check the second option
    493    is(
    494      optionB.getAttributeValue("AXValue"),
    495      "hello",
    496      "Second option has correct value"
    497    );
    498    is(
    499      optionB.getAttributeValue("AXSelected"),
    500      0,
    501      "The second option has no selected state"
    502    );
    503    // Check the relationship between the listbox and its selected children
    504    is(
    505      listbox.getAttributeValue("AXSelectedChildren").length,
    506      1,
    507      "Listbox has one selected child"
    508    );
    509    let selectedChild = listbox.getAttributeValue("AXSelectedChildren")[0];
    510    is(
    511      selectedChild.getAttributeValue("AXValue"),
    512      "hi",
    513      "The first option is the selected child"
    514    );
    515 
    516    let evt = waitForMacEvent("AXSelectedChildrenChanged");
    517    // Remove all selection.
    518    await SpecialPowers.spawn(browser, [], () => {
    519      content.document
    520        .getElementById("optionA")
    521        .setAttribute("aria-selected", "false");
    522    });
    523    await evt;
    524    // Check the relationship between the listbox and its selected children
    525    // after removing all selection.
    526    is(
    527      listbox.getAttributeValue("AXSelectedChildren").length,
    528      0,
    529      "Listbox has no selected child"
    530    );
    531    is(
    532      optionA.getAttributeValue("AXSelected"),
    533      0,
    534      "The first option has no selected state"
    535    );
    536 
    537    evt = waitForMacEvent("AXSelectedChildrenChanged");
    538    // Modify listbox so the second item is selected.
    539    await SpecialPowers.spawn(browser, [], () => {
    540      content.document
    541        .getElementById("optionB")
    542        .setAttribute("aria-selected", "true");
    543    });
    544    await evt;
    545    // Check the relationship between the listbox and its selected children
    546    // after selecting the second option.
    547    is(
    548      listbox.getAttributeValue("AXSelectedChildren").length,
    549      1,
    550      "Listbox has one selected child"
    551    );
    552    selectedChild = listbox.getAttributeValue("AXSelectedChildren")[0];
    553    is(
    554      selectedChild.getAttributeValue("AXValue"),
    555      "hello",
    556      "The second option is the selected child"
    557    );
    558    is(
    559      optionB.getAttributeValue("AXSelected"),
    560      1,
    561      "The second option has selected state"
    562    );
    563  }
    564 );