browser_dbg-call-stack.js (8479B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 "use strict"; 6 7 // Ignore strange errors when shutting down. 8 PromiseTestUtils.allowMatchingRejectionsGlobally(/No such actor/); 9 10 add_task(async function testBasicFrames() { 11 const dbg = await initDebugger( 12 "doc-script-switching.html", 13 "script-switching-01.js", 14 "script-switching-02.js" 15 ); 16 17 const found = findElement(dbg, "callStackBody"); 18 is(found, null, "Call stack is hidden"); 19 20 invokeInTab("firstCall"); 21 await waitForPaused(dbg); 22 23 const frames = findAllElements(dbg, "frames"); 24 assertFrameIsSelected(dbg, frames[0], "secondCall"); 25 26 info("Assert pause at the correct location"); 27 await assertPausedAtSourceAndLine( 28 dbg, 29 findSource(dbg, "script-switching-02.js").id, 30 6 31 ); 32 33 info("Click the second frame and assert the frame and the selected location"); 34 frames[1].click(); 35 await assertSelectedLocation( 36 dbg, 37 findSource(dbg, "script-switching-01.js").id, 38 8 39 ); 40 assertFrameIsSelected(dbg, frames[1], "firstCall"); 41 42 const button = toggleButton(dbg); 43 ok(!button, "toggle button shouldn't be there"); 44 45 await resume(dbg); 46 }); 47 48 add_task(async function testFrameNavigation() { 49 const dbg = await initDebugger("doc-frames.html", "frames.js"); 50 51 const source = findSource(dbg, "frames.js"); 52 invokeInTab("startRecursion"); 53 await waitForPaused(dbg); 54 55 let frames = findAllElements(dbg, "frames"); 56 assertFrameIsSelected(dbg, frames[0], "recurseA"); 57 assertFrameContent(dbg, frames[0], "recurseA", "frames.js:3"); 58 59 // check to make sure that the toggle button isn't there 60 let button = toggleButton(dbg); 61 62 is(button.innerText, "Expand rows", "toggle button should be 'expand'"); 63 is(frames.length, 7, "There should be at most seven frames"); 64 65 frames[0].focus(); 66 67 info("Assert the Home and End Keys on the frame list"); 68 pressKey(dbg, "End"); 69 assertFrameContent( 70 dbg, 71 dbg.win.document.activeElement, 72 "recurseA", 73 "frames.js:8" 74 ); 75 76 pressKey(dbg, "Start"); 77 assertFrameContent( 78 dbg, 79 dbg.win.document.activeElement, 80 "recurseA", 81 "frames.js:3" 82 ); 83 84 info("Assert navigating through the frames"); 85 pressKey(dbg, "Down"); 86 is(frames[1], dbg.win.document.activeElement, "The second frame is focused"); 87 88 pressKey(dbg, "Down"); 89 is(frames[2], dbg.win.document.activeElement, "The third frame is focused"); 90 91 info( 92 "Assert that selecting the third frame jumps to the correct source location" 93 ); 94 pressKey(dbg, "Enter"); 95 96 await assertSelectedLocation(dbg, source.id, 8); 97 assertFrameIsSelected(dbg, frames[2], "recurseA"); 98 assertFrameContent(dbg, frames[2], "recurseA", "frames.js:8"); 99 100 is( 101 dbg.win.document.activeElement, 102 findElement(dbg, "CodeMirrorLines"), 103 "Selecting the frame via the Enter key will open the source, set the cursor at the frame location and focus CodeMirror" 104 ); 105 106 info("Focus the frame again in the frame list"); 107 frames[2].focus(); 108 109 info("Navigate up and assert the second frame"); 110 pressKey(dbg, "Up"); 111 is( 112 frames[1], 113 dbg.win.document.activeElement, 114 "The second frame is now focused" 115 ); 116 117 info( 118 "Assert that selecting the second frame jumps to the correct source location" 119 ); 120 pressKey(dbg, "Enter"); 121 122 await assertSelectedLocation(dbg, source.id, 18); 123 assertFrameIsSelected(dbg, frames[1], "recurseB"); 124 125 frames[0].focus(); 126 127 button.click(); 128 129 button = toggleButton(dbg); 130 frames = findAllElements(dbg, "frames"); 131 is(button.innerText, "Collapse rows", "toggle button should be collapsed"); 132 is(frames.length, 22, "All of the frames should be shown"); 133 await waitForSelectedSource(dbg, "frames.js"); 134 }); 135 136 add_task(async function testGroupFrames() { 137 const url = createMockAngularPage(); 138 const tab = await addTab(url); 139 info("Open debugger"); 140 const toolbox = await openToolboxForTab(tab, "jsdebugger"); 141 const dbg = createDebuggerContext(toolbox); 142 143 const found = findElement(dbg, "callStackBody"); 144 is(found, null, "Call stack is hidden"); 145 146 const pausedContent = SpecialPowers.spawn( 147 gBrowser.selectedBrowser, 148 [], 149 function () { 150 content.document.querySelector("button.pause").click(); 151 } 152 ); 153 154 await waitForPaused(dbg); 155 const group = findElementWithSelector(dbg, ".frames .frames-group"); 156 is( 157 group.querySelector(".badge").textContent, 158 "2", 159 "Group has expected badge" 160 ); 161 is( 162 group.querySelector(".group-description-name").textContent, 163 "Angular", 164 "Group has expected location" 165 ); 166 167 info("Expand the frame group"); 168 group.focus(); 169 pressKey(dbg, "Enter"); 170 171 info("Press arrow to select first frame element"); 172 pressKey(dbg, "Down"); 173 174 info("Assert the Home and End Keys in the Frame Group"); 175 pressKey(dbg, "End"); 176 info("The last frame item in the group is not selected"); 177 assertFrameIsNotSelected(dbg, dbg.win.document.activeElement, "<anonymous>"); 178 assertFrameContent(dbg, dbg.win.document.activeElement, "<anonymous>"); 179 180 pressKey(dbg, "Start"); 181 info("The group header is focused"); 182 is( 183 dbg.win.document.activeElement.querySelector(".group-description-name") 184 .innerText, 185 "Angular", 186 "The group is correct" 187 ); 188 189 const frameElements = findAllElements(dbg, "frames"); 190 is( 191 frameElements[0], 192 dbg.win.document.activeElement, 193 "The first frame is now focused" 194 ); 195 196 const source = findSource(dbg, "angular.js"); 197 await assertPausedAtSourceAndLine(dbg, source.id, 4); 198 await assertSelectedLocation(dbg, source.id, 4); 199 assertFrameIsSelected(dbg, frameElements[1], "<anonymous>"); 200 201 info("Select the frame group"); 202 frameElements[1].focus(); 203 pressKey(dbg, "Up"); 204 205 info( 206 "Assert that the frame group does not collapse when a frame group item is selected" 207 ); 208 pressKey(dbg, "Enter"); 209 const frameGroupHeader = frameElements[1].parentNode.previousElementSibling; 210 ok( 211 frameGroupHeader.classList.contains("expanded"), 212 "The frame group is still expanded" 213 ); 214 is( 215 frameGroupHeader.querySelector(".group-description-name").innerText, 216 "Angular", 217 "The group is correct" 218 ); 219 is( 220 frameGroupHeader.title, 221 "Select a non-group frame to collapse Angular frames", 222 "The group title is correct" 223 ); 224 225 await resume(dbg); 226 227 info("Wait for content to be resumed"); 228 await pausedContent; 229 }); 230 231 function toggleButton(dbg) { 232 const callStackBody = findElement(dbg, "callStackBody"); 233 return callStackBody.querySelector(".show-more"); 234 } 235 236 function assertFrameContent(dbg, element, expectedTitle, expectedLocation) { 237 is( 238 element.querySelector(".title").innerText, 239 expectedTitle, 240 "The frame title is correct" 241 ); 242 243 if (expectedLocation) { 244 is( 245 element.querySelector(".location").innerText, 246 expectedLocation, 247 "The location is correct" 248 ); 249 } 250 } 251 252 async function assertSelectedLocation(dbg, sourceId, line) { 253 await waitFor(() => { 254 const selectedLocation = dbg.selectors.getSelectedLocation(); 255 return ( 256 selectedLocation.source.id == sourceId && selectedLocation.line == line 257 ); 258 }); 259 ok(true, "The correct location is selected"); 260 } 261 262 // Create an HTTP server to simulate an angular app with anonymous functions 263 // and return the URL. 264 function createMockAngularPage() { 265 const httpServer = createTestHTTPServer(); 266 267 httpServer.registerContentType("html", "text/html"); 268 httpServer.registerContentType("js", "application/javascript"); 269 270 const htmlFilename = "angular-mock.html"; 271 httpServer.registerPathHandler( 272 `/${htmlFilename}`, 273 function (request, response) { 274 response.setStatusLine(request.httpVersion, 200, "OK"); 275 response.write(` 276 <html> 277 <button class="pause">Click me</button> 278 <script type="text/javascript" src="angular.js"></script> 279 </html>`); 280 } 281 ); 282 283 // Register an angular.js file in order to create a Group with anonymous functions in 284 // the callstack panel. 285 httpServer.registerPathHandler("/angular.js", function (request, response) { 286 response.setHeader("Content-Type", "application/javascript"); 287 response.write(` 288 document.querySelector("button.pause").addEventListener("click", () => { 289 (function() { 290 debugger; 291 })(); 292 }) 293 `); 294 }); 295 296 const port = httpServer.identity.primaryPort; 297 return `http://localhost:${port}/${htmlFilename}`; 298 }