tor-browser

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

test_focusrings.xhtml (8137B)


      1 <?xml version="1.0"?>
      2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
      3 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
      4 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
      5 
      6 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
      7 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
      8 <script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
      9 
     10 <html:style xmlns:html="http://www.w3.org/1999/xhtml" type="text/css">
     11 * { outline: none; }
     12 #b3:focus-visible { outline: auto }
     13 #l1:focus-visible, #l3:focus-visible, #b1:focus-visible { outline: 2px solid red; }
     14 #l2:focus, #b2:focus { outline: 2px solid red; }
     15 </html:style>
     16 
     17 <script>
     18 <![CDATA[
     19 
     20 SimpleTest.waitForExplicitFinish();
     21 
     22 const kIsMac = navigator.platform.includes("Mac");
     23 
     24 function snapShot(element) {
     25  var rect = element.getBoundingClientRect();
     26  adjustedRect = { left: rect.left - 6, top: rect.top - 6,
     27                   width: rect.width + 12, height: rect.height + 12 }
     28  return SpecialPowers.snapshotRect(window, adjustedRect, "transparent");
     29 }
     30 
     31 async function initTest() {
     32  if (kIsMac) {
     33    // FIXME: Historically this pref was only respected on mac,
     34    // and the test uses that assumption.
     35    //
     36    // Ideally it should be refactored to test with the different
     37    // values of the pref, independently of the platform.
     38    await SpecialPowers.pushPrefEnv({
     39      "set": [
     40        ['accessibility.mouse_focuses_formcontrol', 0],
     41      ]
     42    });
     43  }
     44 
     45  runTest();
     46 }
     47 
     48 function hasOutline(element) {
     49  let cs = getComputedStyle(element);
     50  return cs.outlineWidth != "0px" && cs.outlineStyle != "none";
     51 }
     52 
     53 function checkRing(element, width, message) {
     54  const expectOutline = width != "0px";
     55  is(hasOutline(element), expectOutline, message);
     56  if (expectOutline) {
     57    is(getComputedStyle(element).outlineWidth, width, message);
     58  }
     59 }
     60 
     61 function runTest()
     62 {
     63  // Make sure our snapshots don't depend on mouse position.
     64  synthesizeMouse(document.documentElement, 0, 0, { type: "mousemove" });
     65 
     66  var isWinOrLinux = navigator.platform.includes("Win") || navigator.platform.includes("Linux");
     67 
     68  function checkFocus(element, visible, testid)
     69  {
     70    is(hasOutline(element), visible, testid);
     71  }
     72 
     73  // make sure that a focus ring appears on the focused button
     74  if (kIsMac) {
     75    var focusedButton = $("b3");
     76    const retBefore = compareSnapshots(snapShot(focusedButton), snapShot($("b2")), true);
     77    ok(retBefore[0], `unfocused shows no ring,\nRESULT:\n${retBefore[1]}, \nREFERENCE:\n${retBefore[2]}`);
     78    focusedButton.focus();
     79    const retAfter = compareSnapshots(snapShot(focusedButton), snapShot($("b2")), false);
     80    ok(retAfter[0], `focus shows ring,\nRESULT:\n${retAfter[1]}, \nREFERENCE:\n${retAfter[2]}`);
     81  }
     82 
     83  checkFocus($("l1"), false, "initial appearance");
     84 
     85  // we can't really test the situation on Windows where a dialog doesn't show
     86  // focus rings until a key is pressed, as the default state depends on what
     87  // kind of real user input, mouse or key, was last entered. But we can handle
     88  // the test regardless of which user input last occurred.
     89  $("l1").focus();
     90  var expectedVisible = !isWinOrLinux || hasOutline($("l1"));
     91  testHTMLElements(htmlElements, isWinOrLinux && !expectedVisible);
     92 
     93  $("l1").focus();
     94  checkFocus($("l1"), expectedVisible, "appearance on list after focus() with :moz-focusring");
     95  $("l2").focus();
     96 
     97  checkFocus($("l2"), true, "appearance on list after focus() with :focus");
     98 
     99  ok(!hasOutline($("l1")), "appearance on previous list after focus() with :focus");
    100 
    101  synthesizeMouse($("l1"), 4, 4, { });
    102  checkFocus($("l1"), false, "appearance on list after mouse focus with :moz-focusring");
    103  synthesizeMouse($("l2"), 4, 4, { });
    104  checkFocus($("l2"), true, "appearance on list after mouse focus with :focus");
    105 
    106  synthesizeMouse($("b1"), 4, 4, { });
    107  checkFocus($("b1"), false, "appearance on button after mouse focus with :moz-focusring");
    108 
    109  synthesizeMouse($("b2"), 4, 4, { });
    110  checkFocus($("b2"), !kIsMac, "appearance on button after mouse focus with :focus");
    111 
    112  // after a key is pressed, the focus ring will always be visible
    113  $("l2").focus();
    114  synthesizeKey("KEY_Tab");
    115  checkFocus($("l3"), true, "appearance on list after tab focus");
    116 
    117  if (kIsMac) {
    118    SpecialPowers.pushPrefEnv({"set": [['accessibility.mouse_focuses_formcontrol', 1]]}, testMacFocusesFormControl);
    119  }
    120  else {
    121    SimpleTest.finish();
    122  }
    123 }
    124 
    125 async function testMacFocusesFormControl()
    126 {
    127  await SimpleTest.promiseFocus(window);
    128  testHTMLElements(htmlElementsMacPrefSet, false);
    129  SimpleTest.finish();
    130 }
    131 
    132 var htmlElements = [
    133  "<button id='elem'>Button</button>",
    134  "<input id='elem' type='button'>",
    135  "<input id='elem' type='checkbox'>",
    136  "<input id='elem' class='canfocus'>",
    137  "<input id='elem' type='password' class='canfocus'>",
    138  "<textarea id='elem' class='canfocus'></textarea>",
    139  "<select id='elem' class='canfocus'><option>One</select>",
    140  "<select id='elem' rows='5' class='canfocus'><option>One</select>",
    141  "<div id='elem' tabindex='0' class='canfocus' style='width: 10px; height: 10px;'></div>",
    142  "<a href='about:blank' class='canfocus' onclick='return false;'>about:blank</a>",
    143 ];
    144 
    145 var htmlElementsMacPrefSet = [
    146  "<button id='elem' class='canfocus'>Button</button>",
    147  "<input id='elem' class='canfocus'>",
    148  "<input id='elem' type='button' class='canfocus'>",
    149  "<input id='elem' type='checkbox' class='canfocus'>",
    150 ];
    151 
    152 function createElement(str) {
    153  let doc = new DOMParser().parseFromSafeString(`<html><body>${str}</body></html>`, "text/html");
    154  return doc.body.firstChild;
    155 }
    156 
    157 function testHTMLElements(list, expectedNoRingsOnWin) {
    158  var childwin = frames[0];
    159  var childdoc = childwin.document;
    160  var container = childdoc.getElementById("container");
    161  for (var e = 0; e < list.length; e++) {
    162    // Using innerHTML would be sanitized, so use the DOM parser instead to
    163    // create the elements.
    164    var elem = childdoc.adoptNode(createElement(list[e]));
    165    container.appendChild(elem);
    166 
    167    var shouldFocus = !kIsMac || (elem.className == "canfocus");
    168    var ringSize = (shouldFocus ? (expectedNoRingsOnWin ? 2 : 1) : 0) + "px";
    169 
    170    var expectedMatchWithMouse = shouldFocus && !expectedNoRingsOnWin;
    171    var mouseRingSize = ringSize;
    172    if (shouldFocus) {
    173      var textControl = (function() {
    174        if (elem.localName == "textarea")
    175          return true;
    176        if (elem.localName == "input")
    177          return elem.type == "text" || elem.type == "password";
    178        return false;
    179      }());
    180      expectedMatchWithMouse = textControl;
    181      mouseRingSize = textControl ? "1px" : "2px";
    182    }
    183 
    184    if (elem.localName == "a") {
    185      mouseRingSize = ringSize = "0px";
    186      expectedMatchWithMouse = expectedMatchWithMouse && !kIsMac;
    187    }
    188 
    189    synthesizeMouse(elem, 8, 8, { }, childwin);
    190    is(childdoc.activeElement, shouldFocus ? elem : childdoc.body, "mouse click on " + list[e]);
    191    is(elem.matches(":focus-visible"), expectedMatchWithMouse, "mouse click on " + list[e] + " selector");
    192    checkRing(elem, mouseRingSize, "mouse click on " + list[e] + " ring");
    193 
    194    if (childdoc.activeElement)
    195      childdoc.activeElement.blur();
    196 
    197    ringSize = mouseRingSize;
    198    if (kIsMac && !shouldFocus && elem.localName != "a") {
    199      ringSize = "1px";
    200    }
    201 
    202    elem.focus();
    203    is(childdoc.activeElement, elem, "focus() on " + list[e]);
    204    checkRing(elem, ringSize, "focus() on " + list[e] + " ring");
    205 
    206    childdoc.activeElement.blur();
    207 
    208    // Clear out the container for the next test.
    209    while (container.firstChild) {
    210      container.firstChild.remove();
    211    }
    212  }
    213 }
    214 
    215 SimpleTest.waitForFocus(initTest);
    216 
    217 ]]>
    218 </script>
    219 
    220 <richlistbox id="l1" class="plain" height="20"/>
    221 <richlistbox id="l2" class="plain" height="20"/>
    222 <richlistbox id="l3" class="plain" height="20"/>
    223 <button id="b1" label="Button"/>
    224 <button id="b2" label="Button"/>
    225 <button id="b3" label="Button"/>
    226 
    227 <iframe id="child" src="file_focusrings.html"/>
    228 
    229 <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
    230 
    231 </window>