tor-browser

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

browser_accessibility_keyboard_audit.js (11326B)


      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 /**
      8 * Checks functionality around keyboard audit for the AccessibleActor.
      9 */
     10 
     11 const {
     12  accessibility: {
     13    AUDIT_TYPE: { KEYBOARD },
     14    SCORES: { FAIL, WARNING },
     15    ISSUE_TYPE: {
     16      [KEYBOARD]: {
     17        FOCUSABLE_NO_SEMANTICS,
     18        FOCUSABLE_POSITIVE_TABINDEX,
     19        INTERACTIVE_NOT_FOCUSABLE,
     20        MOUSE_INTERACTIVE_ONLY,
     21        NO_FOCUS_VISIBLE,
     22      },
     23    },
     24  },
     25 } = require("resource://devtools/shared/constants.js");
     26 
     27 add_task(async function () {
     28  const { target, walker, parentAccessibility, a11yWalker } =
     29    await initAccessibilityFrontsForUrl(
     30      `${MAIN_DOMAIN}doc_accessibility_keyboard_audit.html`
     31    );
     32 
     33  const tests = [
     34    [
     35      "Focusable element (styled button) with no semantics.",
     36      "#button-1",
     37      { score: WARNING, issue: FOCUSABLE_NO_SEMANTICS },
     38    ],
     39    ["Element (styled button) with no semantics.", "#button-2", null],
     40    [
     41      "Container element for out of order focusable element.",
     42      "#input-container",
     43      null,
     44    ],
     45    [
     46      "Interactive element with focus out of order (-1).",
     47      "#input-1",
     48      {
     49        score: FAIL,
     50        issue: INTERACTIVE_NOT_FOCUSABLE,
     51      },
     52    ],
     53    [
     54      "Interactive element with focus out of order (-1) when disabled.",
     55      "#input-2",
     56      null,
     57    ],
     58    ["Interactive element when disabled.", "#input-3", null],
     59    ["Focusable interactive element.", "#input-4", null],
     60    [
     61      "Interactive accessible (link with no attributes) with no accessible actions.",
     62      "#link-1",
     63      null,
     64    ],
     65    ["Interactive accessible (link with valid href).", "#link-2", null],
     66    ["Interactive accessible (link with # as href).", "#link-3", null],
     67    [
     68      "Interactive accessible (link with empty string as href).",
     69      "#link-4",
     70      null,
     71    ],
     72    ["Interactive accessible with no tabindex.", "#button-3", null],
     73    [
     74      "Interactive accessible with -1 tabindex.",
     75      "#button-4",
     76      {
     77        score: FAIL,
     78        issue: INTERACTIVE_NOT_FOCUSABLE,
     79      },
     80    ],
     81    ["Interactive accessible with 0 tabindex.", "#button-5", null],
     82    [
     83      "Interactive accessible with 1 tabindex.",
     84      "#button-6",
     85      { score: WARNING, issue: FOCUSABLE_POSITIVE_TABINDEX },
     86    ],
     87    [
     88      "Focusable ARIA button with no focus styling.",
     89      "#focusable-1",
     90      { score: WARNING, issue: NO_FOCUS_VISIBLE },
     91    ],
     92    ["Focusable ARIA button with focus styling.", "#focusable-2", null],
     93    ["Focusable ARIA button with browser styling.", "#focusable-3", null],
     94    [
     95      "Not focusable, non-semantic element that has a click handler.",
     96      "#mouse-only-1",
     97      { score: FAIL, issue: MOUSE_INTERACTIVE_ONLY },
     98    ],
     99    [
    100      "Focusable, non-semantic element that has a click handler.",
    101      "#focusable-4",
    102      { score: WARNING, issue: FOCUSABLE_NO_SEMANTICS },
    103    ],
    104    [
    105      "Not focusable, ARIA button that has a click handler.",
    106      "#button-7",
    107      { score: FAIL, issue: INTERACTIVE_NOT_FOCUSABLE },
    108    ],
    109    ["Focusable, ARIA button with a click handler.", "#button-8", null],
    110    ["Regular image, no keyboard checks should flag an issue.", "#img-1", null],
    111    [
    112      "Image with a longdesc (accessible will have showlongdesc action).",
    113      "#img-2",
    114      null,
    115    ],
    116    [
    117      "Clickable image with a longdesc (accessible will have click and showlongdesc actions).",
    118      "#img-3",
    119      { score: FAIL, issue: MOUSE_INTERACTIVE_ONLY },
    120    ],
    121    [
    122      "Clickable image (accessible will have click action).",
    123      "#img-4",
    124      { score: FAIL, issue: MOUSE_INTERACTIVE_ONLY },
    125    ],
    126    ["Focusable button with aria-haspopup.", "#buttonmenu-1", null],
    127    [
    128      "Not focusable aria button with aria-haspopup.",
    129      "#buttonmenu-2",
    130      {
    131        score: FAIL,
    132        issue: INTERACTIVE_NOT_FOCUSABLE,
    133      },
    134    ],
    135    ["Focusable checkbox.", "#checkbox-1", null],
    136    ["Focusable select element size > 1", "#listbox-1", null],
    137    ["Focusable select element with one option", "#combobox-1", null],
    138    ["Focusable select element with no options", "#combobox-2", null],
    139    ["Focusable select element with two options", "#combobox-3", null],
    140    [
    141      "Non-focusable aria combobox with one aria option.",
    142      "#editcombobox-1",
    143      null,
    144    ],
    145    ["Non-focusable aria combobox with no options.", "#editcombobox-2", null],
    146    ["Focusable aria combobox with no options.", "#editcombobox-3", null],
    147    [
    148      "Non-focusable aria switch",
    149      "#switch-1",
    150      {
    151        score: FAIL,
    152        issue: INTERACTIVE_NOT_FOCUSABLE,
    153      },
    154    ],
    155    ["Focusable aria switch", "#switch-2", null],
    156    [
    157      "Combobox list that is visible (has focusable state)",
    158      "#owned_listbox",
    159      null,
    160    ],
    161    [
    162      "Mouse interactive, label that contains form element (linked)",
    163      "#label-1",
    164      null,
    165    ],
    166    ["Mouse interactive label for external element (linked)", "#label-2", null],
    167    ["Not interactive unlinked label", "#label-3", null],
    168    [
    169      "Not interactive unlinked label with folloing form element",
    170      "#label-4",
    171      null,
    172    ],
    173    ["Image inside an anchor (href)", "#img-5", null],
    174    ["Image inside an anchor (onmousedown)", "#img-6", null],
    175    ["Image inside an anchor (onclick)", "#img-7", null],
    176    ["Image inside an anchor (onmouseup)", "#img-8", null],
    177    [
    178      "Section with a collapse action from aria-expanded attribute",
    179      "#section-1",
    180      null,
    181    ],
    182    ["Tabindex -1 should not report an element as focusable", "#main", null],
    183    [
    184      "Not keyboard focusable element with no focus styling.",
    185      "#not-keyboard-focusable-1",
    186      null,
    187    ],
    188    ["Interactive grid that is not focusable.", "#grid-1", null],
    189    [
    190      "Focusable interactive grid.",
    191      "#grid-2",
    192      { score: "WARNING", issue: "FOCUSABLE_NO_SEMANTICS" },
    193    ],
    194    [
    195      "Non interactive ARIA table does not need to be focusable.",
    196      "#table-1",
    197      null,
    198    ],
    199    [
    200      "Focusable ARIA table does not have interactive semantics",
    201      "#table-2",
    202      { score: "WARNING", issue: "FOCUSABLE_NO_SEMANTICS" },
    203    ],
    204    ["Non interactive table does not need to be focusable.", "#table-3", null],
    205    [
    206      "Focusable table does not have interactive semantics",
    207      "#table-4",
    208      { score: "WARNING", issue: "FOCUSABLE_NO_SEMANTICS" },
    209    ],
    210    [
    211      "Article that is not focusable is not considered interactive",
    212      "#article-1",
    213      null,
    214    ],
    215    ["Focusable article is considered interactive", "#article-2", null],
    216    [
    217      "Column header that is not focusable is not considered interactive (ARIA grid)",
    218      "#columnheader-1",
    219      null,
    220    ],
    221    [
    222      "Column header that is not focusable is not considered interactive (ARIA table)",
    223      "#columnheader-2",
    224      null,
    225    ],
    226    [
    227      "Column header that is not focusable is not considered interactive (table)",
    228      "#columnheader-3",
    229      null,
    230    ],
    231    [
    232      "Column header that is focusable is considered interactive (table)",
    233      "#columnheader-4",
    234      null,
    235    ],
    236    [
    237      "Column header that is not focusable is not considered interactive (table as ARIA grid)",
    238      "#columnheader-5",
    239      null,
    240    ],
    241    [
    242      "Column header that is focusable is considered interactive (table as ARIA grid)",
    243      "#columnheader-6",
    244      null,
    245    ],
    246    [
    247      "Row header that is not focusable is not considered interactive",
    248      "#rowheader-1",
    249      null,
    250    ],
    251    [
    252      "Row header that is not focusable is not considered interactive",
    253      "#rowheader-2",
    254      null,
    255    ],
    256    [
    257      "Row header that is not focusable is not considered interactive",
    258      "#rowheader-3",
    259      null,
    260    ],
    261    [
    262      "Row header that is focusable is considered interactive",
    263      "#rowheader-4",
    264      null,
    265    ],
    266    [
    267      "Row header that is not focusable is not considered interactive (table as ARIA grid)",
    268      "#rowheader-5",
    269      null,
    270    ],
    271    [
    272      "Row header that is focusable is considered interactive (table as ARIA grid)",
    273      "#rowheader-6",
    274      null,
    275    ],
    276    [
    277      "Gridcell that is not focusable is not considered interactive (ARIA grid)",
    278      "#gridcell-1",
    279      null,
    280    ],
    281    [
    282      "Gridcell that is focusable is considered interactive (ARIA grid)",
    283      "#gridcell-2",
    284      null,
    285    ],
    286    [
    287      "Gridcell that is not focusable is not considered interactive (table as ARIA grid)",
    288      "#gridcell-3",
    289      null,
    290    ],
    291    [
    292      "Gridcell that is focusable is considered interactive (table as ARIA grid)",
    293      "#gridcell-4",
    294      null,
    295    ],
    296    [
    297      "Tab list that is not focusable is not considered interactive",
    298      "#tablist-1",
    299      null,
    300    ],
    301    ["Focusable tab list is considered interactive", "#tablist-2", null],
    302    [
    303      "Scrollbar that is not focusable is not considered interactive",
    304      "#scrollbar-1",
    305      null,
    306    ],
    307    ["Focusable scrollbar is considered interactive", "#scrollbar-2", null],
    308    [
    309      "Separator that is not focusable is not considered interactive",
    310      "#separator-1",
    311      null,
    312    ],
    313    ["Focusable separator is considered interactive", "#separator-2", null],
    314    [
    315      "Toolbar that is not focusable is not considered interactive",
    316      "#toolbar-1",
    317      null,
    318    ],
    319    ["Focusable toolbar is considered interactive", "#toolbar-2", null],
    320    [
    321      "Menu popup that is not focusable is not considered interactive",
    322      "#menu-1",
    323      null,
    324    ],
    325    ["Focusable menu popup is considered interactive", "#menu-2", null],
    326    [
    327      "Menubar that is not focusable is not considered interactive",
    328      "#menubar-1",
    329      null,
    330    ],
    331    ["Focusable menubar is considered interactive", "#menubar-2", null],
    332    ["input type=search is considered interactive", "#input-search", null],
    333  ];
    334 
    335  for (const [description, selector, expected] of tests) {
    336    info(description);
    337    const node = await walker.querySelector(walker.rootNode, selector);
    338    const front = await a11yWalker.getAccessibleFor(node);
    339    const audit = await front.audit({ types: [KEYBOARD] });
    340    Assert.deepEqual(
    341      audit[KEYBOARD],
    342      expected,
    343      `Audit result for ${selector} is correct.`
    344    );
    345  }
    346 
    347  info("Text leaf inside a link (jump action is propagated to the text link)");
    348  let node = await walker.querySelector(walker.rootNode, "#link-5");
    349  let parent = await a11yWalker.getAccessibleFor(node);
    350  let front = (await parent.children())[0];
    351  let audit = await front.audit({ types: [KEYBOARD] });
    352  Assert.deepEqual(
    353    audit[KEYBOARD],
    354    null,
    355    "Text leafs are excluded from semantics rule."
    356  );
    357 
    358  info("Combobox list that is invisible");
    359  node = await walker.querySelector(walker.rootNode, "#combobox-1");
    360  parent = await a11yWalker.getAccessibleFor(node);
    361  front = (await parent.children())[0];
    362  audit = await front.audit({ types: [KEYBOARD] });
    363  Assert.deepEqual(
    364    audit[KEYBOARD],
    365    null,
    366    "Combobox lists (invisible) are excluded from semantics rule."
    367  );
    368 
    369  await waitForA11yShutdown(parentAccessibility);
    370  await target.destroy();
    371  gBrowser.removeCurrentTab();
    372 });