tor-browser

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

browser_test_general.js (17384B)


      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 add_setup(async function () {
      8  await SpecialPowers.pushPrefEnv({
      9    set: [["test.wait300msAfterTabSwitch", true]],
     10  });
     11 });
     12 
     13 async function runTests(browser, accDoc) {
     14  const dpr = await getContentDPR(browser);
     15 
     16  await testChildAtPoint(
     17    dpr,
     18    3,
     19    3,
     20    findAccessibleChildByID(accDoc, "list"),
     21    findAccessibleChildByID(accDoc, "listitem"),
     22    findAccessibleChildByID(accDoc, "inner").firstChild
     23  );
     24  todo(
     25    false,
     26    "Bug 746974 - children must match on all platforms. On Windows, " +
     27      "ChildAtPoint with eDeepestChild is incorrectly ignoring MustPrune " +
     28      "for the graphic."
     29  );
     30 
     31  const txt = findAccessibleChildByID(accDoc, "txt");
     32  await testChildAtPoint(dpr, 1, 1, txt, txt, txt);
     33 
     34  info(
     35    "::MustPrune case, point is outside of textbox accessible but is in document."
     36  );
     37  await testChildAtPoint(dpr, -1, -1, txt, null, null);
     38 
     39  info("::MustPrune case, point is outside of root accessible.");
     40  await testChildAtPoint(dpr, -10000, -10000, txt, null, null);
     41 
     42  info("Not specific case, point is inside of btn accessible.");
     43  const btn = findAccessibleChildByID(accDoc, "btn");
     44  await testChildAtPoint(dpr, 1, 1, btn, btn, btn);
     45 
     46  info("Not specific case, point is outside of btn accessible.");
     47  await testChildAtPoint(dpr, -1, -1, btn, null, null);
     48 
     49  info(
     50    "Out of flow accessible testing, do not return out of flow accessible " +
     51      "because it's not a child of the accessible even though visually it is."
     52  );
     53  await invokeContentTask(browser, [], () => {
     54    const { CommonUtils } = ChromeUtils.importESModule(
     55      "chrome://mochitests/content/browser/accessible/tests/browser/Common.sys.mjs"
     56    );
     57    const doc = content.document;
     58    const rectArea = CommonUtils.getNode("area", doc).getBoundingClientRect();
     59    const outOfFlow = CommonUtils.getNode("outofflow", doc);
     60    outOfFlow.style.left = rectArea.left + "px";
     61    outOfFlow.style.top = rectArea.top + "px";
     62  });
     63 
     64  const area = findAccessibleChildByID(accDoc, "area");
     65  await testChildAtPoint(dpr, 1, 1, area, area, area);
     66 
     67  info("Test image maps. Their children are not in the layout tree.");
     68  await waitForImageMap(browser, accDoc);
     69  const imgmap = findAccessibleChildByID(accDoc, "imgmap");
     70  ok(imgmap, "Image map exists");
     71  const theLetterA = imgmap.firstChild;
     72  await hitTest(browser, imgmap, theLetterA, theLetterA);
     73  await hitTest(
     74    browser,
     75    findAccessibleChildByID(accDoc, "container"),
     76    imgmap,
     77    theLetterA
     78  );
     79 
     80  info("hit testing for element contained by zero-width element");
     81  const container2Input = findAccessibleChildByID(accDoc, "container2_input");
     82  await hitTest(
     83    browser,
     84    findAccessibleChildByID(accDoc, "container2"),
     85    container2Input,
     86    container2Input
     87  );
     88 
     89  info("hittesting table, row, cells -- rows are not in the layout tree");
     90  const table = findAccessibleChildByID(accDoc, "table");
     91  const row = findAccessibleChildByID(accDoc, "row");
     92  const cell1 = findAccessibleChildByID(accDoc, "cell1");
     93 
     94  await hitTest(browser, table, row, cell1);
     95 
     96  info("Testing that an inaccessible child doesn't break hit testing");
     97  const containerWithInaccessibleChild = findAccessibleChildByID(
     98    accDoc,
     99    "containerWithInaccessibleChild"
    100  );
    101  const containerWithInaccessibleChildP2 = findAccessibleChildByID(
    102    accDoc,
    103    "containerWithInaccessibleChild_p2"
    104  );
    105  await hitTest(
    106    browser,
    107    containerWithInaccessibleChild,
    108    containerWithInaccessibleChildP2,
    109    containerWithInaccessibleChildP2.firstChild
    110  );
    111 
    112  info("Testing wrapped text");
    113  const wrappedTextLinkFirstP = findAccessibleChildByID(
    114    accDoc,
    115    "wrappedTextLinkFirstP"
    116  );
    117  const wrappedTextLinkFirstA = findAccessibleChildByID(
    118    accDoc,
    119    "wrappedTextLinkFirstA"
    120  );
    121  await hitTest(
    122    browser,
    123    wrappedTextLinkFirstP,
    124    wrappedTextLinkFirstA,
    125    wrappedTextLinkFirstA.firstChild
    126  );
    127  const wrappedTextLeafFirstP = findAccessibleChildByID(
    128    accDoc,
    129    "wrappedTextLeafFirstP"
    130  );
    131  const wrappedTextLeafFirstMark = findAccessibleChildByID(
    132    accDoc,
    133    "wrappedTextLeafFirstMark"
    134  );
    135  await hitTest(
    136    browser,
    137    wrappedTextLeafFirstP,
    138    wrappedTextLeafFirstMark,
    139    wrappedTextLeafFirstMark.firstChild
    140  );
    141  const wrappedTextNestedInlineP = findAccessibleChildByID(
    142    accDoc,
    143    "wrappedTextNestedInlineP"
    144  );
    145  const wrappedTextNestedInlineEm = findAccessibleChildByID(
    146    accDoc,
    147    "wrappedTextNestedInlineEm"
    148  );
    149  const wrappedTextNestedInlineStrong = findAccessibleChildByID(
    150    accDoc,
    151    "wrappedTextNestedInlineStrong"
    152  );
    153  await hitTest(
    154    browser,
    155    wrappedTextNestedInlineP,
    156    wrappedTextNestedInlineEm,
    157    wrappedTextNestedInlineStrong.firstChild
    158  );
    159  const wrappedTextPre = findAccessibleChildByID(accDoc, "wrappedTextPre");
    160  const wrappedTextPreCode = findAccessibleChildByID(
    161    accDoc,
    162    "wrappedTextPreCode"
    163  );
    164  await hitTest(
    165    browser,
    166    wrappedTextPre,
    167    wrappedTextPreCode,
    168    wrappedTextPreCode.firstChild
    169  );
    170  // hitTest() can only test the first character. We need to test a subsequent
    171  // character for this case.
    172  let [x, y, w] = await getContentBoundsForDOMElm(
    173    browser,
    174    "wrappedTextPreCode"
    175  );
    176  // Use the top center of the element.
    177  x = x + w / 2;
    178  await untilCacheIs(
    179    () => getChildAtPoint(wrappedTextPre, x, y, true),
    180    wrappedTextPreCode.firstChild,
    181    `Wrong deepest child accessible at the point (${x}, ${y}) of wrappedTextPre, sought wrappedTextPreCode leaf`
    182  );
    183 
    184  info("Testing image");
    185  const imageP = findAccessibleChildByID(accDoc, "imageP");
    186  const image = findAccessibleChildByID(accDoc, "image");
    187  await hitTest(browser, imageP, image, image);
    188 
    189  info("Testing image map with 0-sized area");
    190  const mapWith0AreaP = findAccessibleChildByID(accDoc, "mapWith0AreaP");
    191  const mapWith0Area = findAccessibleChildByID(accDoc, "mapWith0Area");
    192  await hitTest(browser, mapWith0AreaP, mapWith0Area, mapWith0Area);
    193 }
    194 
    195 addAccessibleTask(
    196  `
    197  <div role="list" id="list">
    198    <div role="listitem" id="listitem"><span title="foo" id="inner">inner</span>item</div>
    199  </div>
    200 
    201  <span role="button">button1</span><span role="button" id="btn">button2</span>
    202 
    203  <span role="textbox">textbox1</span><span role="textbox" id="txt">textbox2</span>
    204 
    205  <div id="outofflow" style="width: 10px; height: 10px; position: absolute; left: 0px; top: 0px; background-color: yellow;">
    206  </div>
    207  <div id="area" style="width: 100px; height: 100px; background-color: blue;"></div>
    208 
    209  <map name="atoz_map">
    210    <area id="thelettera" href="http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
    211          coords="0,0,15,15" alt="thelettera" shape="rect"/>
    212  </map>
    213 
    214  <div id="container">
    215    <img id="imgmap" width="447" height="15" usemap="#atoz_map" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif"/>
    216  </div>
    217 
    218  <div id="container2" style="width: 0px">
    219    <input id="container2_input">
    220  </div>
    221 
    222  <table id="table" border>
    223    <tr id="row">
    224      <td id="cell1">hello</td>
    225      <td id="cell2">world</td>
    226    </tr>
    227  </table>
    228 
    229  <div id="containerWithInaccessibleChild">
    230    <p>hi</p>
    231    <p aria-hidden="true">hi</p>
    232    <p id="containerWithInaccessibleChild_p2">bye</p>
    233  </div>
    234 
    235  <p id="wrappedTextLinkFirstP" style="width: 3ch; font-family: monospace;">
    236    <a id="wrappedTextLinkFirstA" href="https://example.com/">a</a>b cd
    237  </p>
    238 
    239  <p id="wrappedTextLeafFirstP" style="width: 3ch; font-family: monospace;">
    240    <mark id="wrappedTextLeafFirstMark">a</mark><a href="https://example.com/">b cd</a>
    241  </p>
    242 
    243  <p id="wrappedTextNestedInlineP" style="width: 1ch; font-family: monospace;">
    244    <em id="wrappedTextNestedInlineEm"><strong id="wrappedTextNestedInlineStrong">y </strong>z</em>
    245  </p>
    246 
    247  <pre id="wrappedTextPre"><code id="wrappedTextPreCode">ab cd
    248 e</pre>
    249 
    250  <p id="imageP">
    251    <img id="image" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif">
    252  </p>
    253 
    254  <map id="0Area">
    255    <area shape="rect">
    256  </map>
    257  <p id="mapWith0AreaP">
    258    <img id="mapWith0Area" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif" usemap="#0Area">
    259  </p>
    260  `,
    261  runTests,
    262  {
    263    iframe: true,
    264    remoteIframe: true,
    265    // Ensure that all hittest elements are in view.
    266    iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
    267  }
    268 );
    269 
    270 addAccessibleTask(
    271  `
    272  <div id="container">
    273    <h1 id="a">A</h1><h1 id="b">B</h1>
    274  </div>
    275  `,
    276  async function (browser, accDoc) {
    277    const a = findAccessibleChildByID(accDoc, "a");
    278    const b = findAccessibleChildByID(accDoc, "b");
    279    const dpr = await getContentDPR(browser);
    280    // eslint-disable-next-line no-unused-vars
    281    const [x, y, w, h] = Layout.getBounds(a, dpr);
    282    // The point passed below will be made relative to `b`, but
    283    // we'd like to test a point within `a`. Pass `a`s negative
    284    // width for an x offset. Pass zero as a y offset,
    285    // assuming the headings are on the same line.
    286    await testChildAtPoint(dpr, -w, 0, b, null, null);
    287  },
    288  {
    289    iframe: true,
    290    remoteIframe: true,
    291    // Ensure that all hittest elements are in view.
    292    iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
    293  }
    294 );
    295 
    296 addAccessibleTask(
    297  `
    298  <style>
    299    div {
    300      width: 50px;
    301      height: 50px;
    302      position: relative;
    303    }
    304 
    305    div > div {
    306      width: 30px;
    307      height: 30px;
    308      position: absolute;
    309      opacity: 0.9;
    310    }
    311  </style>
    312  <div id="a" style="background-color: orange;">
    313    <div id="aa" style="background-color: purple;"></div>
    314  </div>
    315  <div id="b" style="background-color: yellowgreen;">
    316    <div id="bb" style="top: -30px; background-color: turquoise"></div>
    317  </div>`,
    318  async function (browser, accDoc) {
    319    const a = findAccessibleChildByID(accDoc, "a");
    320    const aa = findAccessibleChildByID(accDoc, "aa");
    321    const dpr = await getContentDPR(browser);
    322    const [, , w, h] = Layout.getBounds(a, dpr);
    323    // test upper left of `a`
    324    await testChildAtPoint(dpr, 1, 1, a, aa, aa);
    325    // test upper right of `a`
    326    await testChildAtPoint(dpr, w - 1, 1, a, a, a);
    327    // test just outside upper left of `a`
    328    await testChildAtPoint(dpr, 1, -1, a, null, null);
    329    // test halfway down/left of `a`
    330    await testChildAtPoint(dpr, 1, Math.round(h / 2), a, a, a);
    331  },
    332  {
    333    chrome: true,
    334    topLevel: true,
    335    iframe: false,
    336    remoteIframe: false,
    337    // Ensure that all hittest elements are in view.
    338    iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
    339  }
    340 );
    341 
    342 /**
    343 * Verify that hit testing returns the proper accessible when one acc content
    344 * is partially hidden due to overflow:hidden;
    345 */
    346 addAccessibleTask(
    347  `
    348  <style>
    349    div div {
    350      overflow: hidden;
    351      font-family: monospace;
    352      width: 2ch;
    353    }
    354  </style>
    355  <div id="container" style="display: flex; flex-direction: row-reverse;">
    356    <div id="aNode">abcde</div><div id="fNode">fghij</div>
    357  </div>`,
    358  async function (browser, docAcc) {
    359    const container = findAccessibleChildByID(docAcc, "container");
    360    const aNode = findAccessibleChildByID(docAcc, "aNode");
    361    const fNode = findAccessibleChildByID(docAcc, "fNode");
    362    const dpr = await getContentDPR(browser);
    363    const [, , containerWidth] = Layout.getBounds(container, dpr);
    364    const [, , aNodeWidth] = Layout.getBounds(aNode, dpr);
    365 
    366    await testChildAtPoint(
    367      dpr,
    368      containerWidth - 1,
    369      1,
    370      container,
    371      aNode,
    372      aNode.firstChild
    373    );
    374    await testChildAtPoint(
    375      dpr,
    376      containerWidth - aNodeWidth - 1,
    377      1,
    378      container,
    379      fNode,
    380      fNode.firstChild
    381    );
    382  },
    383  { chrome: true, iframe: true, remoteIframe: true }
    384 );
    385 
    386 /**
    387 * Verify that hit testing is appropriately fuzzy when working with generics.
    388 * If we match on a generic which contains additional generics and a single text
    389 * leaf, we should return the text leaf as the deepest match instead of the
    390 * generic itself.
    391 */
    392 addAccessibleTask(
    393  `
    394  <a href="example.com" id="link">
    395    <span style="overflow:hidden;" id="generic"><span aria-hidden="true" id="visible">I am some visible text</span><span id="invisible" style="overflow:hidden; height: 1px; width: 1px; position:absolute; clip: rect(0 0 0 0); display:block;">I am some invisible text</span></span>
    396  </a>`,
    397  async function (browser, docAcc) {
    398    const link = findAccessibleChildByID(docAcc, "link");
    399    const generic = findAccessibleChildByID(docAcc, "generic");
    400    const invisible = findAccessibleChildByID(docAcc, "invisible");
    401    const dpr = await getContentDPR(browser);
    402 
    403    await testChildAtPoint(
    404      dpr,
    405      1,
    406      1,
    407      link,
    408      generic, // Direct Child
    409      invisible.firstChild // Deepest Child
    410    );
    411 
    412    await testOffsetAtPoint(
    413      findAccessibleChildByID(docAcc, "invisible", [Ci.nsIAccessibleText]),
    414      1,
    415      1,
    416      COORDTYPE_PARENT_RELATIVE,
    417      0
    418    );
    419  },
    420  { chrome: false, iframe: true, remoteIframe: true }
    421 );
    422 
    423 /**
    424 * Verify that hit testing is appropriately fuzzy when working with generics with siblings.
    425 * We should return the deepest text leaf as the deepest match instead of the generic itself.
    426 */
    427 addAccessibleTask(
    428  `
    429 <div id="generic"><span aria-hidden="true" id="visible">Mozilla</span><span id="invisible" style="display: block !important;border: 0 !important;clip: rect(0 0 0 0) !important;height: 1px !important;margin: -1px !important;overflow: hidden !important;padding: 0 !important;position: absolute !important;white-space: nowrap !important;width: 1px !important;">hello world<br><div id="extraContainer">Mozilla</div></span><br>I am some other text</div>`,
    430  async function (browser, docAcc) {
    431    const generic = findAccessibleChildByID(docAcc, "generic");
    432    const invisible = findAccessibleChildByID(docAcc, "invisible");
    433    const dpr = await getContentDPR(browser);
    434 
    435    await testChildAtPoint(
    436      dpr,
    437      1,
    438      1,
    439      generic,
    440      invisible, // Direct Child
    441      invisible.firstChild // Deepest Child
    442    );
    443  },
    444  { chrome: false, iframe: true, remoteIframe: true }
    445 );
    446 
    447 /**
    448 * Verify that hit testing correctly ignores
    449 * elements with pointer-events: none;
    450 */
    451 addAccessibleTask(
    452  `<div id="container" style="position:relative;"><button id="obscured">click me</button><div id="overlay" style="pointer-events:none; top:0; bottom:0; left:0; right:0; position: absolute;"></div></div><button id="clickable">I am clickable</button>`,
    453  async function (browser, docAcc) {
    454    const container = findAccessibleChildByID(docAcc, "container");
    455    const obscured = findAccessibleChildByID(docAcc, "obscured");
    456    const clickable = findAccessibleChildByID(docAcc, "clickable");
    457    const dpr = await getContentDPR(browser);
    458    let [targetX, targetY, targetW, targetH] = Layout.getBounds(obscured, dpr);
    459    const [x, y] = Layout.getBounds(docAcc, dpr);
    460    await testChildAtPoint(
    461      dpr,
    462      targetX - x + targetW / 2,
    463      targetY - y + targetH / 2,
    464      docAcc,
    465      container, // Direct Child
    466      obscured // Deepest Child
    467    );
    468 
    469    [targetX, targetY, targetW, targetH] = Layout.getBounds(clickable, dpr);
    470    await testChildAtPoint(
    471      dpr,
    472      targetX - x + targetW / 2,
    473      targetY - y + targetH / 2,
    474      docAcc,
    475      clickable, // Direct Child
    476      clickable // Deepest Child
    477    );
    478  },
    479  { chrome: false, iframe: true, remoteIframe: true }
    480 );
    481 
    482 /**
    483 * Test hit testing on elements which change to display: contents.
    484 */
    485 addAccessibleTask(
    486  `
    487 <style>
    488  p {
    489    font-family: monospace;
    490  }
    491 </style>
    492 <details id="detailsOpen" open>
    493  <summary>summary</summary>
    494  <p id="detailsOpenP">detailsOpenP</p>
    495 </details>
    496 <details id="details">
    497  <summary>summary</summary>
    498  <p id="detailsP">detailsP</p>
    499 </details>
    500 <div id="outer">
    501  <p>before</p>
    502  <div id="inner" role="group">
    503    <p id="innerP" hidden>innerP</p>
    504  </div>
    505 </div>
    506  `,
    507  async function testChangeDisplayContents(browser, docAcc) {
    508    const detailsOpen = findAccessibleChildByID(docAcc, "detailsOpen");
    509    const detailsOpenP = findAccessibleChildByID(docAcc, "detailsOpenP");
    510    // Between the details element and its <p> exists
    511    // a pseudoelement, ::details-content. Use this as
    512    // our expected target for direct-child hittesting.
    513    await hitTest(
    514      browser,
    515      detailsOpen,
    516      detailsOpenP.parent,
    517      detailsOpenP.firstChild
    518    );
    519 
    520    info("Opening details");
    521    let shown = waitForEvent(EVENT_SHOW, "detailsP");
    522    await invokeContentTask(browser, [], () => {
    523      content.document.getElementById("details").open = true;
    524    });
    525    const detailsP = (await shown).accessible;
    526    // There is a <slot> between details and detailsP which has display:
    527    // contents.
    528    await hitTest(browser, detailsP.parent, detailsP, detailsP.firstChild);
    529 
    530    info("Setting display: contents on inner, showing innerP");
    531    shown = waitForEvent(EVENT_SHOW, "innerP");
    532    await invokeContentTask(browser, [], () => {
    533      content.document.getElementById("inner").style.display = "contents";
    534      content.document.getElementById("innerP").hidden = false;
    535    });
    536    const innerP = (await shown).accessible;
    537    const inner = findAccessibleChildByID(docAcc, "inner");
    538    await hitTest(browser, inner, innerP, innerP.firstChild);
    539  }
    540 );