browser_dbg-inline-preview.js (8662B)
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 // Test checking inline preview feature 6 7 "use strict"; 8 9 add_task(async function testInlinePreviews() { 10 await pushPref("devtools.debugger.features.inline-preview", true); 11 12 const dbg = await initDebugger( 13 "doc-inline-preview.html", 14 "inline-preview.js" 15 ); 16 await selectSource(dbg, "inline-preview.js"); 17 18 // Reload the page to trigger the pause at the debugger statement 19 // in the block on line 66. 20 const onReload = reload(dbg); 21 await waitForPaused(dbg); 22 23 info("Check that debugger is paused in the block scope"); 24 await assertPausedAtSourceAndLine( 25 dbg, 26 findSource(dbg, "inline-preview.js").id, 27 66 28 ); 29 30 await assertInlinePreviews( 31 dbg, 32 [ 33 { previews: [{ identifier: "x:", value: "1" }], line: 63 }, 34 { previews: [{ identifier: "x:", value: "2" }], line: 65 }, 35 ], 36 // `block` is passed as the function name here because 37 // we are testing a block scope 38 "block" 39 ); 40 41 await resume(dbg); 42 43 await assertInlinePreviews( 44 dbg, 45 [ 46 { previews: [{ identifier: "x:", value: "1" }], line: 63 }, 47 { 48 previews: [{ identifier: "dict:", value: 'Object { hello: "world" }' }], 49 line: 68, 50 }, 51 { previews: [{ identifier: "key:", value: '"hello"' }], line: 69 }, 52 ], 53 "block" 54 ); 55 56 await resume(dbg); 57 await onReload; 58 59 await invokeFunctionAndAssertInlinePreview({ 60 dbg, 61 fnName: "checkValues", 62 expectedInlinePreviews: [ 63 { previews: [{ identifier: "a:", value: '""' }], line: 2 }, 64 { previews: [{ identifier: "b:", value: "false" }], line: 3 }, 65 { previews: [{ identifier: "c:", value: "undefined" }], line: 4 }, 66 { previews: [{ identifier: "d:", value: "null" }], line: 5 }, 67 { previews: [{ identifier: "e:", value: "Array []" }], line: 6 }, 68 { previews: [{ identifier: "f:", value: "Object { }" }], line: 7 }, 69 { 70 previews: [{ identifier: "reg:", value: "/^\\p{RGI_Emoji}$/v" }], 71 line: 8, 72 }, 73 { 74 previews: [{ identifier: "obj:", value: "Object { foo: 1 }" }], 75 line: 9, 76 }, 77 { 78 previews: [ 79 { 80 identifier: "bs:", 81 value: "Array(101) [ {…}, {…}, {…}, … ]", 82 }, 83 ], 84 line: 13, 85 }, 86 ], 87 }); 88 89 await invokeFunctionAndAssertInlinePreview({ 90 dbg, 91 fnName: "columnWise", 92 expectedInlinePreviews: [ 93 { previews: [{ identifier: "a:", value: '"a"' }], line: 21 }, 94 { previews: [{ identifier: "b:", value: '"b"' }], line: 22 }, 95 { previews: [{ identifier: "c:", value: '"c"' }], line: 23 }, 96 ], 97 }); 98 99 // Check that referencing an object property previews the property, not the object (bug 1599917) 100 await invokeFunctionAndAssertInlinePreview({ 101 dbg, 102 fnName: "objectProperties", 103 expectedInlinePreviews: [ 104 { 105 previews: [ 106 { 107 identifier: "obj:", 108 value: 'Object { hello: "world", a: {…} }', 109 }, 110 ], 111 line: 29, 112 }, 113 { previews: [{ identifier: "obj.hello:", value: '"world"' }], line: 30 }, 114 { previews: [{ identifier: "obj.a.b:", value: '"c"' }], line: 31 }, 115 ], 116 }); 117 118 await invokeFunctionAndAssertInlinePreview({ 119 dbg, 120 fnName: "classProperties", 121 expectedInlinePreviews: [ 122 { 123 previews: [ 124 { identifier: "i:", value: "2" }, 125 { identifier: "this.x:", value: "1" }, 126 ], 127 line: 43, 128 }, 129 { 130 previews: [ 131 { identifier: "self:", value: `Object { x: 1, #privateVar: 2 }` }, 132 ], 133 line: 44, 134 }, 135 ], 136 }); 137 138 // Checks __proto__ variable/argument are displayed 139 await invokeFunctionAndAssertInlinePreview({ 140 dbg, 141 fnName: "protoArg", 142 fnArgs: ["tomato"], 143 expectedInlinePreviews: [ 144 { 145 previews: [{ identifier: "__proto__:", value: `"tomato"` }], 146 line: 74, 147 }, 148 ], 149 }); 150 await invokeFunctionAndAssertInlinePreview({ 151 dbg, 152 fnName: "protoVar", 153 expectedInlinePreviews: [ 154 { 155 previews: [{ identifier: "__proto__:", value: `"lemon"` }], 156 line: 79, 157 }, 158 ], 159 }); 160 161 await invokeFunctionAndAssertInlinePreview({ 162 dbg, 163 fnName: "innerBlockHoistedFuncDecl", 164 expectedInlinePreviews: [ 165 { previews: [{ identifier: "foo:", value: "function foo()" }], line: 90 }, 166 ], 167 }); 168 169 // Check inline previews for values within a module script 170 await invokeFunctionAndAssertInlinePreview({ 171 dbg, 172 fnName: "runInModule", 173 expectedInlinePreviews: [ 174 { previews: [{ identifier: "val:", value: "4" }], line: 20 }, 175 { previews: [{ identifier: "ids:", value: "Array [ 1, 2 ]" }], line: 21 }, 176 ], 177 }); 178 179 // Make sure the next breakpoint source is selected, parsed etc... 180 // Bug 1974236: This should not be necessary. 181 await selectSource(dbg, "inline-preview.js"); 182 183 // Checks that open in inspector button works in inline preview 184 invokeInTab("btnClick"); 185 await assertInlinePreviews( 186 dbg, 187 [{ previews: [{ identifier: "btn:", value: "button" }], line: 53 }], 188 "onBtnClick" 189 ); 190 191 await checkInspectorIcon(dbg); 192 193 await dbg.toolbox.selectTool("jsdebugger"); 194 195 await waitForSelectedSource(dbg, "inline-preview.js"); 196 197 // Check preview of event ( event.target should be clickable ) 198 // onBtnClick function in inline-preview.js 199 await assertInlinePreviews( 200 dbg, 201 [ 202 { 203 previews: [ 204 { 205 identifier: "event:", 206 value: "click { target: button, buttons: 0, clientX: 0, … }", 207 }, 208 ], 209 line: 58, 210 }, 211 ], 212 "onBtnClick" 213 ); 214 await checkInspectorIcon(dbg); 215 await resume(dbg); 216 217 await dbg.toolbox.closeToolbox(); 218 }); 219 220 add_task(async function testInlinePreviewsWithExplicitResourceManagement() { 221 await pushPref("devtools.debugger.features.inline-preview", true); 222 // javascript.options.experimental.explicit_resource_management is set to true, but it's 223 // only supported on Nightly at the moment, so only check for SuppressedError if 224 // they're supported. 225 if (!AppConstants.ENABLE_EXPLICIT_RESOURCE_MANAGEMENT) { 226 return; 227 } 228 const dbg = await initDebugger("doc-inline-preview.html"); 229 230 const onPaused = waitForPaused(dbg); 231 dbg.commands.scriptCommand.execute( 232 ` 233 function explicitResourceManagement() { 234 using erm = { 235 [Symbol.dispose]() {}, 236 foo: 42 237 }; 238 console.log(erm.foo); 239 debugger; 240 }; explicitResourceManagement();`, 241 {} 242 ); 243 await onPaused; 244 245 await invokeFunctionAndAssertInlinePreview({ 246 dbg, 247 fnName: "explicitResourceManagement", 248 expectedInlinePreviews: [ 249 { 250 previews: [ 251 { 252 identifier: "erm:", 253 value: `Object { foo: 42, Symbol("Symbol.dispose"): Symbol.dispose() }`, 254 }, 255 ], 256 line: 3, 257 }, 258 { 259 previews: [ 260 { 261 identifier: "erm.foo:", 262 value: "42", 263 }, 264 ], 265 line: 7, 266 }, 267 ], 268 }); 269 270 await dbg.toolbox.closeToolbox(); 271 }); 272 273 async function invokeFunctionAndAssertInlinePreview({ 274 dbg, 275 fnName, 276 fnArgs = [], 277 expectedInlinePreviews, 278 }) { 279 invokeInTab(fnName, ...fnArgs); 280 await assertInlinePreviews(dbg, expectedInlinePreviews, fnName); 281 await resume(dbg); 282 } 283 284 async function checkInspectorIcon(dbg) { 285 const node = await waitForElement(dbg, "inlinePreviewOpenInspector"); 286 287 // Ensure hovering over button highlights the node in content pane 288 const view = node.ownerDocument.defaultView; 289 const { toolbox } = dbg; 290 291 // Setup a promise that will set `nodeHighlighted` to the highlighter-shown 292 // event payload. 293 let nodeHighlighted; 294 toolbox 295 .getHighlighter() 296 .waitForHighlighterShown() 297 .then(event => { 298 nodeHighlighted = event; 299 }); 300 301 info("Wait for node to be highlighted"); 302 const nodeFront = await waitFor(() => { 303 // The test intermittently fails when we try to mouseover only once. 304 // Setup a simple polling mechanism to avoid this. See Bug 1607636. 305 if (nodeHighlighted) { 306 return nodeHighlighted.nodeFront; 307 } 308 309 EventUtils.synthesizeMouseAtCenter(node, { type: "mousemove" }, view); 310 return false; 311 }); 312 313 is(nodeFront.displayName, "button", "The correct node was highlighted"); 314 315 // Ensure panel changes when button is clicked 316 const onInspectorPanelLoad = waitForInspectorPanelChange(dbg); 317 node.click(); 318 await onInspectorPanelLoad; 319 320 await resume(dbg); 321 }