browser_dbg-windowless-workers.js (5421B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 // Test basic worker functionality: the main thread and worker can be 6 // separately controlled from the same debugger. 7 8 "use strict"; 9 10 add_task(async function () { 11 await pushPref("devtools.debugger.threads-visible", true); 12 13 const dbg = await initDebugger( 14 "doc-windowless-workers.html", 15 "simple-worker.js" 16 ); 17 const mainThread = dbg.toolbox.threadFront.actor; 18 19 await waitForThreadCount(dbg, 2); 20 const workers = dbg.selectors.getThreads(); 21 Assert.equal(workers.length, 2, "Got two workers"); 22 const thread1 = workers[0].actor; 23 const thread2 = workers[1].actor; 24 25 const mainThreadSource = findSource(dbg, "doc-windowless-workers.html"); 26 27 info("Pause in the main thread"); 28 assertNotPaused(dbg); 29 await dbg.actions.breakOnNext(); 30 await waitForPaused(dbg, "doc-windowless-workers.html"); 31 await assertPausedAtSourceAndLine(dbg, mainThreadSource.id, 10); 32 threadIsSelected(dbg, 1); 33 34 info("Pause in the first worker"); 35 await dbg.actions.selectThread(thread1); 36 assertNotPaused(dbg); 37 await dbg.actions.breakOnNext(); 38 await waitForPaused(dbg, "simple-worker.js"); 39 threadIsSelected(dbg, 2); 40 const workerSource2 = dbg.selectors.getSelectedSource(); 41 await assertPausedAtSourceAndLine(dbg, workerSource2.id, 3); 42 43 info("Add a watch expression and view the value"); 44 await addExpression(dbg, "count"); 45 is(getWatchExpressionLabel(dbg, 1), "count"); 46 const v = getWatchExpressionValue(dbg, 1); 47 Assert.equal(v, `${+v}`, "Value of count should be a number"); 48 49 info("StepOver in the first worker"); 50 await stepOver(dbg); 51 await assertPausedAtSourceAndLine(dbg, workerSource2.id, 4); 52 53 info("Ensure that the watch expression has updated"); 54 await waitUntil(() => { 55 const v2 = getWatchExpressionValue(dbg, 1); 56 return +v2 == +v + 1; 57 }); 58 59 info("Resume in the first worker"); 60 await resume(dbg); 61 assertNotPaused(dbg); 62 63 info("StepOver in the main thread"); 64 dbg.actions.selectThread(mainThread); 65 await stepOver(dbg); 66 await assertPausedAtSourceAndLine(dbg, mainThreadSource.id, 11); 67 68 info("Resume in the mainThread"); 69 await resume(dbg); 70 assertNotPaused(dbg); 71 72 info("Pause in both workers"); 73 await addBreakpoint(dbg, "simple-worker.js", 10); 74 invokeInTab("sayHello"); 75 76 info("Wait for both workers to pause"); 77 // When a thread pauses the current thread changes, 78 // and we don't want to get confused. 79 await waitForPausedThread(dbg, thread1); 80 await waitForPausedThread(dbg, thread2); 81 threadIsPaused(dbg, 2); 82 threadIsPaused(dbg, 3); 83 84 info("View the first paused thread"); 85 dbg.actions.selectThread(thread1); 86 await waitForPaused(dbg); 87 await assertPausedAtSourceAndLine(dbg, workerSource2.id, 10); 88 89 info("View the second paused thread"); 90 await dbg.actions.selectThread(thread2); 91 threadIsSelected(dbg, 3); 92 await waitForPaused(dbg); 93 const workerSource3 = dbg.selectors.getSelectedSource(); 94 is( 95 workerSource2, 96 workerSource3, 97 "The selected source is the same as we have one source per URL" 98 ); 99 await assertPausedAtSourceAndLine(dbg, workerSource3.id, 10); 100 101 info("StepOver in second worker and not the first"); 102 await stepOver(dbg); 103 await assertPausedAtSourceAndLine(dbg, workerSource3.id, 11); 104 await dbg.actions.selectThread(thread1); 105 await assertPausedAtSourceAndLine(dbg, workerSource2.id, 10); 106 107 info("Resume both worker execution"); 108 await resume(dbg); 109 assertNotPaused(dbg); 110 await dbg.actions.selectThread(thread2); 111 await resume(dbg); 112 assertNotPaused(dbg); 113 114 let sourceActors = dbg.selectors.getSourceActorsForSource(workerSource3.id); 115 is( 116 sourceActors.length, 117 2, 118 "There is one source actor per thread for the worker source" 119 ); 120 info( 121 "Terminate the first worker and wait for having only the second worker in threads list" 122 ); 123 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { 124 content.wrappedJSObject.worker1.terminate(); 125 }); 126 await waitForThreadCount(dbg, 1); 127 sourceActors = dbg.selectors.getSourceActorsForSource(workerSource3.id); 128 is( 129 sourceActors.length, 130 1, 131 "After the first worker is destroyed, we only have one source actor for the worker source" 132 ); 133 ok( 134 sourceExists(dbg, "simple-worker.js"), 135 "But we still have the worker source object" 136 ); 137 138 info("Terminate the second worker and wait for no more additional threads"); 139 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { 140 content.wrappedJSObject.worker2.terminate(); 141 }); 142 await waitForThreadCount(dbg, 0); 143 sourceActors = dbg.selectors.getSourceActorsForSource(workerSource3.id); 144 is( 145 sourceActors.length, 146 0, 147 "After all workers are destroyed, we no longer have any source actor" 148 ); 149 ok( 150 !sourceExists(dbg, "simple-worker.js"), 151 "And we no longer have the worker source" 152 ); 153 }); 154 155 function assertClass(dbg, selector, className, ...args) { 156 ok( 157 findElement(dbg, selector, ...args).classList.contains(className), 158 `${className} class exists` 159 ); 160 } 161 162 function threadIsPaused(dbg, index) { 163 return ok( 164 findElement(dbg, "threadsPaneItemPause", index), 165 `Thread ${index} is paused` 166 ); 167 } 168 169 function threadIsSelected(dbg, index) { 170 return assertClass(dbg, "threadsPaneItem", "selected", index); 171 }