diff options
Diffstat (limited to 'devtools/client/debugger/test/mochitest/browser_dbg-javascript-tracer.js')
-rw-r--r-- | devtools/client/debugger/test/mochitest/browser_dbg-javascript-tracer.js | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-javascript-tracer.js b/devtools/client/debugger/test/mochitest/browser_dbg-javascript-tracer.js new file mode 100644 index 0000000000..9292e1ba17 --- /dev/null +++ b/devtools/client/debugger/test/mochitest/browser_dbg-javascript-tracer.js @@ -0,0 +1,323 @@ +/* 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 <http://mozilla.org/MPL/2.0/>. */ + +// Tests the Javascript Tracing feature. + +"use strict"; + +add_task(async function () { + // This is preffed off for now, so ensure turning it on + await pushPref("devtools.debugger.features.javascript-tracing", true); + + const dbg = await initDebugger("doc-scripts.html"); + + info("Enable the tracing"); + await clickElement(dbg, "trace"); + + const topLevelThreadActorID = + dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID; + info("Wait for tracing to be enabled"); + await waitForState(dbg, state => { + return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID); + }); + + ok( + dbg.toolbox.splitConsole, + "Split console is automatically opened when tracing to the console" + ); + + await hasConsoleMessage(dbg, "Started tracing to Web Console"); + + invokeInTab("main"); + + info("Wait for console messages for the whole trace"); + // `main` calls `foo` which calls `bar` + await hasConsoleMessage(dbg, "λ main"); + await hasConsoleMessage(dbg, "λ foo"); + await hasConsoleMessage(dbg, "λ bar"); + + const traceMessages = await findConsoleMessages(dbg.toolbox, "λ main"); + is(traceMessages.length, 1, "We got a unique trace for 'main' function call"); + const sourceLink = traceMessages[0].querySelector(".frame-link-source"); + sourceLink.click(); + info("Wait for the main function to be highlighted in the debugger"); + await waitForSelectedSource(dbg, "simple1.js"); + await waitForSelectedLocation(dbg, 1, 16); + + // Trigger a click to verify we do trace DOM events + BrowserTestUtils.synthesizeMouseAtCenter( + "button", + {}, + gBrowser.selectedBrowser + ); + + await hasConsoleMessage(dbg, "DOM(click)"); + await hasConsoleMessage(dbg, "λ simple"); + + // Test Blackboxing + info("Clear the console from previous traces"); + const { hud } = await dbg.toolbox.getPanel("webconsole"); + hud.ui.clearOutput(); + await waitFor( + async () => !(await findConsoleMessages(dbg.toolbox, "λ main")).length, + "Wait for console to be cleared" + ); + + info( + "Now blackbox only the source where main function is (simple1.js), but foo and bar are in another module" + ); + await clickElement(dbg, "blackbox"); + await waitForDispatch(dbg.store, "BLACKBOX_WHOLE_SOURCES"); + + info("Trigger some code from simple1 and simple2"); + invokeInTab("main"); + + info("Only methods from simple2 are logged"); + await hasConsoleMessage(dbg, "λ foo"); + await hasConsoleMessage(dbg, "λ bar"); + is( + (await findConsoleMessages(dbg.toolbox, "λ main")).length, + 0, + "Traces from simple1.js, related to main function are not logged" + ); + + info("Revert blackboxing"); + await clickElement(dbg, "blackbox"); + await waitForDispatch(dbg.store, "UNBLACKBOX_WHOLE_SOURCES"); + + // Test Disabling tracing + info("Disable the tracing"); + await clickElement(dbg, "trace"); + info("Wait for tracing to be disabled"); + await waitForState(dbg, state => { + return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID); + }); + await hasConsoleMessage(dbg, "Stopped tracing"); + + invokeInTab("inline_script2"); + + // Let some time for the tracer to appear if we failed disabling the tracing + await wait(1000); + + const messages = await findConsoleMessages(dbg.toolbox, "inline_script2"); + is( + messages.length, + 0, + "We stopped recording traces, an the function call isn't logged in the console" + ); + + // Test Navigations + await navigate(dbg, "doc-sourcemaps2.html", "main.js", "main.min.js"); + + info("Re-enable the tracing after navigation"); + await clickElement(dbg, "trace"); + + const newTopLevelThread = + dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID; + info("Wait for tracing to be re-enabled"); + await waitForState(dbg, state => { + return dbg.selectors.getIsThreadCurrentlyTracing(newTopLevelThread); + }); + + invokeInTab("logMessage"); + + await hasConsoleMessage(dbg, "λ logMessage"); + + // Test clicking on the function to open the precise related location + const traceMessages2 = await findConsoleMessages(dbg.toolbox, "λ logMessage"); + is( + traceMessages2.length, + 1, + "We got a unique trace for 'logMessage' function call" + ); + const sourceLink2 = traceMessages2[0].querySelector(".frame-link-source"); + sourceLink2.click(); + + info("Wait for the 'logMessage' function to be highlighted in the debugger"); + await waitForSelectedSource(dbg, "main.js"); + await waitForSelectedLocation(dbg, 4, 2); + ok(true, "The selected source and location is on the original file"); + + await dbg.toolbox.closeToolbox(); +}); + +add_task(async function testPersitentLogMethod() { + let dbg = await initDebugger("doc-scripts.html"); + is( + dbg.selectors.getJavascriptTracingLogMethod(), + "console", + "By default traces are logged to the console" + ); + + info("Change the log method to stdout"); + dbg.actions.setJavascriptTracingLogMethod("stdout"); + + await dbg.toolbox.closeToolbox(); + + dbg = await initDebugger("doc-scripts.html"); + is( + dbg.selectors.getJavascriptTracingLogMethod(), + "stdout", + "The new setting has been persisted" + ); + + info("Reset back to the default value"); + dbg.actions.setJavascriptTracingLogMethod("console"); +}); + +add_task(async function testPageKeyShortcut() { + // Ensures that the key shortcut emitted in the content process bubbles up to the parent process + await pushPref("test.events.async.enabled", true); + + // Fake DevTools being opened by a real user interaction. + // Tests are bypassing DevToolsStartup to open the tools by calling gDevTools directly. + // By doing so DevToolsStartup considers itself as uninitialized, + // whereas we want it to handle the key shortcut we trigger in this test. + const DevToolsStartup = Cc["@mozilla.org/devtools/startup-clh;1"].getService( + Ci.nsISupports + ).wrappedJSObject; + DevToolsStartup.initialized = true; + registerCleanupFunction(() => { + DevToolsStartup.initialized = false; + }); + + const dbg = await initDebuggerWithAbsoluteURL("data:text/html,key-shortcut"); + + const topLevelThreadActorID = + dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID; + ok( + !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID), + "Tracing is disabled on debugger opening" + ); + + info( + "Focus the page in order to assert that the page keeps the focus when enabling the tracer" + ); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + content.focus(); + }); + await waitFor( + () => Services.focus.focusedElement == gBrowser.selectedBrowser + ); + is( + Services.focus.focusedElement, + gBrowser.selectedBrowser, + "The tab is still focused before enabling tracing" + ); + + info("Toggle ON the tracing via the key shortcut from the web page"); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + EventUtils.synthesizeKey( + "VK_5", + { ctrlKey: true, shiftKey: true }, + content + ); + }); + + info("Wait for tracing to be enabled"); + await waitForState(dbg, state => { + return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID); + }); + + is( + Services.focus.focusedElement, + gBrowser.selectedBrowser, + "The tab is still focused after enabling tracing" + ); + + info("Toggle it back off, with the same shortcut"); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + EventUtils.synthesizeKey( + "VK_5", + { ctrlKey: true, shiftKey: true }, + content + ); + }); + + info("Wait for tracing to be disabled"); + await waitForState(dbg, state => { + return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID); + }); +}); + +add_task(async function testPageKeyShortcutWithoutDebugger() { + // Ensures that the key shortcut emitted in the content process bubbles up to the parent process + await pushPref("test.events.async.enabled", true); + + // Fake DevTools being opened by a real user interaction. + // Tests are bypassing DevToolsStartup to open the tools by calling gDevTools directly. + // By doing so DevToolsStartup considers itself as uninitialized, + // whereas we want it to handle the key shortcut we trigger in this test. + const DevToolsStartup = Cc["@mozilla.org/devtools/startup-clh;1"].getService( + Ci.nsISupports + ).wrappedJSObject; + DevToolsStartup.initialized = true; + registerCleanupFunction(() => { + DevToolsStartup.initialized = false; + }); + + const toolbox = await openNewTabAndToolbox( + "data:text/html,tracer", + "webconsole" + ); + + info( + "Focus the page in order to assert that the page keeps the focus when enabling the tracer" + ); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + content.focus(); + }); + await waitFor( + () => Services.focus.focusedElement == gBrowser.selectedBrowser + ); + is( + Services.focus.focusedElement, + gBrowser.selectedBrowser, + "The tab is still focused before enabling tracing" + ); + + info("Toggle ON the tracing via the key shortcut from the web page"); + const { resourceCommand } = toolbox.commands; + const { onResource: onTracingStateEnabled } = + await resourceCommand.waitForNextResource( + resourceCommand.TYPES.JSTRACER_STATE, + { + ignoreExistingResources: true, + predicate(resource) { + return resource.enabled; + }, + } + ); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + EventUtils.synthesizeKey( + "VK_5", + { ctrlKey: true, shiftKey: true }, + content + ); + }); + info("Wait for tracing to be enabled"); + await onTracingStateEnabled; + + info("Toggle it back off, with the same shortcut"); + const { onResource: onTracingStateDisabled } = + await resourceCommand.waitForNextResource( + resourceCommand.TYPES.JSTRACER_STATE, + { + ignoreExistingResources: true, + predicate(resource) { + return !resource.enabled; + }, + } + ); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + EventUtils.synthesizeKey( + "VK_5", + { ctrlKey: true, shiftKey: true }, + content + ); + }); + + info("Wait for tracing to be disabled"); + await onTracingStateDisabled; +}); |