summaryrefslogtreecommitdiffstats
path: root/devtools/shared/commands/target/tests/browser_target_command_tab_workers.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/commands/target/tests/browser_target_command_tab_workers.js')
-rw-r--r--devtools/shared/commands/target/tests/browser_target_command_tab_workers.js322
1 files changed, 322 insertions, 0 deletions
diff --git a/devtools/shared/commands/target/tests/browser_target_command_tab_workers.js b/devtools/shared/commands/target/tests/browser_target_command_tab_workers.js
new file mode 100644
index 0000000000..92f5629d4c
--- /dev/null
+++ b/devtools/shared/commands/target/tests/browser_target_command_tab_workers.js
@@ -0,0 +1,322 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the TargetCommand API around workers
+
+const FISSION_TEST_URL = URL_ROOT_SSL + "fission_document.html";
+const IFRAME_FILE = "fission_iframe.html";
+const REMOTE_IFRAME_URL = URL_ROOT_ORG_SSL + IFRAME_FILE;
+const IFRAME_URL = URL_ROOT_SSL + IFRAME_FILE;
+const WORKER_FILE = "test_worker.js";
+const WORKER_URL = URL_ROOT_SSL + WORKER_FILE;
+const REMOTE_IFRAME_WORKER_URL = URL_ROOT_ORG_SSL + WORKER_FILE;
+
+add_task(async function () {
+ // Disable the preloaded process as it creates processes intermittently
+ // which forces the emission of RDP requests we aren't correctly waiting for.
+ await pushPref("dom.ipc.processPrelaunch.enabled", false);
+
+ // The WorkerDebuggerManager#getWorkerDebuggerEnumerator method we're using to retrieve
+ // workers loops through _all_ the workers in the process, which means it goes over workers
+ // from other tabs as well. Here we add a few tabs that are not going to be used in the
+ // test, just to check that their workers won't be retrieved by getAllTargets/watchTargets.
+ await addTab(`${FISSION_TEST_URL}?id=first-untargetted-tab&noServiceWorker`);
+ await addTab(`${FISSION_TEST_URL}?id=second-untargetted-tab&noServiceWorker`);
+
+ info("Test TargetCommand against workers via a tab target");
+ const tab = await addTab(`${FISSION_TEST_URL}?&noServiceWorker`);
+
+ // Create a TargetCommand for the tab
+ const commands = await CommandsFactory.forTab(tab);
+ const targetCommand = commands.targetCommand;
+
+ // Workaround to allow listening for workers in the content toolbox
+ // without the fission preferences
+ targetCommand.listenForWorkers = true;
+
+ await commands.targetCommand.startListening();
+
+ const { TYPES } = targetCommand;
+
+ info("Check that getAllTargets only returns dedicated workers");
+ const workers = await targetCommand.getAllTargets([
+ TYPES.WORKER,
+ TYPES.SHARED_WORKER,
+ ]);
+
+ // XXX: This should be modified in Bug 1607778, where we plan to add support for shared workers.
+ is(workers.length, 2, "Retrieved two worker…");
+ const mainPageWorker = workers.find(
+ worker => worker.url == `${WORKER_URL}#simple-worker`
+ );
+ const iframeWorker = workers.find(worker => {
+ return worker.url == `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-iframe`;
+ });
+ ok(mainPageWorker, "…the dedicated worker on the main page");
+ ok(iframeWorker, "…and the dedicated worker on the iframe");
+
+ info(
+ "Assert that watchTargets will call the create callback for existing dedicated workers"
+ );
+ const targets = [];
+ const destroyedTargets = [];
+ const onAvailable = async ({ targetFront }) => {
+ info(`onAvailable called for ${targetFront.url}`);
+ is(
+ targetFront.targetType,
+ TYPES.WORKER,
+ "We are only notified about worker targets"
+ );
+ ok(!targetFront.isTopLevel, "The workers are never top level");
+ targets.push(targetFront);
+ info(`Handled ${targets.length} targets\n`);
+ };
+ const onDestroyed = async ({ targetFront }) => {
+ is(
+ targetFront.targetType,
+ TYPES.WORKER,
+ "We are only notified about worker targets"
+ );
+ ok(!targetFront.isTopLevel, "The workers are never top level");
+ destroyedTargets.push(targetFront);
+ };
+
+ await targetCommand.watchTargets({
+ types: [TYPES.WORKER, TYPES.SHARED_WORKER],
+ onAvailable,
+ onDestroyed,
+ });
+
+ // XXX: This should be modified in Bug 1607778, where we plan to add support for shared workers.
+ info("Check that watched targets return the same fronts as getAllTargets");
+ is(targets.length, 2, "watcheTargets retrieved 2 worker…");
+ const mainPageWorkerTarget = targets.find(t => t === mainPageWorker);
+ const iframeWorkerTarget = targets.find(t => t === iframeWorker);
+
+ ok(
+ mainPageWorkerTarget,
+ "…the dedicated worker in main page, which is the same front we received from getAllTargets"
+ );
+ ok(
+ iframeWorkerTarget,
+ "…the dedicated worker in iframe, which is the same front we received from getAllTargets"
+ );
+
+ info("Spawn workers in main page and iframe");
+ await SpecialPowers.spawn(tab.linkedBrowser, [WORKER_FILE], workerUrl => {
+ // Put the worker on the global so we can access it later
+ content.spawnedWorker = new content.Worker(`${workerUrl}#spawned-worker`);
+ const iframe = content.document.querySelector("iframe");
+ SpecialPowers.spawn(iframe, [workerUrl], innerWorkerUrl => {
+ // Put the worker on the global so we can access it later
+ content.spawnedWorker = new content.Worker(
+ `${innerWorkerUrl}#spawned-worker-in-iframe`
+ );
+ });
+ });
+
+ await waitFor(
+ () => targets.length === 4,
+ "Wait for the target list to notify us about the spawned worker"
+ );
+ const mainPageSpawnedWorkerTarget = targets.find(
+ innerTarget => innerTarget.url == `${WORKER_URL}#spawned-worker`
+ );
+ ok(mainPageSpawnedWorkerTarget, "Retrieved spawned worker");
+ const iframeSpawnedWorkerTarget = targets.find(
+ innerTarget =>
+ innerTarget.url == `${REMOTE_IFRAME_WORKER_URL}#spawned-worker-in-iframe`
+ );
+ ok(iframeSpawnedWorkerTarget, "Retrieved spawned worker in iframe");
+
+ await wait(100);
+
+ info(
+ "Check that the target list calls onDestroy when a worker is terminated"
+ );
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.spawnedWorker.terminate();
+ content.spawnedWorker = null;
+
+ SpecialPowers.spawn(content.document.querySelector("iframe"), [], () => {
+ content.spawnedWorker.terminate();
+ content.spawnedWorker = null;
+ });
+ });
+ await waitFor(
+ () =>
+ destroyedTargets.includes(mainPageSpawnedWorkerTarget) &&
+ destroyedTargets.includes(iframeSpawnedWorkerTarget),
+ "Wait for the target list to notify us about the terminated workers"
+ );
+
+ ok(
+ true,
+ "The target list handled the terminated workers (from the main page and the iframe)"
+ );
+
+ info(
+ "Check that reloading the page will notify about the terminated worker and the new existing one"
+ );
+ const targetsCountBeforeReload = targets.length;
+ await reloadBrowser();
+
+ await waitFor(() => {
+ return (
+ destroyedTargets.includes(mainPageWorkerTarget) &&
+ destroyedTargets.includes(iframeWorkerTarget)
+ );
+ }, `Wait for the target list to notify us about the terminated workers when reloading`);
+ ok(
+ true,
+ "The target list notified us about all the expected workers being destroyed when reloading"
+ );
+
+ await waitFor(
+ () => targets.length === targetsCountBeforeReload + 2,
+ "Wait for the target list to notify us about the new workers after reloading"
+ );
+
+ const mainPageWorkerTargetAfterReload = targets.find(
+ t => t !== mainPageWorkerTarget && t.url == `${WORKER_URL}#simple-worker`
+ );
+ const iframeWorkerTargetAfterReload = targets.find(
+ t =>
+ t !== iframeWorkerTarget &&
+ t.url == `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-iframe`
+ );
+
+ ok(
+ mainPageWorkerTargetAfterReload,
+ "The target list handled the worker created once the page navigated"
+ );
+ ok(
+ iframeWorkerTargetAfterReload,
+ "The target list handled the worker created in the iframe once the page navigated"
+ );
+
+ const targetCount = targets.length;
+
+ info(
+ "Check that when removing an iframe we're notified about its workers being terminated"
+ );
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.document.querySelector("iframe").remove();
+ });
+ await waitFor(() => {
+ return destroyedTargets.includes(iframeWorkerTargetAfterReload);
+ }, `Wait for the target list to notify us about the terminated workers when removing an iframe`);
+
+ info("Check that target list handles adding iframes with workers");
+ const iframeUrl = `${IFRAME_URL}?noServiceWorker=true&hashSuffix=in-created-iframe`;
+ const remoteIframeUrl = `${REMOTE_IFRAME_URL}?noServiceWorker=true&hashSuffix=in-created-remote-iframe`;
+
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [iframeUrl, remoteIframeUrl],
+ (url, remoteUrl) => {
+ const firstIframe = content.document.createElement("iframe");
+ content.document.body.append(firstIframe);
+ firstIframe.src = url + "-1";
+
+ const secondIframe = content.document.createElement("iframe");
+ content.document.body.append(secondIframe);
+ secondIframe.src = url + "-2";
+
+ const firstRemoteIframe = content.document.createElement("iframe");
+ content.document.body.append(firstRemoteIframe);
+ firstRemoteIframe.src = remoteUrl + "-1";
+
+ const secondRemoteIframe = content.document.createElement("iframe");
+ content.document.body.append(secondRemoteIframe);
+ secondRemoteIframe.src = remoteUrl + "-2";
+ }
+ );
+
+ // It's important to check the length of `targets` here to ensure we don't get unwanted
+ // worker targets.
+ await waitFor(
+ () => targets.length === targetCount + 4,
+ "Wait for the target list to notify us about the workers in the new iframes"
+ );
+ const firstSpawnedIframeWorkerTarget = targets.find(
+ worker => worker.url == `${WORKER_URL}#simple-worker-in-created-iframe-1`
+ );
+ const secondSpawnedIframeWorkerTarget = targets.find(
+ worker => worker.url == `${WORKER_URL}#simple-worker-in-created-iframe-2`
+ );
+ const firstSpawnedRemoteIframeWorkerTarget = targets.find(
+ worker =>
+ worker.url ==
+ `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-created-remote-iframe-1`
+ );
+ const secondSpawnedRemoteIframeWorkerTarget = targets.find(
+ worker =>
+ worker.url ==
+ `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-created-remote-iframe-2`
+ );
+
+ ok(
+ firstSpawnedIframeWorkerTarget,
+ "The target list handled the worker in the first new same-origin iframe"
+ );
+ ok(
+ secondSpawnedIframeWorkerTarget,
+ "The target list handled the worker in the second new same-origin iframe"
+ );
+ ok(
+ firstSpawnedRemoteIframeWorkerTarget,
+ "The target list handled the worker in the first new remote iframe"
+ );
+ ok(
+ secondSpawnedRemoteIframeWorkerTarget,
+ "The target list handled the worker in the second new remote iframe"
+ );
+
+ info("Check that navigating away does destroy all targets");
+ BrowserTestUtils.startLoadingURIString(
+ tab.linkedBrowser,
+ "data:text/html,<meta charset=utf8>Away"
+ );
+
+ await waitFor(
+ () => destroyedTargets.length === targets.length,
+ "Wait for all the targets to be reported as destroyed"
+ );
+
+ ok(
+ destroyedTargets.includes(mainPageWorkerTargetAfterReload),
+ "main page worker target was destroyed"
+ );
+ ok(
+ destroyedTargets.includes(firstSpawnedIframeWorkerTarget),
+ "first spawned same-origin iframe worker target was destroyed"
+ );
+ ok(
+ destroyedTargets.includes(secondSpawnedIframeWorkerTarget),
+ "second spawned same-origin iframe worker target was destroyed"
+ );
+ ok(
+ destroyedTargets.includes(firstSpawnedRemoteIframeWorkerTarget),
+ "first spawned remote iframe worker target was destroyed"
+ );
+ ok(
+ destroyedTargets.includes(secondSpawnedRemoteIframeWorkerTarget),
+ "second spawned remote iframe worker target was destroyed"
+ );
+
+ targetCommand.unwatchTargets({
+ types: [TYPES.WORKER, TYPES.SHARED_WORKER],
+ onAvailable,
+ onDestroyed,
+ });
+ targetCommand.destroy();
+
+ info("Unregister service workers so they don't appear in other tests.");
+ await unregisterAllServiceWorkers(commands.client);
+
+ BrowserTestUtils.removeTab(tab);
+ await commands.destroy();
+});