171 lines
5.3 KiB
JavaScript
171 lines
5.3 KiB
JavaScript
/* 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/>. */
|
|
|
|
// Test basic worker functionality: the main thread and worker can be
|
|
// separately controlled from the same debugger.
|
|
|
|
"use strict";
|
|
|
|
add_task(async function () {
|
|
await pushPref("devtools.debugger.threads-visible", true);
|
|
|
|
const dbg = await initDebugger(
|
|
"doc-windowless-workers.html",
|
|
"simple-worker.js"
|
|
);
|
|
const mainThread = dbg.toolbox.threadFront.actor;
|
|
|
|
await waitForThreadCount(dbg, 2);
|
|
const workers = dbg.selectors.getThreads();
|
|
Assert.equal(workers.length, 2, "Got two workers");
|
|
const thread1 = workers[0].actor;
|
|
const thread2 = workers[1].actor;
|
|
|
|
const mainThreadSource = findSource(dbg, "doc-windowless-workers.html");
|
|
|
|
info("Pause in the main thread");
|
|
assertNotPaused(dbg);
|
|
await dbg.actions.breakOnNext();
|
|
await waitForPaused(dbg, "doc-windowless-workers.html");
|
|
await assertPausedAtSourceAndLine(dbg, mainThreadSource.id, 10);
|
|
threadIsSelected(dbg, 1);
|
|
|
|
info("Pause in the first worker");
|
|
await dbg.actions.selectThread(thread1);
|
|
assertNotPaused(dbg);
|
|
await dbg.actions.breakOnNext();
|
|
await waitForPaused(dbg, "simple-worker.js");
|
|
threadIsSelected(dbg, 2);
|
|
const workerSource2 = dbg.selectors.getSelectedSource();
|
|
await assertPausedAtSourceAndLine(dbg, workerSource2.id, 3);
|
|
|
|
info("Add a watch expression and view the value");
|
|
await addExpression(dbg, "count");
|
|
is(getWatchExpressionLabel(dbg, 1), "count");
|
|
const v = getWatchExpressionValue(dbg, 1);
|
|
Assert.equal(v, `${+v}`, "Value of count should be a number");
|
|
|
|
info("StepOver in the first worker");
|
|
await stepOver(dbg);
|
|
await assertPausedAtSourceAndLine(dbg, workerSource2.id, 4);
|
|
|
|
info("Ensure that the watch expression has updated");
|
|
await waitUntil(() => {
|
|
const v2 = getWatchExpressionValue(dbg, 1);
|
|
return +v2 == +v + 1;
|
|
});
|
|
|
|
info("Resume in the first worker");
|
|
await resume(dbg);
|
|
assertNotPaused(dbg);
|
|
|
|
info("StepOver in the main thread");
|
|
dbg.actions.selectThread(mainThread);
|
|
await stepOver(dbg);
|
|
await assertPausedAtSourceAndLine(dbg, mainThreadSource.id, 11);
|
|
|
|
info("Resume in the mainThread");
|
|
await resume(dbg);
|
|
assertNotPaused(dbg);
|
|
|
|
info("Pause in both workers");
|
|
await addBreakpoint(dbg, "simple-worker.js", 10);
|
|
invokeInTab("sayHello");
|
|
|
|
info("Wait for both workers to pause");
|
|
// When a thread pauses the current thread changes,
|
|
// and we don't want to get confused.
|
|
await waitForPausedThread(dbg, thread1);
|
|
await waitForPausedThread(dbg, thread2);
|
|
threadIsPaused(dbg, 2);
|
|
threadIsPaused(dbg, 3);
|
|
|
|
info("View the first paused thread");
|
|
dbg.actions.selectThread(thread1);
|
|
await waitForPaused(dbg);
|
|
await assertPausedAtSourceAndLine(dbg, workerSource2.id, 10);
|
|
|
|
info("View the second paused thread");
|
|
await dbg.actions.selectThread(thread2);
|
|
threadIsSelected(dbg, 3);
|
|
await waitForPaused(dbg);
|
|
const workerSource3 = dbg.selectors.getSelectedSource();
|
|
is(
|
|
workerSource2,
|
|
workerSource3,
|
|
"The selected source is the same as we have one source per URL"
|
|
);
|
|
await assertPausedAtSourceAndLine(dbg, workerSource3.id, 10);
|
|
|
|
info("StepOver in second worker and not the first");
|
|
await stepOver(dbg);
|
|
await assertPausedAtSourceAndLine(dbg, workerSource3.id, 11);
|
|
await dbg.actions.selectThread(thread1);
|
|
await assertPausedAtSourceAndLine(dbg, workerSource2.id, 10);
|
|
|
|
info("Resume both worker execution");
|
|
await resume(dbg);
|
|
assertNotPaused(dbg);
|
|
await dbg.actions.selectThread(thread2);
|
|
await resume(dbg);
|
|
assertNotPaused(dbg);
|
|
|
|
let sourceActors = dbg.selectors.getSourceActorsForSource(workerSource3.id);
|
|
is(
|
|
sourceActors.length,
|
|
2,
|
|
"There is one source actor per thread for the worker source"
|
|
);
|
|
info(
|
|
"Terminate the first worker and wait for having only the second worker in threads list"
|
|
);
|
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
|
|
content.wrappedJSObject.worker1.terminate();
|
|
});
|
|
await waitForThreadCount(dbg, 1);
|
|
sourceActors = dbg.selectors.getSourceActorsForSource(workerSource3.id);
|
|
is(
|
|
sourceActors.length,
|
|
1,
|
|
"After the first worker is destroyed, we only have one source actor for the worker source"
|
|
);
|
|
ok(
|
|
sourceExists(dbg, "simple-worker.js"),
|
|
"But we still have the worker source object"
|
|
);
|
|
|
|
info("Terminate the second worker and wait for no more additional threads");
|
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
|
|
content.wrappedJSObject.worker2.terminate();
|
|
});
|
|
await waitForThreadCount(dbg, 0);
|
|
sourceActors = dbg.selectors.getSourceActorsForSource(workerSource3.id);
|
|
is(
|
|
sourceActors.length,
|
|
0,
|
|
"After all workers are destroyed, we no longer have any source actor"
|
|
);
|
|
ok(
|
|
!sourceExists(dbg, "simple-worker.js"),
|
|
"And we no longer have the worker source"
|
|
);
|
|
});
|
|
|
|
function assertClass(dbg, selector, className, ...args) {
|
|
ok(
|
|
findElement(dbg, selector, ...args).classList.contains(className),
|
|
`${className} class exists`
|
|
);
|
|
}
|
|
|
|
function threadIsPaused(dbg, index) {
|
|
return ok(
|
|
findElement(dbg, "threadsPaneItemPause", index),
|
|
`Thread ${index} is paused`
|
|
);
|
|
}
|
|
|
|
function threadIsSelected(dbg, index) {
|
|
return assertClass(dbg, "threadsPaneItem", "selected", index);
|
|
}
|