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 });