browser_target_command_tab_workers.js (11635B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test the TargetCommand API around workers 7 8 const FISSION_TEST_URL = URL_ROOT_SSL + "fission_document.html"; 9 const IFRAME_FILE = "fission_iframe.html"; 10 const REMOTE_IFRAME_URL = URL_ROOT_ORG_SSL + IFRAME_FILE; 11 const IFRAME_URL = URL_ROOT_SSL + IFRAME_FILE; 12 const WORKER_FILE = "test_worker.js"; 13 const WORKER_URL = URL_ROOT_SSL + WORKER_FILE; 14 const REMOTE_IFRAME_WORKER_URL = URL_ROOT_ORG_SSL + WORKER_FILE; 15 16 add_task(async function () { 17 // Disable the preloaded process as it creates processes intermittently 18 // which forces the emission of RDP requests we aren't correctly waiting for. 19 await pushPref("dom.ipc.processPrelaunch.enabled", false); 20 21 // The WorkerDebuggerManager#getWorkerDebuggerEnumerator method we're using to retrieve 22 // workers loops through _all_ the workers in the process, which means it goes over workers 23 // from other tabs as well. Here we add a few tabs that are not going to be used in the 24 // test, just to check that their workers won't be retrieved by getAllTargets/watchTargets. 25 await addTab(`${FISSION_TEST_URL}?id=first-untargetted-tab&noServiceWorker`); 26 await addTab(`${FISSION_TEST_URL}?id=second-untargetted-tab&noServiceWorker`); 27 28 info("Test TargetCommand against workers via a tab target"); 29 const tab = await addTab(`${FISSION_TEST_URL}?&noServiceWorker`); 30 31 // Create a TargetCommand for the tab 32 const commands = await CommandsFactory.forTab(tab); 33 const targetCommand = commands.targetCommand; 34 35 // Workaround to allow listening for workers in the content toolbox 36 // without the fission preferences 37 targetCommand.listenForWorkers = true; 38 39 await commands.targetCommand.startListening(); 40 41 const { TYPES } = targetCommand; 42 43 info("Check that getAllTargets only returns dedicated workers"); 44 const workers = await targetCommand.getAllTargets([ 45 TYPES.WORKER, 46 TYPES.SHARED_WORKER, 47 ]); 48 49 // XXX: This should be modified in Bug 1607778, where we plan to add support for shared workers. 50 is(workers.length, 2, "Retrieved two worker…"); 51 const mainPageWorker = workers.find( 52 worker => worker.url == `${WORKER_URL}#simple-worker` 53 ); 54 is( 55 mainPageWorker.name, 56 "Simple worker", 57 "The custom worker name is exposed on the target object" 58 ); 59 const iframeWorker = workers.find(worker => { 60 return worker.url == `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-iframe`; 61 }); 62 ok(mainPageWorker, "…the dedicated worker on the main page"); 63 ok(iframeWorker, "…and the dedicated worker on the iframe"); 64 65 info( 66 "Assert that watchTargets will call the create callback for existing dedicated workers" 67 ); 68 const targets = []; 69 const destroyedTargets = []; 70 const onAvailable = async ({ targetFront }) => { 71 info(`onAvailable called for ${targetFront.url}`); 72 is( 73 targetFront.targetType, 74 TYPES.WORKER, 75 "We are only notified about worker targets" 76 ); 77 ok(!targetFront.isTopLevel, "The workers are never top level"); 78 targets.push(targetFront); 79 info(`Handled ${targets.length} targets\n`); 80 }; 81 const onDestroyed = async ({ targetFront }) => { 82 is( 83 targetFront.targetType, 84 TYPES.WORKER, 85 "We are only notified about worker targets" 86 ); 87 ok(!targetFront.isTopLevel, "The workers are never top level"); 88 destroyedTargets.push(targetFront); 89 }; 90 91 await targetCommand.watchTargets({ 92 types: [TYPES.WORKER, TYPES.SHARED_WORKER], 93 onAvailable, 94 onDestroyed, 95 }); 96 97 // XXX: This should be modified in Bug 1607778, where we plan to add support for shared workers. 98 info("Check that watched targets return the same fronts as getAllTargets"); 99 is(targets.length, 2, "watcheTargets retrieved 2 worker…"); 100 const mainPageWorkerTarget = targets.find(t => t === mainPageWorker); 101 const iframeWorkerTarget = targets.find(t => t === iframeWorker); 102 103 ok( 104 mainPageWorkerTarget, 105 "…the dedicated worker in main page, which is the same front we received from getAllTargets" 106 ); 107 ok( 108 iframeWorkerTarget, 109 "…the dedicated worker in iframe, which is the same front we received from getAllTargets" 110 ); 111 112 info("Spawn workers in main page and iframe"); 113 await SpecialPowers.spawn(tab.linkedBrowser, [WORKER_FILE], workerUrl => { 114 // Put the worker on the global so we can access it later 115 content.spawnedWorker = new content.Worker(`${workerUrl}#spawned-worker`); 116 const iframe = content.document.querySelector("iframe"); 117 SpecialPowers.spawn(iframe, [workerUrl], innerWorkerUrl => { 118 // Put the worker on the global so we can access it later 119 content.spawnedWorker = new content.Worker( 120 `${innerWorkerUrl}#spawned-worker-in-iframe` 121 ); 122 }); 123 }); 124 125 await waitFor( 126 () => targets.length === 4, 127 "Wait for the target list to notify us about the spawned worker" 128 ); 129 const mainPageSpawnedWorkerTarget = targets.find( 130 innerTarget => innerTarget.url == `${WORKER_URL}#spawned-worker` 131 ); 132 ok(mainPageSpawnedWorkerTarget, "Retrieved spawned worker"); 133 const iframeSpawnedWorkerTarget = targets.find( 134 innerTarget => 135 innerTarget.url == `${REMOTE_IFRAME_WORKER_URL}#spawned-worker-in-iframe` 136 ); 137 ok(iframeSpawnedWorkerTarget, "Retrieved spawned worker in iframe"); 138 139 await wait(100); 140 141 info( 142 "Check that the target list calls onDestroy when a worker is terminated" 143 ); 144 await SpecialPowers.spawn(tab.linkedBrowser, [], () => { 145 content.spawnedWorker.terminate(); 146 content.spawnedWorker = null; 147 148 SpecialPowers.spawn(content.document.querySelector("iframe"), [], () => { 149 content.spawnedWorker.terminate(); 150 content.spawnedWorker = null; 151 }); 152 }); 153 await waitFor( 154 () => 155 destroyedTargets.includes(mainPageSpawnedWorkerTarget) && 156 destroyedTargets.includes(iframeSpawnedWorkerTarget), 157 "Wait for the target list to notify us about the terminated workers" 158 ); 159 160 ok( 161 true, 162 "The target list handled the terminated workers (from the main page and the iframe)" 163 ); 164 165 info( 166 "Check that reloading the page will notify about the terminated worker and the new existing one" 167 ); 168 const targetsCountBeforeReload = targets.length; 169 await reloadBrowser(); 170 171 await waitFor(() => { 172 return ( 173 destroyedTargets.includes(mainPageWorkerTarget) && 174 destroyedTargets.includes(iframeWorkerTarget) 175 ); 176 }, `Wait for the target list to notify us about the terminated workers when reloading`); 177 ok( 178 true, 179 "The target list notified us about all the expected workers being destroyed when reloading" 180 ); 181 182 await waitFor( 183 () => targets.length === targetsCountBeforeReload + 2, 184 "Wait for the target list to notify us about the new workers after reloading" 185 ); 186 187 const mainPageWorkerTargetAfterReload = targets.find( 188 t => t !== mainPageWorkerTarget && t.url == `${WORKER_URL}#simple-worker` 189 ); 190 const iframeWorkerTargetAfterReload = targets.find( 191 t => 192 t !== iframeWorkerTarget && 193 t.url == `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-iframe` 194 ); 195 196 ok( 197 mainPageWorkerTargetAfterReload, 198 "The target list handled the worker created once the page navigated" 199 ); 200 ok( 201 iframeWorkerTargetAfterReload, 202 "The target list handled the worker created in the iframe once the page navigated" 203 ); 204 205 const targetCount = targets.length; 206 207 info( 208 "Check that when removing an iframe we're notified about its workers being terminated" 209 ); 210 await SpecialPowers.spawn(tab.linkedBrowser, [], () => { 211 content.document.querySelector("iframe").remove(); 212 }); 213 await waitFor(() => { 214 return destroyedTargets.includes(iframeWorkerTargetAfterReload); 215 }, `Wait for the target list to notify us about the terminated workers when removing an iframe`); 216 217 info("Check that target list handles adding iframes with workers"); 218 const iframeUrl = `${IFRAME_URL}?noServiceWorker=true&hashSuffix=in-created-iframe`; 219 const remoteIframeUrl = `${REMOTE_IFRAME_URL}?noServiceWorker=true&hashSuffix=in-created-remote-iframe`; 220 221 await SpecialPowers.spawn( 222 tab.linkedBrowser, 223 [iframeUrl, remoteIframeUrl], 224 (url, remoteUrl) => { 225 const firstIframe = content.document.createElement("iframe"); 226 content.document.body.append(firstIframe); 227 firstIframe.src = url + "-1"; 228 229 const secondIframe = content.document.createElement("iframe"); 230 content.document.body.append(secondIframe); 231 secondIframe.src = url + "-2"; 232 233 const firstRemoteIframe = content.document.createElement("iframe"); 234 content.document.body.append(firstRemoteIframe); 235 firstRemoteIframe.src = remoteUrl + "-1"; 236 237 const secondRemoteIframe = content.document.createElement("iframe"); 238 content.document.body.append(secondRemoteIframe); 239 secondRemoteIframe.src = remoteUrl + "-2"; 240 } 241 ); 242 243 // It's important to check the length of `targets` here to ensure we don't get unwanted 244 // worker targets. 245 await waitFor( 246 () => targets.length === targetCount + 4, 247 "Wait for the target list to notify us about the workers in the new iframes" 248 ); 249 const firstSpawnedIframeWorkerTarget = targets.find( 250 worker => worker.url == `${WORKER_URL}#simple-worker-in-created-iframe-1` 251 ); 252 const secondSpawnedIframeWorkerTarget = targets.find( 253 worker => worker.url == `${WORKER_URL}#simple-worker-in-created-iframe-2` 254 ); 255 const firstSpawnedRemoteIframeWorkerTarget = targets.find( 256 worker => 257 worker.url == 258 `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-created-remote-iframe-1` 259 ); 260 const secondSpawnedRemoteIframeWorkerTarget = targets.find( 261 worker => 262 worker.url == 263 `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-created-remote-iframe-2` 264 ); 265 266 ok( 267 firstSpawnedIframeWorkerTarget, 268 "The target list handled the worker in the first new same-origin iframe" 269 ); 270 ok( 271 secondSpawnedIframeWorkerTarget, 272 "The target list handled the worker in the second new same-origin iframe" 273 ); 274 ok( 275 firstSpawnedRemoteIframeWorkerTarget, 276 "The target list handled the worker in the first new remote iframe" 277 ); 278 ok( 279 secondSpawnedRemoteIframeWorkerTarget, 280 "The target list handled the worker in the second new remote iframe" 281 ); 282 283 info("Check that navigating away does destroy all targets"); 284 BrowserTestUtils.startLoadingURIString( 285 tab.linkedBrowser, 286 "data:text/html,<meta charset=utf8>Away" 287 ); 288 289 await waitFor( 290 () => destroyedTargets.length === targets.length, 291 "Wait for all the targets to be reported as destroyed" 292 ); 293 294 ok( 295 destroyedTargets.includes(mainPageWorkerTargetAfterReload), 296 "main page worker target was destroyed" 297 ); 298 ok( 299 destroyedTargets.includes(firstSpawnedIframeWorkerTarget), 300 "first spawned same-origin iframe worker target was destroyed" 301 ); 302 ok( 303 destroyedTargets.includes(secondSpawnedIframeWorkerTarget), 304 "second spawned same-origin iframe worker target was destroyed" 305 ); 306 ok( 307 destroyedTargets.includes(firstSpawnedRemoteIframeWorkerTarget), 308 "first spawned remote iframe worker target was destroyed" 309 ); 310 ok( 311 destroyedTargets.includes(secondSpawnedRemoteIframeWorkerTarget), 312 "second spawned remote iframe worker target was destroyed" 313 ); 314 315 targetCommand.unwatchTargets({ 316 types: [TYPES.WORKER, TYPES.SHARED_WORKER], 317 onAvailable, 318 onDestroyed, 319 }); 320 targetCommand.destroy(); 321 322 info("Unregister service workers so they don't appear in other tests."); 323 await unregisterAllServiceWorkers(commands.client); 324 325 BrowserTestUtils.removeTab(tab); 326 await commands.destroy(); 327 });