tor-browser

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

browser_roles_elements.js (12302B)


      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 /**
     15 * Test different HTML elements for their roles and subroles
     16 */
     17 function testRoleAndSubRole(accDoc, id, axRole, axSubRole, axRoleDescription) {
     18  let el = getNativeInterface(accDoc, id);
     19  if (axRole) {
     20    is(
     21      el.getAttributeValue("AXRole"),
     22      axRole,
     23      "AXRole for " + id + " is " + axRole
     24    );
     25  }
     26  if (axSubRole) {
     27    is(
     28      el.getAttributeValue("AXSubrole"),
     29      axSubRole,
     30      "Subrole for " + id + " is " + axSubRole
     31    );
     32  }
     33  if (axRoleDescription) {
     34    is(
     35      el.getAttributeValue("AXRoleDescription"),
     36      axRoleDescription,
     37      "Subrole for " + id + " is " + axRoleDescription
     38    );
     39  }
     40 }
     41 
     42 addAccessibleTask(
     43  `
     44  <!-- WAI-ARIA landmark roles -->
     45  <div id="application" role="application"></div>
     46  <div id="banner" role="banner"></div>
     47  <div id="complementary" role="complementary"></div>
     48  <div id="contentinfo" role="contentinfo"></div>
     49  <div id="form" role="form"></div>
     50  <div id="form_label" aria-label="form" role="form"></div>
     51  <div id="main" role="main"></div>
     52  <div id="navigation" role="navigation"></div>
     53  <div id="search" role="search"></div>
     54  <div id="searchbox" role="searchbox"></div>
     55 
     56  <!-- DPub landmarks -->
     57  <div id="dPubNavigation" role="doc-index"></div>
     58  <div id="dPubRegion" role="doc-introduction"></div>
     59 
     60  <!-- Other WAI-ARIA widget roles -->
     61  <div id="alert" role="alert"></div>
     62  <div id="alertdialog" role="alertdialog"></div>
     63  <div id="article" role="article"></div>
     64  <div id="code" role="code"></div>
     65  <div id="dialog" role="dialog"></div>
     66  <div id="ariaDocument" role="document"></div>
     67  <div id="log" role="log"></div>
     68  <div id="marquee" role="marquee"></div>
     69  <div id="ariaMath" role="math"></div>
     70  <div id="note" role="note"></div>
     71  <div id="ariaRegion" aria-label="region" role="region"></div>
     72  <div id="ariaStatus" role="status"></div>
     73  <div id="switch" role="switch"></div>
     74  <div id="timer" role="timer"></div>
     75  <div id="tooltip" role="tooltip"></div>
     76  <div role="menu"><input type="radio" role="menuitemradio" id="menuitemradio"></div>
     77  <div role="menu"><input type="checkbox" role="menuitemcheckbox" id="menuitemcheckbox"></div>
     78  <input type="datetime-local" id="datetime">
     79 
     80  <!-- text entries -->
     81  <div id="textbox_multiline" role="textbox" aria-multiline="true"></div>
     82  <div id="textbox_singleline" role="textbox" aria-multiline="false"></div>
     83  <textarea id="textArea"></textarea>
     84  <input id="textInput">
     85 
     86  <!-- True HTML5 search box -->
     87  <input type="search" id="htmlSearch" />
     88 
     89  <!-- Password input -->
     90  <input type="password" id="password" />
     91 
     92  <!-- A button morphed into a toggle via ARIA -->
     93  <button id="toggle" aria-pressed="false"></button>
     94 
     95  <!-- A button with a 'banana' role description -->
     96  <button id="banana" aria-roledescription="banana"></button>
     97 
     98  <!-- Other elements -->
     99  <del id="deletion">Deleted text</del>
    100  <dl id="dl"><dt id="dt">term</dt><dd id="dd">definition</dd></dl>
    101  <hr id="hr" />
    102  <ins id="insertion">Inserted text</ins>
    103  <meter id="meter" min="0" max="100" value="24">meter text here</meter>
    104  <sub id="sub">sub text here</sub>
    105  <sup id="sup">sup text here</sup>
    106 
    107  <!-- Some SVG stuff -->
    108  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg"
    109       xmlns:xlink="http://www.w3.org/1999/xlink">
    110    <g id="g">
    111      <title>g</title>
    112    </g>
    113    <rect width="300" height="100" id="rect"
    114          style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)">
    115      <title>rect</title>
    116    </rect>
    117    <circle cx="100" cy="50" r="40" stroke="black" id="circle"
    118            stroke-width="2" fill="red">
    119      <title>circle</title>
    120    </circle>
    121    <ellipse cx="300" cy="80" rx="100" ry="50" id="ellipse"
    122             style="fill:yellow;stroke:purple;stroke-width:2">
    123      <title>ellipse</title>
    124    </ellipse>
    125    <line x1="0" y1="0" x2="200" y2="200" id="line"
    126          style="stroke:rgb(255,0,0);stroke-width:2">
    127      <title>line</title>
    128    </line>
    129    <polygon points="200,10 250,190 160,210" id="polygon"
    130             style="fill:lime;stroke:purple;stroke-width:1">
    131      <title>polygon</title>
    132    </polygon>
    133    <polyline points="20,20 40,25 60,40 80,120 120,140 200,180" id="polyline"
    134              style="fill:none;stroke:black;stroke-width:3" >
    135      <title>polyline</title>
    136    </polyline>
    137    <path d="M150 0 L75 200 L225 200 Z" id="path">
    138      <title>path</title>
    139    </path>
    140    <image x1="25" y1="80" width="50" height="20" id="image"
    141           xlink:href="../moz.png">
    142      <title>image</title>
    143    </image>
    144  </svg>`,
    145  (browser, accDoc) => {
    146    // WAI-ARIA landmark subroles, regardless of AXRole
    147    testRoleAndSubRole(accDoc, "application", null, "AXLandmarkApplication");
    148    testRoleAndSubRole(accDoc, "banner", null, "AXLandmarkBanner");
    149    testRoleAndSubRole(
    150      accDoc,
    151      "complementary",
    152      null,
    153      "AXLandmarkComplementary"
    154    );
    155    testRoleAndSubRole(accDoc, "contentinfo", null, "AXLandmarkContentInfo");
    156    testRoleAndSubRole(accDoc, "form", null, "AXApplicationGroup");
    157    testRoleAndSubRole(accDoc, "form_label", null, "AXLandmarkForm");
    158    testRoleAndSubRole(accDoc, "main", null, "AXLandmarkMain");
    159    testRoleAndSubRole(accDoc, "navigation", null, "AXLandmarkNavigation");
    160    testRoleAndSubRole(accDoc, "search", null, "AXLandmarkSearch");
    161    testRoleAndSubRole(accDoc, "searchbox", null, "AXSearchField");
    162 
    163    // DPub roles map into two categories, sample one of each
    164    testRoleAndSubRole(
    165      accDoc,
    166      "dPubNavigation",
    167      "AXGroup",
    168      "AXLandmarkNavigation"
    169    );
    170    testRoleAndSubRole(accDoc, "dPubRegion", "AXGroup", "AXLandmarkRegion");
    171 
    172    // ARIA widget roles
    173    testRoleAndSubRole(accDoc, "alert", null, "AXApplicationAlert");
    174    testRoleAndSubRole(
    175      accDoc,
    176      "alertdialog",
    177      "AXGroup",
    178      "AXApplicationAlertDialog",
    179      "alert dialog"
    180    );
    181    testRoleAndSubRole(accDoc, "article", null, "AXDocumentArticle");
    182    testRoleAndSubRole(accDoc, "code", "AXGroup", "AXCodeStyleGroup");
    183    testRoleAndSubRole(accDoc, "dialog", null, "AXApplicationDialog", "dialog");
    184    testRoleAndSubRole(accDoc, "ariaDocument", null, "AXDocument");
    185    testRoleAndSubRole(accDoc, "log", null, "AXApplicationLog");
    186    testRoleAndSubRole(accDoc, "marquee", null, "AXApplicationMarquee");
    187    testRoleAndSubRole(accDoc, "ariaMath", null, "AXDocumentMath");
    188    testRoleAndSubRole(accDoc, "note", null, "AXDocumentNote");
    189    testRoleAndSubRole(accDoc, "ariaRegion", null, "AXLandmarkRegion");
    190    testRoleAndSubRole(accDoc, "ariaStatus", "AXGroup", "AXApplicationStatus");
    191    testRoleAndSubRole(accDoc, "switch", "AXCheckBox", "AXSwitch");
    192    testRoleAndSubRole(accDoc, "timer", null, "AXApplicationTimer");
    193    testRoleAndSubRole(accDoc, "tooltip", "AXGroup", "AXUserInterfaceTooltip");
    194    testRoleAndSubRole(accDoc, "menuitemradio", "AXMenuItem", null);
    195    testRoleAndSubRole(accDoc, "menuitemcheckbox", "AXMenuItem", null);
    196    testRoleAndSubRole(accDoc, "datetime", "AXGroup", null);
    197    // XXX for datetime elements, we spoof the role via the title, since
    198    // providing the correct role results in the internal elements being
    199    // unreachable by VO
    200    is(
    201      getNativeInterface(accDoc, "datetime").getAttributeValue("AXTitle"),
    202      "date field"
    203    );
    204 
    205    // Text boxes
    206    testRoleAndSubRole(accDoc, "textbox_multiline", "AXTextArea");
    207    testRoleAndSubRole(accDoc, "textbox_singleline", "AXTextField");
    208    testRoleAndSubRole(accDoc, "textArea", "AXTextArea");
    209    testRoleAndSubRole(accDoc, "textInput", "AXTextField");
    210 
    211    // True HTML5 search field
    212    testRoleAndSubRole(accDoc, "htmlSearch", "AXTextField", "AXSearchField");
    213 
    214    // Password input
    215    testRoleAndSubRole(accDoc, "password", "AXTextField", "AXSecureTextField");
    216 
    217    // A button morphed into a toggle by ARIA
    218    testRoleAndSubRole(accDoc, "toggle", "AXCheckBox", "AXToggle");
    219 
    220    // A banana button
    221    testRoleAndSubRole(accDoc, "banana", "AXButton", null, "banana");
    222 
    223    // Other elements
    224    testRoleAndSubRole(accDoc, "deletion", "AXGroup", "AXDeleteStyleGroup");
    225    testRoleAndSubRole(accDoc, "dl", "AXList", "AXDefinitionList");
    226    testRoleAndSubRole(accDoc, "dt", "AXGroup", "AXTerm");
    227    testRoleAndSubRole(accDoc, "dd", "AXGroup", "AXDefinition");
    228    testRoleAndSubRole(accDoc, "hr", "AXSplitter", "AXContentSeparator");
    229    testRoleAndSubRole(accDoc, "insertion", "AXGroup", "AXInsertStyleGroup");
    230    testRoleAndSubRole(
    231      accDoc,
    232      "meter",
    233      "AXLevelIndicator",
    234      "AXMeter",
    235      "level indicator"
    236    );
    237    testRoleAndSubRole(accDoc, "sub", "AXGroup", "AXSubscriptStyleGroup");
    238    testRoleAndSubRole(accDoc, "sup", "AXGroup", "AXSuperscriptStyleGroup");
    239 
    240    // Some SVG stuff
    241    testRoleAndSubRole(accDoc, "svg", "AXImage");
    242    testRoleAndSubRole(accDoc, "g", "AXGroup");
    243    testRoleAndSubRole(accDoc, "rect", "AXImage");
    244    testRoleAndSubRole(accDoc, "circle", "AXImage");
    245    testRoleAndSubRole(accDoc, "ellipse", "AXImage");
    246    testRoleAndSubRole(accDoc, "line", "AXImage");
    247    testRoleAndSubRole(accDoc, "polygon", "AXImage");
    248    testRoleAndSubRole(accDoc, "polyline", "AXImage");
    249    testRoleAndSubRole(accDoc, "path", "AXImage");
    250    testRoleAndSubRole(accDoc, "image", "AXImage");
    251  }
    252 );
    253 
    254 addAccessibleTask(
    255  `
    256  <figure id="figure">
    257    <img id="img" src="http://example.com/a11y/accessible/tests/mochitest/moz.png" alt="Logo">
    258    <p>Non-image figure content</p>
    259    <figcaption id="figcaption">Old Mozilla logo</figcaption>
    260  </figure>`,
    261  (browser, accDoc) => {
    262    let figure = getNativeInterface(accDoc, "figure");
    263    ok(!figure.getAttributeValue("AXTitle"), "Figure should not have a title");
    264    is(
    265      figure.getAttributeValue("AXDescription"),
    266      "Old Mozilla logo",
    267      "Correct figure label"
    268    );
    269    is(figure.getAttributeValue("AXRole"), "AXGroup", "Correct figure role");
    270    is(
    271      figure.getAttributeValue("AXRoleDescription"),
    272      "figure",
    273      "Correct figure role description"
    274    );
    275 
    276    let img = getNativeInterface(accDoc, "img");
    277    ok(!img.getAttributeValue("AXTitle"), "img should not have a title");
    278    is(img.getAttributeValue("AXDescription"), "Logo", "Correct img label");
    279    is(img.getAttributeValue("AXRole"), "AXImage", "Correct img role");
    280    is(
    281      img.getAttributeValue("AXRoleDescription"),
    282      "image",
    283      "Correct img role description"
    284    );
    285 
    286    let figcaption = getNativeInterface(accDoc, "figcaption");
    287    ok(
    288      !figcaption.getAttributeValue("AXTitle"),
    289      "figcaption should not have a title"
    290    );
    291    ok(
    292      !figcaption.getAttributeValue("AXDescription"),
    293      "figcaption should not have a label"
    294    );
    295    is(
    296      figcaption.getAttributeValue("AXRole"),
    297      "AXGroup",
    298      "Correct figcaption role"
    299    );
    300    is(
    301      figcaption.getAttributeValue("AXRoleDescription"),
    302      "group",
    303      "Correct figcaption role description"
    304    );
    305  }
    306 );
    307 
    308 addAccessibleTask(`<button>hello world</button>`, async (browser, accDoc) => {
    309  const webArea = accDoc.nativeInterface.QueryInterface(
    310    Ci.nsIAccessibleMacInterface
    311  );
    312 
    313  is(
    314    webArea.getAttributeValue("AXRole"),
    315    "AXWebArea",
    316    "web area should be an AXWebArea"
    317  );
    318  ok(
    319    !webArea.attributeNames.includes("AXSubrole"),
    320    "AXWebArea should not have a subrole"
    321  );
    322 
    323  let roleChanged = waitForMacEvent("AXMozRoleChanged");
    324  await SpecialPowers.spawn(browser, [], () => {
    325    content.document.body.setAttribute("role", "application");
    326  });
    327  await roleChanged;
    328 
    329  is(
    330    webArea.getAttributeValue("AXRole"),
    331    "AXWebArea",
    332    "web area should retain AXWebArea role"
    333  );
    334  ok(
    335    !webArea.attributeNames.includes("AXSubrole"),
    336    "AXWebArea should not have a subrole"
    337  );
    338 
    339  let rootGroup = webArea.getAttributeValue("AXChildren")[0];
    340  is(rootGroup.getAttributeValue("AXRole"), "AXGroup");
    341  is(rootGroup.getAttributeValue("AXSubrole"), "AXLandmarkApplication");
    342 });