diff options
Diffstat (limited to 'devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js')
-rw-r--r-- | devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js new file mode 100644 index 0000000000..5b6629f8b0 --- /dev/null +++ b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js @@ -0,0 +1,165 @@ +/* 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"); + const mainThread = dbg.toolbox.threadFront.actor; + + await waitForThreadCount(dbg, 2); + const workers = dbg.selectors.getThreads(); + ok(workers.length == 2, "Got two workers"); + const thread1 = workers[0].actor; + const thread2 = workers[1].actor; + + const mainThreadSource = findSource(dbg, "doc-windowless-workers.html"); + + await waitForSource(dbg, "simple-worker.js"); + + info("Pause in the main thread"); + assertNotPaused(dbg); + await dbg.actions.breakOnNext(getThreadContext(dbg)); + await waitForPaused(dbg, "doc-windowless-workers.html"); + assertPausedAtSourceAndLine(dbg, mainThreadSource.id, 10); + threadIsSelected(dbg, 1); + + info("Pause in the first worker"); + await dbg.actions.selectThread(getContext(dbg), thread1); + assertNotPaused(dbg); + await dbg.actions.breakOnNext(getThreadContext(dbg)); + await waitForPaused(dbg, "simple-worker.js"); + threadIsSelected(dbg, 2); + const workerSource2 = dbg.selectors.getSelectedSource(); + 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); + ok(v == `${+v}`, "Value of count should be a number"); + + info("StepOver in the first worker"); + await stepOver(dbg); + 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(getContext(dbg), mainThread); + await stepOver(dbg); + 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(getContext(dbg), thread1); + await waitForPaused(dbg); + assertPausedAtSourceAndLine(dbg, workerSource2.id, 10); + + info("View the second paused thread"); + await dbg.actions.selectThread(getContext(dbg), 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" + ); + assertPausedAtSourceAndLine(dbg, workerSource3.id, 10); + + info("StepOver in second worker and not the first"); + await stepOver(dbg); + assertPausedAtSourceAndLine(dbg, workerSource3.id, 11); + await dbg.actions.selectThread(getContext(dbg), thread1); + assertPausedAtSourceAndLine(dbg, workerSource2.id, 10); + + info("Resume both worker execution"); + await resume(dbg); + await dbg.actions.selectThread(getContext(dbg), thread2); + await resume(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)); +} + +function threadIsSelected(dbg, index) { + return assertClass(dbg, "threadsPaneItem", "selected", index); +} |