Files
sousa-gecko/devtools/server/tracer/tests/browser/browser_worker_tracer.js
T
Eden Chuang 81fff21b00 Bug 1944240 - Update worker-debugging tests for the default-on RemoteWorkerDebugger. r=jdescottes,asuth,extension-reviewers,devtools-reviewers,dom-worker-reviewers,robwu,ochameau
Several tests introspect workers through the nsIWorkerDebuggerManager -- by
enumerating it, matching a worker by its (relative) script URL, or checking
process placement. With the parent-process RemoteWorkerDebugger on by default a
worker registers its debugger in the parent process, which reports the absolute
script URL, registers asynchronously over IPC, and (for content workers) is no
longer visible in the content-process manager. These tests assume the local
WorkerDebugger's synchronous, content-process, relative-URL behaviour and fail.

Pin dom.worker.remoteDebugger.enabled to false in these tests so they keep using
the local WorkerDebugger. These checks are debugger-location-dependent: the
legacy worker-introspection path still needs to be modernized to the
RemoteWorkerDebugger model, and each pin (or test) should be removed once the
local WorkerDebugger mechanism is removed:
  - devtools/client/shared/test/browser_dbg_listworkers.js
  - devtools/shared/webconsole/test/chrome/test_console_worker.html
  - devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html
  - dom/workers/test/test_shutdownCheck.xhtml
  - dom/workers/test/browser_privilegedmozilla_remoteworker.js
  - dom/workers/test/browser_serviceworker_fetch_new_process.js
  - dom/base/crashtests/eventSource_invalid_scheme_worker_shutdown.html
  - toolkit/components/extensions/test/browser/browser_ext_background_serviceworker.js

The extension service-worker xpcshell helper (head_service_worker.js) is instead
updated to watch the parent-process WorkerDebuggerManager when the pref is on, so
test_ext_background_service_worker keeps working through the remote debugger
rather than being pinned.

dom_worker_helper.js matches a debugger by absolute or relative script URL (the
parent reports the absolute URL), and test_WorkerDebugger.xhtml only asserts
nsIWorkerDebugger.window for the local debugger, since a remote worker has no
window in the parent process.

Run the worker tests that exercise worker debugging under both pref values, so
both the local WorkerDebugger and the parent-process RemoteWorkerDebugger stay
covered on CI regardless of the channel default. dom_worker_helper.js gains an
addTaskWithBothWorkerDebuggers helper, and each of the following runs once with
dom.worker.remoteDebugger.enabled=false and once with it true:
  - the WorkerDebugger* / WorkerDebuggerGlobalScope* chrome mochitests (except
    test_WorkerDebugger_frozen.xhtml)
  - dom/workers/test/browser_WorkerDebugger{,_waiting}.initialize.js
  - devtools browser_worker_tracer.js and browser_target_command_tab_workers.js
  - the WebDriver BiDi browser_WorkerListener_{chromeWorker,serviceWorker,
    sharedWorker}.js tests

A few worker tests keep global state that does not reset cleanly between the two
runs -- browser_target_command_browser_workers.js enumerates every worker in the
browser and its parent-process workers linger, test_WorkerDebugger_frozen.xhtml
manipulates frozen/suspended state, and browser_WorkerListener.js drives multiple
tabs -- so they keep running at the channel default rather than twice.

Add tests covering the parent-process worker debugging that the
RemoteWorkerDebugger enables:

  - browser_parent_worker_nested.js: a chrome worker and the nested worker it
    spawns both register through the parent-process RemoteWorkerDebugger, and the
    nested worker's debugger URL is resolved to an absolute URL.

  - browser_resources_thread_states_parent_worker.js: THREAD_STATE resources let
    DevTools interactively pause and resume a chrome worker via main-process
    (Browser Toolbox) commands.

Differential Revision: https://phabricator.services.mozilla.com/D306652
2026-07-07 20:20:07 +00:00

84 lines
2.6 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].getService(
Ci.nsIWorkerDebuggerManager
);
const BASE_URL =
"chrome://mochitests/content/browser/devtools/server/tracer/tests/browser/";
const WORKER_URL = BASE_URL + "Worker.tracer.js";
const WORKER_DEBUGGER_URL = BASE_URL + "WorkerDebugger.tracer.js";
async function doTest() {
const onDbg = waitForWorkerDebugger(WORKER_URL);
info("Instantiate a regular worker");
const worker = new Worker(WORKER_URL);
info("Wait for worker to reply back");
await new Promise(r => (worker.onmessage = r));
info("Wait for WorkerDebugger to be instantiated");
const dbg = await onDbg;
const onDebuggerScriptSentFrames = new Promise(resolve => {
const listener = {
onMessage(msg) {
dbg.removeListener(listener);
resolve(JSON.parse(msg));
},
};
dbg.addListener(listener);
});
info("Evaluate a Worker Debugger test script");
dbg.initialize(WORKER_DEBUGGER_URL);
info("Wait for frames to be notified by the debugger script");
const frames = await onDebuggerScriptSentFrames;
is(frames.length, 3);
// There is a third frame which relates to the usage of Debugger.Object.executeInGlobal
// which we ignore as that's a test side effect.
const lastFrame = frames.at(-1);
const beforeLastFrame = frames.at(-2);
is(beforeLastFrame.depth, 1);
is(beforeLastFrame.formatedDisplayName, "λ foo");
is(beforeLastFrame.prefix, "testWorkerPrefix: ");
ok(beforeLastFrame.frame);
is(lastFrame.depth, 2);
is(lastFrame.formatedDisplayName, "λ bar");
is(lastFrame.prefix, "testWorkerPrefix: ");
ok(lastFrame.frame);
}
// Run once per dom.worker.remoteDebugger.enabled value so the worker debugger
// is exercised against both the local WorkerDebugger and the parent-process
// RemoteWorkerDebugger (bug 1944240).
for (const remoteDebuggerEnabled of [false, true]) {
add_task(async function testTracingWorker() {
await SpecialPowers.pushPrefEnv({
set: [["dom.worker.remoteDebugger.enabled", remoteDebuggerEnabled]],
});
info(
"Running with dom.worker.remoteDebugger.enabled=" + remoteDebuggerEnabled
);
await doTest();
});
}
function waitForWorkerDebugger(url) {
return new Promise(function (resolve) {
wdm.addListener({
onRegister(dbg) {
if (dbg.url !== url) {
return;
}
ok(true, "Debugger with url " + url + " should be registered.");
wdm.removeListener(this);
resolve(dbg);
},
});
});
}