summaryrefslogtreecommitdiffstats
path: root/dom/tests/mochitest/general/test_focusrings.xhtml
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/tests/mochitest/general/test_focusrings.xhtml217
1 files changed, 217 insertions, 0 deletions
diff --git a/dom/tests/mochitest/general/test_focusrings.xhtml b/dom/tests/mochitest/general/test_focusrings.xhtml
new file mode 100644
index 0000000000..38882ad99c
--- /dev/null
+++ b/dom/tests/mochitest/general/test_focusrings.xhtml
@@ -0,0 +1,217 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+<script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+
+<html:style xmlns:html="http://www.w3.org/1999/xhtml" type="text/css">
+* { outline: none; }
+#b3:focus-visible { outline: auto }
+#l1:focus-visible, #l3:focus-visible, #b1:focus-visible { outline: 2px solid red; }
+#l2:focus, #b2:focus { outline: 2px solid red; }
+</html:style>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+const kIsMac = navigator.platform.includes("Mac");
+
+function snapShot(element) {
+ var rect = element.getBoundingClientRect();
+ adjustedRect = { left: rect.left - 6, top: rect.top - 6,
+ width: rect.width + 12, height: rect.height + 12 }
+ return SpecialPowers.snapshotRect(window, adjustedRect, "transparent");
+}
+
+async function initTest() {
+ if (kIsMac) {
+ // FIXME: Historically this pref was only respected on mac,
+ // and the test uses that assumption.
+ //
+ // Ideally it should be refactored to test with the different
+ // values of the pref, independently of the platform.
+ await SpecialPowers.pushPrefEnv({
+ "set": [
+ ['accessibility.mouse_focuses_formcontrol', 0],
+ ]
+ });
+ }
+
+ runTest();
+}
+
+function runTest()
+{
+ var isWinOrLinux = navigator.platform.includes("Win") || navigator.platform.includes("Linux");
+
+ function checkFocus(element, visible, testid)
+ {
+ var outline = getComputedStyle(element, "").outlineWidth;
+ is(outline, visible ? "2px" : "0px", testid);
+ }
+
+ // make sure that a focus ring appears on the focused button
+ if (kIsMac) {
+ var focusedButton = $("b3");
+ const retBefore = compareSnapshots(snapShot(focusedButton), snapShot($("b2")), true);
+ ok(retBefore[0], `unfocused shows no ring,\nRESULT:\n${retBefore[1]}, \nREFERENCE:\n${retBefore[2]}`);
+ focusedButton.focus();
+ const retAfter = compareSnapshots(snapShot(focusedButton), snapShot($("b2")), false);
+ ok(retAfter[0], `focus shows ring,\nRESULT:\n${retAfter[1]}, \nREFERENCE:\n${retAfter[2]}`);
+ }
+
+ checkFocus($("l1"), false, "initial appearance");
+
+ // we can't really test the situation on Windows where a dialog doesn't show
+ // focus rings until a key is pressed, as the default state depends on what
+ // kind of real user input, mouse or key, was last entered. But we can handle
+ // the test regardless of which user input last occurred.
+ $("l1").focus();
+ var expectedVisible = (!isWinOrLinux || getComputedStyle($("l1"), "").outlineWidth == "2px");
+ testHTMLElements(htmlElements, isWinOrLinux && !expectedVisible);
+
+ $("l1").focus();
+ checkFocus($("l1"), expectedVisible, "appearance on list after focus() with :moz-focusring");
+ $("l2").focus();
+
+ checkFocus($("l2"), true, "appearance on list after focus() with :focus");
+
+ is(getComputedStyle($("l1"), "").outlineWidth, "0px", "appearance on previous list after focus() with :focus");
+
+ synthesizeMouse($("l1"), 4, 4, { });
+ checkFocus($("l1"), false, "appearance on list after mouse focus with :moz-focusring");
+ synthesizeMouse($("l2"), 4, 4, { });
+ checkFocus($("l2"), true, "appearance on list after mouse focus with :focus");
+
+ synthesizeMouse($("b1"), 4, 4, { });
+ checkFocus($("b1"), false, "appearance on button after mouse focus with :moz-focusring");
+
+ synthesizeMouse($("b2"), 4, 4, { });
+ checkFocus($("b2"), !kIsMac, "appearance on button after mouse focus with :focus");
+
+ // after a key is pressed, the focus ring will always be visible
+ $("l2").focus();
+ synthesizeKey("KEY_Tab");
+ checkFocus($("l3"), true, "appearance on list after tab focus");
+
+ if (kIsMac) {
+ SpecialPowers.pushPrefEnv({"set": [['accessibility.mouse_focuses_formcontrol', 1]]}, testMacFocusesFormControl);
+ }
+ else {
+ SimpleTest.finish();
+ }
+}
+
+async function testMacFocusesFormControl()
+{
+ await SimpleTest.promiseFocus(window);
+ testHTMLElements(htmlElementsMacPrefSet, false);
+ SimpleTest.finish();
+}
+
+var htmlElements = [
+ "<button id='elem'>Button</button>",
+ "<input id='elem' type='button'>",
+ "<input id='elem' type='checkbox'>",
+ "<input id='elem' class='canfocus'>",
+ "<input id='elem' type='password' class='canfocus'>",
+ "<textarea id='elem' class='canfocus'></textarea>",
+ "<select id='elem' class='canfocus'><option>One</select>",
+ "<select id='elem' rows='5' class='canfocus'><option>One</select>",
+ "<div id='elem' tabindex='0' class='canfocus' style='width: 10px; height: 10px;'></div>",
+ "<a href='about:blank' class='canfocus' onclick='return false;'>about:blank</a>",
+];
+
+var htmlElementsMacPrefSet = [
+ "<button id='elem' class='canfocus'>Button</button>",
+ "<input id='elem' class='canfocus'>",
+ "<input id='elem' type='button' class='canfocus'>",
+ "<input id='elem' type='checkbox' class='canfocus'>",
+];
+
+function createElement(str) {
+ let doc = new DOMParser().parseFromSafeString(`<html><body>${str}</body></html>`, "text/html");
+ return doc.body.firstChild;
+}
+
+function testHTMLElements(list, expectedNoRingsOnWin) {
+ var childwin = frames[0];
+ var childdoc = childwin.document;
+ var container = childdoc.getElementById("container");
+ for (var e = 0; e < list.length; e++) {
+ // Using innerHTML would be sanitized, so use the DOM parser instead to
+ // create the elements.
+ var elem = childdoc.adoptNode(createElement(list[e]));
+ container.appendChild(elem);
+
+ var shouldFocus = !kIsMac || (elem.className == "canfocus");
+ var ringSize = (shouldFocus ? (expectedNoRingsOnWin ? 2 : 1) : 0) + "px";
+
+ var expectedMatchWithMouse = shouldFocus && !expectedNoRingsOnWin;
+ var mouseRingSize = ringSize;
+ if (shouldFocus) {
+ var textControl = (function() {
+ if (elem.localName == "textarea")
+ return true;
+ if (elem.localName == "input")
+ return elem.type == "text" || elem.type == "password";
+ return false;
+ }());
+ expectedMatchWithMouse = textControl;
+ mouseRingSize = textControl ? "1px" : "2px";
+ }
+
+ if (elem.localName == "a") {
+ mouseRingSize = ringSize = "0px";
+ expectedMatchWithMouse = expectedMatchWithMouse && !kIsMac;
+ }
+
+ synthesizeMouse(elem, 8, 8, { }, childwin);
+ is(childdoc.activeElement, shouldFocus ? elem : childdoc.body, "mouse click on " + list[e]);
+ is(childwin.getComputedStyle(elem).outlineWidth, mouseRingSize, "mouse click on " + list[e] + " ring");
+ is(elem.matches(":-moz-focusring"), expectedMatchWithMouse, "mouse click on " + list[e] + " selector");
+
+ if (childdoc.activeElement)
+ childdoc.activeElement.blur();
+
+ ringSize = mouseRingSize;
+ if (kIsMac && !shouldFocus && elem.localName != "a") {
+ ringSize = "1px";
+ }
+
+ elem.focus();
+ is(childdoc.activeElement, elem, "focus() on " + list[e]);
+ is(childwin.getComputedStyle(elem).outlineWidth, ringSize,
+ "focus() on " + list[e] + " ring");
+
+ childdoc.activeElement.blur();
+
+ // Clear out the container for the next test.
+ while (container.firstChild) {
+ container.firstChild.remove();
+ }
+ }
+}
+
+SimpleTest.waitForFocus(initTest);
+
+]]>
+</script>
+
+<richlistbox id="l1" class="plain" height="20"/>
+<richlistbox id="l2" class="plain" height="20"/>
+<richlistbox id="l3" class="plain" height="20"/>
+<button id="b1" label="Button"/>
+<button id="b2" label="Button"/>
+<button id="b3" label="Button"/>
+
+<iframe id="child" src="file_focusrings.html"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+</window>