tor-browser

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

browser_webconsole_keyboard_accessibility.js (7897B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Check that basic keyboard shortcuts work in the web console.
      5 
      6 "use strict";
      7 
      8 const HTML_FILENAME = `test.html`;
      9 const HTML_CONTENT = `<!DOCTYPE html><p>Test keyboard accessibility</p>
     10  <script>
     11    for (let i = 1; i <= 100; i++) {
     12      console.log("console message " + i);
     13    }
     14    function logTrace() {
     15      const sub = () => console.trace("console trace message");
     16      sub();
     17    }
     18    logTrace();
     19  </script>
     20  `;
     21 
     22 const TRACE_FRAME_LINE_REGEX = /test\.html:\d+:?\d*/;
     23 
     24 const httpServer = createTestHTTPServer();
     25 httpServer.registerContentType("html", "text/html");
     26 httpServer.registerPathHandler(
     27  "/" + HTML_FILENAME,
     28  function (request, response) {
     29    response.setStatusLine(request.httpVersion, 200, "OK");
     30    response.write(HTML_CONTENT);
     31  }
     32 );
     33 
     34 const port = httpServer.identity.primaryPort;
     35 const TEST_URI = `http://localhost:${port}/${HTML_FILENAME}`;
     36 
     37 add_task(async function () {
     38  // Force tabfocus for all elements on OSX.
     39  SpecialPowers.pushPrefEnv({ set: [["accessibility.tabfocus", 7]] });
     40 
     41  const hud = await openNewTabAndConsole(TEST_URI);
     42 
     43  info("Web Console opened");
     44  const outputScroller = hud.ui.outputScroller;
     45  const traceMsgNode = await waitFor(
     46    () => findConsoleAPIMessage(hud, "console trace message"),
     47    "waiting for all the messages to be displayed",
     48    100,
     49    1000
     50  );
     51 
     52  // wait for all the stacktrace frames to be rendered.
     53  await waitFor(() =>
     54    traceMsgNode.querySelector(".message-body-wrapper > .stacktrace .frames")
     55  );
     56 
     57  let currentPosition = outputScroller.scrollTop;
     58  const bottom = currentPosition;
     59  hud.jsterm.focus();
     60 
     61  info("Check Page up keyboard shortcut");
     62  EventUtils.synthesizeKey("KEY_PageUp");
     63  isnot(
     64    outputScroller.scrollTop,
     65    currentPosition,
     66    "scroll position changed after page up"
     67  );
     68 
     69  info("Check Page down keyboard shortcut");
     70  currentPosition = outputScroller.scrollTop;
     71  EventUtils.synthesizeKey("KEY_PageDown");
     72  Assert.greater(
     73    outputScroller.scrollTop,
     74    currentPosition,
     75    "scroll position now at bottom"
     76  );
     77 
     78  info("Check Home keyboard shortcut");
     79  EventUtils.synthesizeKey("KEY_Home");
     80  is(outputScroller.scrollTop, 0, "scroll position now at top");
     81 
     82  info("Check End keyboard shortcut");
     83  EventUtils.synthesizeKey("KEY_End");
     84  const scrollTop = outputScroller.scrollTop;
     85  ok(
     86    scrollTop > 0 && Math.abs(scrollTop - bottom) <= 5,
     87    "scroll position now at bottom"
     88  );
     89 
     90  info("Hit Shift-Tab to focus switch to editor mode button");
     91  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
     92  ok(
     93    outputScroller.ownerDocument.activeElement.classList.contains(
     94      "webconsole-input-openEditorButton"
     95    ),
     96    "switch to editor mode button is focused"
     97  );
     98 
     99  info("Check stacktrace frames can be focused");
    100  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
    101  EventUtils.synthesizeKey("KEY_ArrowUp");
    102  ok(
    103    outputScroller.ownerDocument.activeElement.closest(".message.trace"),
    104    "The active element is in the trace message"
    105  );
    106  is(
    107    TRACE_FRAME_LINE_REGEX.exec(
    108      outputScroller.ownerDocument.activeElement.innerText
    109    )?.[0],
    110    "test.html:10",
    111    `last frame of the stacktrace is focused ${outputScroller.ownerDocument.activeElement.innerText}`
    112  );
    113 
    114  is(
    115    outputScroller.ownerDocument.activeElement.getAttribute("class"),
    116    "frame",
    117    "active element has expected class"
    118  );
    119 
    120  info("Hit Up Arrow to navigate to second frame of the stacktrace");
    121  EventUtils.synthesizeKey("KEY_ArrowUp");
    122  ok(
    123    outputScroller.ownerDocument.activeElement.closest(".message.trace"),
    124    "The active element is in the trace message"
    125  );
    126  is(
    127    TRACE_FRAME_LINE_REGEX.exec(
    128      outputScroller.ownerDocument.activeElement.innerText
    129    )?.[0],
    130    "test.html:8",
    131    "second frame of the stacktrace is focused"
    132  );
    133  is(
    134    outputScroller.ownerDocument.activeElement.getAttribute("class"),
    135    "frame",
    136    "active element has expected class"
    137  );
    138 
    139  info("Hit Up Arrow to navigate to first frame of the stacktrace");
    140  EventUtils.synthesizeKey("KEY_ArrowUp");
    141  ok(
    142    outputScroller.ownerDocument.activeElement.closest(".message.trace"),
    143    "The active element is in the trace message"
    144  );
    145  is(
    146    TRACE_FRAME_LINE_REGEX.exec(
    147      outputScroller.ownerDocument.activeElement.innerText
    148    )?.[0],
    149    "test.html:7",
    150    "third frame of the stacktrace is focused"
    151  );
    152  is(
    153    outputScroller.ownerDocument.activeElement.getAttribute("class"),
    154    "frame",
    155    "active element has expected class"
    156  );
    157 
    158  info("Hit Tab to navigate to the message location");
    159  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
    160  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
    161  ok(
    162    outputScroller.ownerDocument.activeElement.closest(".message.trace"),
    163    "The active element is in the trace message"
    164  );
    165  is(
    166    outputScroller.ownerDocument.activeElement.getAttribute("class"),
    167    "frame-link-source",
    168    "active element is the console trace message location"
    169  );
    170  is(
    171    TRACE_FRAME_LINE_REGEX.exec(
    172      outputScroller.ownerDocument.activeElement.innerText
    173    )?.[0],
    174    "test.html:7:33",
    175    "active element is expected message location"
    176  );
    177 
    178  info("Hit Tab to navigate to the previous message location");
    179  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
    180  ok(
    181    !outputScroller.ownerDocument.activeElement.closest(".message.trace"),
    182    "The active element is not in the trace message"
    183  );
    184  is(
    185    outputScroller.ownerDocument.activeElement.getAttribute("class"),
    186    "frame-link-source",
    187    "active element is the console trace message location"
    188  );
    189  is(
    190    TRACE_FRAME_LINE_REGEX.exec(
    191      outputScroller.ownerDocument.activeElement.innerText
    192    )[0],
    193    "test.html:4:15",
    194    "active element is expected message location"
    195  );
    196 
    197  info("Clear output");
    198  hud.jsterm.focus();
    199 
    200  info("try ctrl-l to clear output");
    201  let clearShortcut;
    202  if (Services.appinfo.OS === "Darwin") {
    203    clearShortcut = WCUL10n.getStr("webconsole.clear.keyOSX");
    204  } else {
    205    clearShortcut = WCUL10n.getStr("webconsole.clear.key");
    206  }
    207  synthesizeKeyShortcut(clearShortcut);
    208  await waitFor(() => !findAllMessages(hud).length);
    209  ok(isInputFocused(hud), "console was cleared and input is focused");
    210 
    211  if (Services.appinfo.OS === "Darwin") {
    212    info("Log a new message from the content page");
    213    const onMessage = waitForMessageByType(
    214      hud,
    215      "another simple text message",
    216      ".console-api"
    217    );
    218    SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
    219      content.console.log("another simple text message");
    220    });
    221    await onMessage;
    222 
    223    info("Send Cmd-K to clear console");
    224    synthesizeKeyShortcut(WCUL10n.getStr("webconsole.clear.alternativeKeyOSX"));
    225 
    226    await waitFor(() => !findAllMessages(hud).length);
    227    ok(
    228      isInputFocused(hud),
    229      "console was cleared as expected with alternative shortcut"
    230    );
    231  }
    232 
    233  // Focus filter
    234  info("try ctrl-f to focus filter");
    235  synthesizeKeyShortcut(WCUL10n.getStr("webconsole.find.key"));
    236  ok(!isInputFocused(hud), "input is not focused");
    237  ok(hasFocus(getFilterInput(hud)), "filter input is focused");
    238 
    239  info("try ctrl-f when filter is already focused");
    240  synthesizeKeyShortcut(WCUL10n.getStr("webconsole.find.key"));
    241  ok(!isInputFocused(hud), "input is not focused");
    242  is(
    243    getFilterInput(hud),
    244    outputScroller.ownerDocument.activeElement,
    245    "filter input is focused"
    246  );
    247 
    248  info("Ctrl-U should open view:source when input is focused");
    249  hud.jsterm.focus();
    250  const onTabOpen = BrowserTestUtils.waitForNewTab(
    251    gBrowser,
    252    url => url.startsWith("view-source:"),
    253    true
    254  );
    255  EventUtils.synthesizeKey("u", { accelKey: true });
    256  await onTabOpen;
    257  ok(
    258    true,
    259    "The view source tab was opened with the expected keyboard shortcut"
    260  );
    261 });