Bug 1867603 - [devtools] Introduce a tracer command to toggle tracing without the debugger. r=devtools-reviewers,nchevobbe

Differential Revision: https://phabricator.services.mozilla.com/D195125
This commit is contained in:
Alexandre Poirot 2023-12-02 08:53:38 +00:00
parent 9ec5953695
commit c19e89ee06
9 changed files with 153 additions and 48 deletions

View File

@ -363,12 +363,6 @@ class DebuggerPanel {
this._actions.selectThread(threadActorID);
}
toggleJavascriptTracing() {
this._actions.toggleTracing(
this._selectors.getJavascriptTracingLogMethod(this._getState())
);
}
destroy() {
this.panelWin.Debugger.destroy();
this.emit("destroyed");

View File

@ -28,9 +28,7 @@ export function toggleTracing(logMethod) {
return dispatch({
type: "TOGGLE_TRACING",
[PROMISE]: isTracingEnabled
? client.stopTracing()
: client.startTracing(logMethod),
[PROMISE]: client.toggleTracing(logMethod),
});
};
}

View File

@ -111,37 +111,8 @@ function forEachThread(iteratee) {
return Promise.all(promises);
}
/**
* Start JavaScript tracing for all targets.
*
* @param {String} logMethod
* Where to log the traces. Can be stdout or console.
*/
async function startTracing(logMethod) {
const targets = commands.targetCommand.getAllTargets(
commands.targetCommand.ALL_TYPES
);
await Promise.all(
targets.map(async targetFront => {
const tracerFront = await targetFront.getFront("tracer");
return tracerFront.startTracing(logMethod);
})
);
}
/**
* Stop JavaScript tracing for all targets.
*/
async function stopTracing() {
const targets = commands.targetCommand.getAllTargets(
commands.targetCommand.ALL_TYPES
);
await Promise.all(
targets.map(async targetFront => {
const tracerFront = await targetFront.getFront("tracer");
return tracerFront.stopTracing();
})
);
async function toggleTracing(logMethod) {
return commands.tracerCommand.toggle(logMethod);
}
function resume(thread, frameId) {
@ -504,8 +475,7 @@ const clientCommands = {
loadObjectProperties,
releaseActor,
pauseGrip,
startTracing,
stopTracing,
toggleTracing,
resume,
stepIn,
stepOut,

View File

@ -221,7 +221,7 @@ add_task(async function testPageKeyShortcut() {
"The tab is still focused after enabling tracing"
);
info("Toggle it back off, wit the same shortcut");
info("Toggle it back off, with the same shortcut");
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
EventUtils.synthesizeKey(
"VK_5",
@ -235,3 +235,84 @@ add_task(async function testPageKeyShortcut() {
return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThread);
});
});
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.TRACING_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.TRACING_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;
});

View File

@ -304,11 +304,7 @@ var gDevToolsBrowser = (exports.gDevToolsBrowser = {
if (!toolbox) {
break;
}
const dbg = await toolbox.getPanel("jsdebugger");
if (!dbg) {
break;
}
dbg.toggleJavascriptTracing();
await toolbox.commands.tracerCommand.toggle();
break;
}
},

View File

@ -22,6 +22,7 @@ const Commands = {
"devtools/shared/commands/target-configuration/target-configuration-command",
threadConfigurationCommand:
"devtools/shared/commands/thread-configuration/thread-configuration-command",
tracerCommand: "devtools/shared/commands/tracer/tracer-command",
};
/* eslint-disable sort-keys */

View File

@ -12,6 +12,7 @@ DIRS += [
"target",
"target-configuration",
"thread-configuration",
"tracer",
]
DevToolsModules(

View File

@ -0,0 +1,7 @@
# 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/.
DevToolsModules(
"tracer-command.js",
)

View File

@ -0,0 +1,57 @@
/* 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/. */
"use strict";
loader.lazyGetter(this, "TARGET_TYPES", function () {
return require("resource://devtools/shared/commands/target/target-command.js")
.TYPES;
});
class TracerCommand {
constructor({ commands }) {
this.#targetCommand = commands.targetCommand;
}
#targetCommand;
#isTracing = false;
/**
* Toggle JavaScript tracing for all targets.
*
* @param {String} logMethod (optional)
* Where to log the traces. Can be console or stdout.
*/
async toggle(logMethod) {
this.#isTracing = !this.#isTracing;
// If no explicit log method is passed, default to the preference value.
if (!logMethod && this.#isTracing) {
logMethod = Services.prefs.getStringPref(
"devtools.debugger.javascript-tracing-log-method",
""
);
}
const targets = this.#targetCommand.getAllTargets(
this.#targetCommand.ALL_TYPES
);
await Promise.all(
targets.map(async targetFront => {
const tracerFront = await targetFront.getFront("tracer");
// Bug 1848136: For now the tracer doesn't work for worker targets.
if (tracerFront.targetType == TARGET_TYPES.WORKER) {
return null;
}
if (this.#isTracing) {
return tracerFront.startTracing(logMethod);
}
return tracerFront.stopTracing();
})
);
}
}
module.exports = TracerCommand;