summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/test/mochitest/browser_dbg-javascript-tracer.js
diff options
context:
space:
mode:
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.js323
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;
+});