/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ /* * Tests that log points are correctly logged to the console */ "use strict"; add_task(async function () { Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); const dbg = await initDebugger( "doc-script-switching.html", "script-switching-01.js" ); const source = findSource(dbg, "script-switching-01.js"); await selectSource(dbg, "script-switching-01.js"); await getDebuggerSplitConsole(dbg); info( `Add a first log breakpoint with no argument, which will log "display name", i.e. firstCall` ); await altClickElement(dbg, "gutterElement", 7); await waitForBreakpoint(dbg, "script-switching-01.js", 7); info("Add another log breakpoint with multiple arguments"); await dbg.actions.addBreakpoint(createLocation({ line: 8, source }), { logValue: "'a', 'b', 'c', firstCall", }); invokeInTab("firstCall"); await waitForPaused(dbg); info("Wait for the two log breakpoints"); await hasConsoleMessage(dbg, "firstCall"); await hasConsoleMessage(dbg, "a b c"); const { link, value } = await findConsoleMessage(dbg, "a b c"); is(link, "script-switching-01.js:8:3", "logs should have the relevant link"); is(value, "a b c \nfunction firstCall()", "logs should have multiple values"); await removeBreakpoint(dbg, source.id, 7); await removeBreakpoint(dbg, source.id, 8); await resume(dbg); info( "Now set a log point calling a method with a debugger statement and a breakpoint, it shouldn't pause on the log point" ); await addBreakpoint(dbg, "script-switching-01.js", 8); await addBreakpoint(dbg, "script-switching-01.js", 7); await dbg.actions.addBreakpoint(createLocation({ line: 7, source }), { logValue: "'second call', secondCall()", }); invokeInTab("firstCall"); await waitForPaused(dbg); // We aren't pausing on secondCall's debugger statement, // called by the condition, but only on the breakpoint we set on firstCall, line 8 await assertPausedAtSourceAndLine(dbg, source.id, 8); // The log point is visible, even if it had a debugger statement in it. await hasConsoleMessage(dbg, "second call 44"); await removeBreakpoint(dbg, source.id, 7); await removeBreakpoint(dbg, source.id, 8); await resume(dbg); // Resume a second time as we are hittin the debugger statement as firstCall calls secondCall await resume(dbg); info( "Set a log point throwing an exception and ensure the exception is displayed" ); await dbg.actions.addBreakpoint(createLocation({ line: 7, source }), { logValue: "jsWithError(", }); invokeInTab("firstCall"); await waitForPaused(dbg); // Exceptions in conditional breakpoint would not trigger a pause, // So we end up pausing on the debugger statement in the other script. await assertPausedAtSourceAndLine( dbg, findSource(dbg, "script-switching-02.js").id, 6 ); // But verify that the exception message is visible even if we didn't pause. // As the logValue is evaled within an array `[${logValue}]`, // the exception message is a bit cryptic... await hasConsoleMessage(dbg, "expected expression, got ']'"); await dbg.actions.removeAllBreakpoints(); await resume(dbg); info("About to set log point"); await selectSource(dbg, "script-switching-01.js"); await setLogPoint(dbg, 8, "'stacktrace test'", true); invokeInTab("logPointTest"); info("logPointTest invoked in tab"); await waitForPaused(dbg); await resume(dbg); info("Checking for any console messages"); await hasConsoleMessage(dbg, "stacktrace test"); const [stacktraceMsg] = await findConsoleMessages( dbg.toolbox, "stacktrace test" ); const stacktraceFrames = await waitFor(() => stacktraceMsg.querySelector(".frames") ); const frameNodes = stacktraceFrames.querySelectorAll(".frame"); info(`Found ${frameNodes.length} frames in the stacktrace`); is( frameNodes.length, 2, "The message does have the expected number of frames in the stacktrace" ); ok( frameNodes[0].textContent.includes("script-switching-01.js:6"), "First frame should be from line 6" ); ok( frameNodes[1].textContent.includes("script-switching-01.js:12"), "Second frame should be from line 12" ); // reopen the panel info("Reopening the panel to test the checkbox"); await selectSource(dbg, "script-switching-01.js"); rightClickElement(dbg, "gutterElement", 8); await waitForContextMenu(dbg); selectDebuggerContextMenuItem( dbg, `${selectors.addLogItem},${selectors.editLogItem}` ); await waitForConditionalPanelFocus(dbg); info("Updating the log point input value"); type(dbg, "'logpoint without stacktrace'"); // wait for a bit so codemirror is able to process the input await wait(1000); //make sure that the checkbox is checked const stacktraceCheckbox = dbg.win.document.querySelector("#showStacktrace"); ok( stacktraceCheckbox.checked, "Checkbox is still checked when reopening the logpoint panel" ); // uncheck the checkbox info("Click the checkbox to uncheck it"); stacktraceCheckbox.click(); info("Checkbox clicked to uncheck it"); await waitFor(() => { return !stacktraceCheckbox.checked; }); ok(true, "Checkbox is unchecked after clicking"); const saveButton = dbg.win.document.getElementById("save-logpoint"); const onBreakpointSet = waitForDispatch(dbg.store, "SET_BREAKPOINT"); saveButton.click(); await onBreakpointSet; info("Call logPointTest to hit the logpoint"); invokeInTab("logPointTest"); // the functions has a debugger statement, so wait for pause and resume await waitForPaused(dbg); await resume(dbg); await hasConsoleMessage(dbg, "logpoint without stacktrace"); const [logpointMsg] = await findConsoleMessages( dbg.toolbox, "logpoint without stacktrace" ); // Wait for a bit so stacktrace would be rendered await wait(1000); is( logpointMsg.querySelector(".frames"), null, "There is no stacktrace for the logpoint without stacktrace" ); info("Check logpoint async stacktrace"); await selectSource(dbg, "script-switching-01.js"); await setLogPoint(dbg, 25, `"async stack test"`, true); invokeInTab("dbgTestAsyncStack"); info("Checking for any console messages"); await hasConsoleMessage(dbg, "async stack test"); const [asyncStacktraceMsg] = await findConsoleMessages( dbg.toolbox, "async stack test" ); const asyncStacktraceFrames = await waitFor(() => asyncStacktraceMsg.querySelector(".frames") ); const asyncFrameNodes = asyncStacktraceFrames.querySelectorAll( ".frame, .location-async-cause" ); Assert.stringContains( asyncFrameNodes[0].textContent, "dbgTestOnTimeout https://example.com/browser/devtools/client/debugger/test/mochitest/examples/script-switching-01.js:24" ); Assert.stringContains( asyncFrameNodes[1].textContent, "(Async: setTimeout handler)" ); Assert.stringContains( asyncFrameNodes[2].textContent, "dbgTestTimeout https://example.com/browser/devtools/client/debugger/test/mochitest/examples/script-switching-01.js:17" ); Assert.stringContains( asyncFrameNodes[3].textContent, "dbgTestOnPromiseThen https://example.com/browser/devtools/client/debugger/test/mochitest/examples/script-switching-01.js:27" ); Assert.stringContains( asyncFrameNodes[4].textContent, "(Async: promise callback)" ); Assert.stringContains( asyncFrameNodes[5].textContent, "dbgTestPromiseThen https://example.com/browser/devtools/client/debugger/test/mochitest/examples/script-switching-01.js:21" ); Assert.stringContains( asyncFrameNodes[6].textContent, "dbgTestAsyncStack https://example.com/browser/devtools/client/debugger/test/mochitest/examples/script-switching-01.js:30" ); });