tor-browser

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

browser_generalProps.js (15366B)


      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 /* eslint-disable camelcase */
     15 // From https://learn.microsoft.com/en-us/windows/win32/winauto/landmark-type-identifiers
     16 const UIA_CustomLandmarkTypeId = 80000;
     17 const UIA_MainLandmarkTypeId = 80002;
     18 /* eslint-enable camelcase */
     19 
     20 /**
     21 * Test the Name property.
     22 */
     23 addUiaTask(
     24  `
     25 <button id="button">before</button>
     26 <div id="div">div</div>
     27  `,
     28  async function testName(browser) {
     29    await definePyVar("doc", `getDocUia()`);
     30    await assignPyVarToUiaWithId("button");
     31    is(
     32      await runPython(`button.CurrentName`),
     33      "before",
     34      "button has correct name"
     35    );
     36    await assignPyVarToUiaWithId("div");
     37    is(await runPython(`div.CurrentName`), "", "div has no name");
     38 
     39    info("Setting aria-label on button");
     40    await setUpWaitForUiaPropEvent("Name", "button");
     41    await invokeSetAttribute(browser, "button", "aria-label", "after");
     42    await waitForUiaEvent();
     43    ok(true, "Got Name prop change event on button");
     44    is(
     45      await runPython(`button.CurrentName`),
     46      "after",
     47      "button has correct name"
     48    );
     49  }
     50 );
     51 
     52 /**
     53 * Test the FullDescription property.
     54 */
     55 addUiaTask(
     56  `
     57 <button id="button" aria-description="before">button</button>
     58 <div id="div">div</div>
     59  `,
     60  async function testFullDescription(browser) {
     61    await definePyVar("doc", `getDocUia()`);
     62    await assignPyVarToUiaWithId("button");
     63    is(
     64      await runPython(`button.CurrentFullDescription`),
     65      "before",
     66      "button has correct FullDescription"
     67    );
     68    await assignPyVarToUiaWithId("div");
     69    is(
     70      await runPython(`div.CurrentFullDescription`),
     71      "",
     72      "div has no FullDescription"
     73    );
     74 
     75    info("Setting aria-description on button");
     76    await setUpWaitForUiaPropEvent("FullDescription", "button");
     77    await invokeSetAttribute(browser, "button", "aria-description", "after");
     78    await waitForUiaEvent();
     79    ok(true, "Got FullDescription prop change event on button");
     80    is(
     81      await runPython(`button.CurrentFullDescription`),
     82      "after",
     83      "button has correct FullDescription"
     84    );
     85  },
     86  // The IA2 -> UIA proxy doesn't support FullDescription.
     87  { uiaEnabled: true, uiaDisabled: false }
     88 );
     89 
     90 /**
     91 * Test the IsEnabled property.
     92 */
     93 addUiaTask(
     94  `
     95 <button id="button">button</button>
     96 <p id="p">p</p>
     97  `,
     98  async function testIsEnabled(browser) {
     99    await definePyVar("doc", `getDocUia()`);
    100    await assignPyVarToUiaWithId("button");
    101    ok(await runPython(`button.CurrentIsEnabled`), "button has IsEnabled true");
    102    // The IA2 -> UIA proxy doesn't fire IsEnabled prop change events.
    103    if (gIsUiaEnabled) {
    104      info("Setting disabled on button");
    105      await setUpWaitForUiaPropEvent("IsEnabled", "button");
    106      await invokeSetAttribute(browser, "button", "disabled", true);
    107      await waitForUiaEvent();
    108      ok(true, "Got IsEnabled prop change event on button");
    109      ok(
    110        !(await runPython(`button.CurrentIsEnabled`)),
    111        "button has IsEnabled false"
    112      );
    113    }
    114 
    115    await assignPyVarToUiaWithId("p");
    116    ok(await runPython(`p.CurrentIsEnabled`), "p has IsEnabled true");
    117  }
    118 );
    119 
    120 async function testGroupPos(id, level, pos, size) {
    121  await assignPyVarToUiaWithId(id);
    122  is(await runPython(`${id}.CurrentLevel`), level, `${id} Level correct`);
    123  is(
    124    await runPython(`${id}.CurrentPositionInSet`),
    125    pos,
    126    `${id} PositionInSet correct`
    127  );
    128  is(
    129    await runPython(`${id}.CurrentSizeOfSet`),
    130    size,
    131    `${id} SizeOfSet correct`
    132  );
    133 }
    134 
    135 /**
    136 * Test the Level, PositionInSet and SizeOfSet properties.
    137 */
    138 addUiaTask(
    139  `
    140 <ul>
    141  <li id="li1">li1<ul id="ul1">
    142    <li id="li2a">li2a</li>
    143    <li id="li2b" hidden>li2b</li>
    144    <li id="li2c">li2c</li>
    145  </ul></li>
    146 </ul>
    147 <h2 id="h2">h2</h2>
    148 <button id="button">button</button>
    149  `,
    150  async function testGroupPosProps(browser) {
    151    await definePyVar("doc", `getDocUia()`);
    152    await testGroupPos("li1", 1, 1, 1);
    153    await testGroupPos("li2a", 2, 1, 2);
    154    await testGroupPos("li2c", 2, 2, 2);
    155    info("Showing li2b");
    156    // There aren't events in any API for a change to group position properties
    157    // because this would be too spammy and isn't particularly useful given
    158    // how frequently these can change.
    159    let shown = waitForEvent(EVENT_SHOW, "li2b");
    160    await invokeContentTask(browser, [], () => {
    161      content.document.getElementById("li2b").hidden = false;
    162    });
    163    await shown;
    164    await testGroupPos("li2a", 2, 1, 3);
    165    await testGroupPos("li2b", 2, 2, 3);
    166    await testGroupPos("li2c", 2, 3, 3);
    167 
    168    // The IA2 -> UIA proxy doesn't map heading level to the Level property.
    169    if (gIsUiaEnabled) {
    170      await testGroupPos("h2", 2, 0, 0);
    171    }
    172    await testGroupPos("button", 0, 0, 0);
    173  }
    174 );
    175 
    176 /**
    177 * Test the FrameworkId property.
    178 */
    179 addUiaTask(
    180  `<button id="button">button</button>`,
    181  async function testFrameworkId() {
    182    await definePyVar("doc", `getDocUia()`);
    183    is(
    184      await runPython(`doc.CurrentFrameworkId`),
    185      "Gecko",
    186      "doc FrameworkId is correct"
    187    );
    188    await assignPyVarToUiaWithId("button");
    189    is(
    190      await runPython(`button.CurrentFrameworkId`),
    191      "Gecko",
    192      "button FrameworkId is correct"
    193    );
    194  }
    195 );
    196 
    197 /**
    198 * Test the ClassName property.
    199 */
    200 addUiaTask(
    201  `
    202 <p id="p">p</p>
    203 <button id="button" class="c1">button</button>
    204  `,
    205  async function testClassName(browser, docAcc) {
    206    await definePyVar("doc", `getDocUia()`);
    207    await assignPyVarToUiaWithId("p");
    208    ok(!(await runPython(`p.CurrentClassName`)), "p has no ClassName");
    209 
    210    await assignPyVarToUiaWithId("button");
    211    is(
    212      await runPython(`button.CurrentClassName`),
    213      "c1",
    214      "button has correct ClassName"
    215    );
    216    info("Changing button class");
    217    await invokeSetAttribute(browser, "button", "class", "c2 c3");
    218    // Gecko doesn't fire an event for class changes, as this isn't useful for
    219    // clients.
    220    const button = findAccessibleChildByID(docAcc, "button");
    221    await untilCacheIs(
    222      () => button.attributes.getStringProperty("class"),
    223      "c2 c3",
    224      "button class updated"
    225    );
    226    is(
    227      await runPython(`button.CurrentClassName`),
    228      "c2 c3",
    229      "button has correct ClassName"
    230    );
    231  },
    232  // The IA2 -> UIA proxy doesn't support ClassName.
    233  { uiaEnabled: true, uiaDisabled: false }
    234 );
    235 
    236 /**
    237 * Test the AriaRole property.
    238 */
    239 addUiaTask(
    240  `
    241 <div id="button" role="button">button</div>
    242 <div id="main" role="main">main</div>
    243 <div id="unknown" role="unknown">unknown</div>
    244 <button id="computedButton">computedButton</button>
    245 <h1 id="computedHeading">computedHeading</h1>
    246 <main id="computedMain">computedMain</main>
    247 <div id="generic">generic</div>
    248  `,
    249  async function testAriaRole() {
    250    await definePyVar("doc", `getDocUia()`);
    251    is(
    252      await runPython(`findUiaByDomId(doc, "button").CurrentAriaRole`),
    253      "button",
    254      "button has correct AriaRole"
    255    );
    256    is(
    257      await runPython(`findUiaByDomId(doc, "main").CurrentAriaRole`),
    258      "main",
    259      "main has correct AriaRole"
    260    );
    261    is(
    262      await runPython(`findUiaByDomId(doc, "unknown").CurrentAriaRole`),
    263      "unknown",
    264      "unknown has correct AriaRole"
    265    );
    266    // The IA2 -> UIA proxy doesn't compute ARIA roles.
    267    if (gIsUiaEnabled) {
    268      is(
    269        await runPython(
    270          `findUiaByDomId(doc, "computedButton").CurrentAriaRole`
    271        ),
    272        "button",
    273        "computedButton has correct AriaRole"
    274      );
    275      is(
    276        await runPython(`findUiaByDomId(doc, "computedMain").CurrentAriaRole`),
    277        "main",
    278        "computedMain has correct AriaRole"
    279      );
    280      is(
    281        await runPython(
    282          `findUiaByDomId(doc, "computedHeading").CurrentAriaRole`
    283        ),
    284        "heading",
    285        "computedHeading has correct AriaRole"
    286      );
    287      is(
    288        await runPython(`findUiaByDomId(doc, "generic").CurrentAriaRole`),
    289        "generic",
    290        "generic has correct AriaRole"
    291      );
    292    }
    293  }
    294 );
    295 
    296 /**
    297 * Test the LocalizedControlType property. We don't support this ourselves, but
    298 * the system provides it based on ControlType and AriaRole.
    299 */
    300 addUiaTask(
    301  `
    302 <button id="button">button</button>
    303 <h1 id="h1">h1</h1>
    304 <main id="main">main</main>
    305  `,
    306  async function testLocalizedControlType() {
    307    await definePyVar("doc", `getDocUia()`);
    308    is(
    309      await runPython(
    310        `findUiaByDomId(doc, "button").CurrentLocalizedControlType`
    311      ),
    312      "button",
    313      "button has correct LocalizedControlType"
    314    );
    315    // The IA2 -> UIA proxy doesn't compute ARIA roles, so it can't compute the
    316    // correct LocalizedControlType for these either.
    317    if (gIsUiaEnabled) {
    318      is(
    319        await runPython(
    320          `findUiaByDomId(doc, "h1").CurrentLocalizedControlType`
    321        ),
    322        "heading",
    323        "h1 has correct LocalizedControlType"
    324      );
    325      is(
    326        await runPython(
    327          `findUiaByDomId(doc, "main").CurrentLocalizedControlType`
    328        ),
    329        "main",
    330        "main has correct LocalizedControlType"
    331      );
    332    }
    333  }
    334 );
    335 
    336 /**
    337 * Test the LandmarkType property.
    338 */
    339 addUiaTask(
    340  `
    341 <div id="main" role="main">main</div>
    342 <main id="htmlMain">htmlMain</main>
    343 <div id="banner" role="banner">banner</div>
    344 <header id="header">header</header>
    345 <div id="region" role="region" aria-label="region">region</div>
    346 <div id="unnamedRegion" role="region">unnamedRegion</div>
    347 <main id="mainBanner" role="banner">mainBanner</main>
    348 <div id="none">none</div>
    349  `,
    350  async function testLandmarkType() {
    351    await definePyVar("doc", `getDocUia()`);
    352    is(
    353      await runPython(`findUiaByDomId(doc, "main").CurrentLandmarkType`),
    354      UIA_MainLandmarkTypeId,
    355      "main has correct LandmarkType"
    356    );
    357    is(
    358      await runPython(`findUiaByDomId(doc, "htmlMain").CurrentLandmarkType`),
    359      UIA_MainLandmarkTypeId,
    360      "htmlMain has correct LandmarkType"
    361    );
    362    is(
    363      await runPython(`findUiaByDomId(doc, "banner").CurrentLandmarkType`),
    364      UIA_CustomLandmarkTypeId,
    365      "banner has correct LandmarkType"
    366    );
    367    is(
    368      await runPython(`findUiaByDomId(doc, "header").CurrentLandmarkType`),
    369      UIA_CustomLandmarkTypeId,
    370      "header has correct LandmarkType"
    371    );
    372    is(
    373      await runPython(`findUiaByDomId(doc, "region").CurrentLandmarkType`),
    374      UIA_CustomLandmarkTypeId,
    375      "region has correct LandmarkType"
    376    );
    377    is(
    378      await runPython(
    379        `findUiaByDomId(doc, "unnamedRegion").CurrentLandmarkType`
    380      ),
    381      0,
    382      "unnamedRegion has correct LandmarkType"
    383    );
    384    // ARIA role takes precedence.
    385    is(
    386      await runPython(`findUiaByDomId(doc, "mainBanner").CurrentLandmarkType`),
    387      UIA_CustomLandmarkTypeId,
    388      "mainBanner has correct LandmarkType"
    389    );
    390    is(
    391      await runPython(`findUiaByDomId(doc, "none").CurrentLandmarkType`),
    392      0,
    393      "none has correct LandmarkType"
    394    );
    395  }
    396 );
    397 
    398 /**
    399 * Test the LocalizedLandmarkType property.
    400 */
    401 addUiaTask(
    402  `
    403 <div id="main" role="main">main</div>
    404 <div id="contentinfo" role="contentinfo">contentinfo</div>
    405 <div id="region" role="region" aria-label="region">region</div>
    406 <div id="unnamedRegion" role="region">unnamedRegion</div>
    407 <main id="mainBanner" role="banner">mainBanner</main>
    408 <div id="none">none</div>
    409  `,
    410  async function testLocalizedLandmarkType() {
    411    await definePyVar("doc", `getDocUia()`);
    412    // Provided by the system.
    413    is(
    414      await runPython(
    415        `findUiaByDomId(doc, "main").CurrentLocalizedLandmarkType`
    416      ),
    417      "main",
    418      "main has correct LocalizedLandmarkType"
    419    );
    420    // The IA2 -> UIA proxy doesn't follow the Core AAM spec for this role.
    421    if (gIsUiaEnabled) {
    422      // Provided by us.
    423      is(
    424        await runPython(
    425          `findUiaByDomId(doc, "contentinfo").CurrentLocalizedLandmarkType`
    426        ),
    427        "content information",
    428        "contentinfo has correct LocalizedLandmarkType"
    429      );
    430    }
    431    is(
    432      await runPython(
    433        `findUiaByDomId(doc, "region").CurrentLocalizedLandmarkType`
    434      ),
    435      "region",
    436      "region has correct LocalizedLandmarkType"
    437    );
    438    // Invalid landmark.
    439    is(
    440      await runPython(
    441        `findUiaByDomId(doc, "unnamedRegion").CurrentLocalizedLandmarkType`
    442      ),
    443      "",
    444      "unnamedRegion has correct LocalizedLandmarkType"
    445    );
    446    // ARIA role takes precedence.
    447    is(
    448      await runPython(
    449        `findUiaByDomId(doc, "mainBanner").CurrentLocalizedLandmarkType`
    450      ),
    451      "banner",
    452      "mainBanner has correct LocalizedLandmarkType"
    453    );
    454    is(
    455      await runPython(
    456        `findUiaByDomId(doc, "none").CurrentLocalizedLandmarkType`
    457      ),
    458      "",
    459      "none has correct LocalizedLandmarkType"
    460    );
    461  }
    462 );
    463 
    464 /**
    465 * Test the AcceleratorKey property.
    466 */
    467 addUiaTask(
    468  `
    469  <div id="button" role="button" aria-keyshortcuts="Alt+Shift+f">foo</div>
    470  `,
    471  async function testAcceleratorKey() {
    472    await definePyVar("doc", `getDocUia()`);
    473    is(
    474      await runPython(`findUiaByDomId(doc, "button").CurrentAcceleratorKey`),
    475      "Alt+Shift+f",
    476      "button has correct AcceleratorKey"
    477    );
    478  },
    479  { uiaEnabled: true, uiaDisabled: false }
    480 );
    481 
    482 /**
    483 * Test the IsOffscreen property.
    484 */
    485 addUiaTask(
    486  `
    487 <button id="onscreen">onscreen</button>
    488 <button id="offscreen" style="position: absolute; left: -10000px;">offscreen</button>
    489  `,
    490  async function testIsOffscreen(browser, docAcc) {
    491    await definePyVar("doc", `getDocUia()`);
    492    ok(
    493      !(await runPython(`findUiaByDomId(doc, "onscreen").CurrentIsOffscreen`)),
    494      "onscreen has correct IsOffscreen"
    495    );
    496    ok(
    497      await runPython(`findUiaByDomId(doc, "offscreen").CurrentIsOffscreen`),
    498      "offscreen has correct IsOffscreen"
    499    );
    500    ok(
    501      !(await runPython(`doc.CurrentIsOffscreen`)),
    502      "doc has correct IsOffscreen"
    503    );
    504    info("Opening a new tab");
    505    await BrowserTestUtils.withNewTab("", async () => {
    506      // withNewTab (nor a focus event) isn't enough to guarantee the new tab is
    507      // fully active in the foreground yet.
    508      await untilCacheOk(() => {
    509        const [state] = getStates(docAcc);
    510        return state & STATE_OFFSCREEN;
    511      }, "doc is offscreen in cross-platform tree");
    512      // doc is now a background tab, so it should be offscreen.
    513      ok(
    514        await runPython(`doc.CurrentIsOffscreen`),
    515        "doc has correct IsOffscreen"
    516      );
    517    });
    518  },
    519  { uiaEnabled: true, uiaDisabled: true }
    520 );
    521 
    522 /**
    523 * Test the IsPassword property.
    524 */
    525 addUiaTask(
    526  `
    527 <input type="text" id="text">
    528 <input type="password" id="password">
    529  `,
    530  async function testIsPassword() {
    531    await definePyVar("doc", `getDocUia()`);
    532    ok(
    533      !(await runPython(`findUiaByDomId(doc, "text").CurrentIsPassword`)),
    534      "text has correct IsPassword"
    535    );
    536    ok(
    537      await runPython(`findUiaByDomId(doc, "password").CurrentIsPassword`),
    538      "password has correct IsPassword"
    539    );
    540    ok(
    541      !(await runPython(`doc.CurrentIsPassword`)),
    542      "doc has correct IsPassword"
    543    );
    544  },
    545  { uiaEnabled: true, uiaDisabled: true }
    546 );