summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser/hittest/browser_test_general.js
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/tests/browser/hittest/browser_test_general.js')
-rw-r--r--accessible/tests/browser/hittest/browser_test_general.js425
1 files changed, 425 insertions, 0 deletions
diff --git a/accessible/tests/browser/hittest/browser_test_general.js b/accessible/tests/browser/hittest/browser_test_general.js
new file mode 100644
index 0000000000..ca3a879c18
--- /dev/null
+++ b/accessible/tests/browser/hittest/browser_test_general.js
@@ -0,0 +1,425 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+async function runTests(browser, accDoc) {
+ const dpr = await getContentDPR(browser);
+
+ await testChildAtPoint(
+ dpr,
+ 3,
+ 3,
+ findAccessibleChildByID(accDoc, "list"),
+ findAccessibleChildByID(accDoc, "listitem"),
+ findAccessibleChildByID(accDoc, "inner").firstChild
+ );
+ todo(
+ false,
+ "Bug 746974 - children must match on all platforms. On Windows, " +
+ "ChildAtPoint with eDeepestChild is incorrectly ignoring MustPrune " +
+ "for the graphic."
+ );
+
+ const txt = findAccessibleChildByID(accDoc, "txt");
+ await testChildAtPoint(dpr, 1, 1, txt, txt, txt);
+
+ info(
+ "::MustPrune case, point is outside of textbox accessible but is in document."
+ );
+ await testChildAtPoint(dpr, -1, -1, txt, null, null);
+
+ info("::MustPrune case, point is outside of root accessible.");
+ await testChildAtPoint(dpr, -10000, -10000, txt, null, null);
+
+ info("Not specific case, point is inside of btn accessible.");
+ const btn = findAccessibleChildByID(accDoc, "btn");
+ await testChildAtPoint(dpr, 1, 1, btn, btn, btn);
+
+ info("Not specific case, point is outside of btn accessible.");
+ await testChildAtPoint(dpr, -1, -1, btn, null, null);
+
+ info(
+ "Out of flow accessible testing, do not return out of flow accessible " +
+ "because it's not a child of the accessible even though visually it is."
+ );
+ await invokeContentTask(browser, [], () => {
+ const { CommonUtils } = ChromeUtils.importESModule(
+ "chrome://mochitests/content/browser/accessible/tests/browser/Common.sys.mjs"
+ );
+ const doc = content.document;
+ const rectArea = CommonUtils.getNode("area", doc).getBoundingClientRect();
+ const outOfFlow = CommonUtils.getNode("outofflow", doc);
+ outOfFlow.style.left = rectArea.left + "px";
+ outOfFlow.style.top = rectArea.top + "px";
+ });
+
+ const area = findAccessibleChildByID(accDoc, "area");
+ await testChildAtPoint(dpr, 1, 1, area, area, area);
+
+ info("Test image maps. Their children are not in the layout tree.");
+ await waitForImageMap(browser, accDoc);
+ const imgmap = findAccessibleChildByID(accDoc, "imgmap");
+ ok(imgmap, "Image map exists");
+ const theLetterA = imgmap.firstChild;
+ await hitTest(browser, imgmap, theLetterA, theLetterA);
+ await hitTest(
+ browser,
+ findAccessibleChildByID(accDoc, "container"),
+ imgmap,
+ theLetterA
+ );
+
+ info("hit testing for element contained by zero-width element");
+ const container2Input = findAccessibleChildByID(accDoc, "container2_input");
+ await hitTest(
+ browser,
+ findAccessibleChildByID(accDoc, "container2"),
+ container2Input,
+ container2Input
+ );
+
+ info("hittesting table, row, cells -- rows are not in the layout tree");
+ const table = findAccessibleChildByID(accDoc, "table");
+ const row = findAccessibleChildByID(accDoc, "row");
+ const cell1 = findAccessibleChildByID(accDoc, "cell1");
+
+ await hitTest(browser, table, row, cell1);
+
+ info("Testing that an inaccessible child doesn't break hit testing");
+ const containerWithInaccessibleChild = findAccessibleChildByID(
+ accDoc,
+ "containerWithInaccessibleChild"
+ );
+ const containerWithInaccessibleChildP2 = findAccessibleChildByID(
+ accDoc,
+ "containerWithInaccessibleChild_p2"
+ );
+ await hitTest(
+ browser,
+ containerWithInaccessibleChild,
+ containerWithInaccessibleChildP2,
+ containerWithInaccessibleChildP2.firstChild
+ );
+
+ info("Testing wrapped text");
+ const wrappedTextLinkFirstP = findAccessibleChildByID(
+ accDoc,
+ "wrappedTextLinkFirstP"
+ );
+ const wrappedTextLinkFirstA = findAccessibleChildByID(
+ accDoc,
+ "wrappedTextLinkFirstA"
+ );
+ await hitTest(
+ browser,
+ wrappedTextLinkFirstP,
+ wrappedTextLinkFirstA,
+ wrappedTextLinkFirstA.firstChild
+ );
+ const wrappedTextLeafFirstP = findAccessibleChildByID(
+ accDoc,
+ "wrappedTextLeafFirstP"
+ );
+ const wrappedTextLeafFirstMark = findAccessibleChildByID(
+ accDoc,
+ "wrappedTextLeafFirstMark"
+ );
+ await hitTest(
+ browser,
+ wrappedTextLeafFirstP,
+ wrappedTextLeafFirstMark,
+ wrappedTextLeafFirstMark.firstChild
+ );
+
+ info("Testing image");
+ const imageP = findAccessibleChildByID(accDoc, "imageP");
+ const image = findAccessibleChildByID(accDoc, "image");
+ await hitTest(browser, imageP, image, image);
+
+ info("Testing image map with 0-sized area");
+ const mapWith0AreaP = findAccessibleChildByID(accDoc, "mapWith0AreaP");
+ const mapWith0Area = findAccessibleChildByID(accDoc, "mapWith0Area");
+ await hitTest(browser, mapWith0AreaP, mapWith0Area, mapWith0Area);
+}
+
+addAccessibleTask(
+ `
+ <div role="list" id="list">
+ <div role="listitem" id="listitem"><span title="foo" id="inner">inner</span>item</div>
+ </div>
+
+ <span role="button">button1</span><span role="button" id="btn">button2</span>
+
+ <span role="textbox">textbox1</span><span role="textbox" id="txt">textbox2</span>
+
+ <div id="outofflow" style="width: 10px; height: 10px; position: absolute; left: 0px; top: 0px; background-color: yellow;">
+ </div>
+ <div id="area" style="width: 100px; height: 100px; background-color: blue;"></div>
+
+ <map name="atoz_map">
+ <area id="thelettera" href="http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
+ coords="0,0,15,15" alt="thelettera" shape="rect"/>
+ </map>
+
+ <div id="container">
+ <img id="imgmap" width="447" height="15" usemap="#atoz_map" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif"/>
+ </div>
+
+ <div id="container2" style="width: 0px">
+ <input id="container2_input">
+ </div>
+
+ <table id="table" border>
+ <tr id="row">
+ <td id="cell1">hello</td>
+ <td id="cell2">world</td>
+ </tr>
+ </table>
+
+ <div id="containerWithInaccessibleChild">
+ <p>hi</p>
+ <p aria-hidden="true">hi</p>
+ <p id="containerWithInaccessibleChild_p2">bye</p>
+ </div>
+
+ <p id="wrappedTextLinkFirstP" style="width: 3ch; font-family: monospace;">
+ <a id="wrappedTextLinkFirstA" href="https://example.com/">a</a>b cd
+ </p>
+
+ <p id="wrappedTextLeafFirstP" style="width: 3ch; font-family: monospace;">
+ <mark id="wrappedTextLeafFirstMark">a</mark><a href="https://example.com/">b cd</a>
+ </p>
+
+ <p id="imageP">
+ <img id="image" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif">
+ </p>
+
+ <map id="0Area">
+ <area shape="rect">
+ </map>
+ <p id="mapWith0AreaP">
+ <img id="mapWith0Area" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif" usemap="#0Area">
+ </p>
+ `,
+ runTests,
+ {
+ iframe: true,
+ remoteIframe: true,
+ // Ensure that all hittest elements are in view.
+ iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
+ }
+);
+
+addAccessibleTask(
+ `
+ <div id="container">
+ <h1 id="a">A</h1><h1 id="b">B</h1>
+ </div>
+ `,
+ async function (browser, accDoc) {
+ const a = findAccessibleChildByID(accDoc, "a");
+ const b = findAccessibleChildByID(accDoc, "b");
+ const dpr = await getContentDPR(browser);
+ // eslint-disable-next-line no-unused-vars
+ const [x, y, w, h] = Layout.getBounds(a, dpr);
+ // The point passed below will be made relative to `b`, but
+ // we'd like to test a point within `a`. Pass `a`s negative
+ // width for an x offset. Pass zero as a y offset,
+ // assuming the headings are on the same line.
+ await testChildAtPoint(dpr, -w, 0, b, null, null);
+ },
+ {
+ iframe: true,
+ remoteIframe: true,
+ // Ensure that all hittest elements are in view.
+ iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
+ }
+);
+
+addAccessibleTask(
+ `
+ <style>
+ div {
+ width: 50px;
+ height: 50px;
+ position: relative;
+ }
+
+ div > div {
+ width: 30px;
+ height: 30px;
+ position: absolute;
+ opacity: 0.9;
+ }
+ </style>
+ <div id="a" style="background-color: orange;">
+ <div id="aa" style="background-color: purple;"></div>
+ </div>
+ <div id="b" style="background-color: yellowgreen;">
+ <div id="bb" style="top: -30px; background-color: turquoise"></div>
+ </div>`,
+ async function (browser, accDoc) {
+ const a = findAccessibleChildByID(accDoc, "a");
+ const aa = findAccessibleChildByID(accDoc, "aa");
+ const dpr = await getContentDPR(browser);
+ const [, , w, h] = Layout.getBounds(a, dpr);
+ // test upper left of `a`
+ await testChildAtPoint(dpr, 1, 1, a, aa, aa);
+ // test upper right of `a`
+ await testChildAtPoint(dpr, w - 1, 1, a, a, a);
+ // test just outside upper left of `a`
+ await testChildAtPoint(dpr, 1, -1, a, null, null);
+ // test halfway down/left of `a`
+ await testChildAtPoint(dpr, 1, Math.round(h / 2), a, a, a);
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: false,
+ remoteIframe: false,
+ // Ensure that all hittest elements are in view.
+ iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
+ }
+);
+
+/**
+ * Verify that hit testing returns the proper accessible when one acc content
+ * is partially hidden due to overflow:hidden;
+ */
+addAccessibleTask(
+ `
+ <style>
+ div div {
+ overflow: hidden;
+ font-family: monospace;
+ width: 2ch;
+ }
+ </style>
+ <div id="container" style="display: flex; flex-direction: row-reverse;">
+ <div id="aNode">abcde</div><div id="fNode">fghij</div>
+ </div>`,
+ async function (browser, docAcc) {
+ const container = findAccessibleChildByID(docAcc, "container");
+ const aNode = findAccessibleChildByID(docAcc, "aNode");
+ const fNode = findAccessibleChildByID(docAcc, "fNode");
+ const dpr = await getContentDPR(browser);
+ const [, , containerWidth] = Layout.getBounds(container, dpr);
+ const [, , aNodeWidth] = Layout.getBounds(aNode, dpr);
+
+ await testChildAtPoint(
+ dpr,
+ containerWidth - 1,
+ 1,
+ container,
+ aNode,
+ aNode.firstChild
+ );
+ await testChildAtPoint(
+ dpr,
+ containerWidth - aNodeWidth - 1,
+ 1,
+ container,
+ fNode,
+ fNode.firstChild
+ );
+ },
+ { chrome: true, iframe: true, remoteIframe: true }
+);
+
+/**
+ * Verify that hit testing is appropriately fuzzy when working with generics.
+ * If we match on a generic which contains additional generics and a single text
+ * leaf, we should return the text leaf as the deepest match instead of the
+ * generic itself.
+ */
+addAccessibleTask(
+ `
+ <a href="example.com" id="link">
+ <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>
+ </a>`,
+ async function (browser, docAcc) {
+ const link = findAccessibleChildByID(docAcc, "link");
+ const generic = findAccessibleChildByID(docAcc, "generic");
+ const invisible = findAccessibleChildByID(docAcc, "invisible");
+ const dpr = await getContentDPR(browser);
+
+ await testChildAtPoint(
+ dpr,
+ 1,
+ 1,
+ link,
+ generic, // Direct Child
+ invisible.firstChild // Deepest Child
+ );
+
+ await testOffsetAtPoint(
+ findAccessibleChildByID(docAcc, "invisible", [Ci.nsIAccessibleText]),
+ 1,
+ 1,
+ COORDTYPE_PARENT_RELATIVE,
+ 0
+ );
+ },
+ { chrome: false, iframe: true, remoteIframe: true }
+);
+
+/**
+ * Verify that hit testing is appropriately fuzzy when working with generics with siblings.
+ * We should return the deepest text leaf as the deepest match instead of the generic itself.
+ */
+addAccessibleTask(
+ `
+<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>`,
+ async function (browser, docAcc) {
+ const generic = findAccessibleChildByID(docAcc, "generic");
+ const invisible = findAccessibleChildByID(docAcc, "invisible");
+ const dpr = await getContentDPR(browser);
+
+ await testChildAtPoint(
+ dpr,
+ 1,
+ 1,
+ generic,
+ invisible, // Direct Child
+ invisible.firstChild // Deepest Child
+ );
+ },
+ { chrome: false, iframe: true, remoteIframe: true }
+);
+
+/**
+ * Verify that hit testing correctly ignores
+ * elements with pointer-events: none;
+ */
+addAccessibleTask(
+ `<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>`,
+ async function (browser, docAcc) {
+ const container = findAccessibleChildByID(docAcc, "container");
+ const obscured = findAccessibleChildByID(docAcc, "obscured");
+ const clickable = findAccessibleChildByID(docAcc, "clickable");
+ const dpr = await getContentDPR(browser);
+ let [targetX, targetY, targetW, targetH] = Layout.getBounds(obscured, dpr);
+ const [x, y] = Layout.getBounds(docAcc, dpr);
+ await testChildAtPoint(
+ dpr,
+ targetX - x + targetW / 2,
+ targetY - y + targetH / 2,
+ docAcc,
+ container, // Direct Child
+ obscured // Deepest Child
+ );
+
+ [targetX, targetY, targetW, targetH] = Layout.getBounds(clickable, dpr);
+ await testChildAtPoint(
+ dpr,
+ targetX - x + targetW / 2,
+ targetY - y + targetH / 2,
+ docAcc,
+ clickable, // Direct Child
+ clickable // Deepest Child
+ );
+ },
+ { chrome: false, iframe: true, remoteIframe: true }
+);