diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /dom/workers/test/xpcshell | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | dom/workers/test/xpcshell/data/chrome.manifest | 1 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/data/worker.js | 6 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/data/worker_fileReader.js | 7 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/test_ext_redirects_sw_scripts.js | 415 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/test_fileReader.js | 33 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/test_remoteworker_launch_new_process.js | 94 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/test_workers.js | 37 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/test_workers_clone_error.js | 42 | ||||
-rw-r--r-- | dom/workers/test/xpcshell/xpcshell.ini | 28 |
9 files changed, 663 insertions, 0 deletions
diff --git a/dom/workers/test/xpcshell/data/chrome.manifest b/dom/workers/test/xpcshell/data/chrome.manifest new file mode 100644 index 0000000000..611e81fd4e --- /dev/null +++ b/dom/workers/test/xpcshell/data/chrome.manifest @@ -0,0 +1 @@ +content workers ./ diff --git a/dom/workers/test/xpcshell/data/worker.js b/dom/workers/test/xpcshell/data/worker.js new file mode 100644 index 0000000000..6fb17798c6 --- /dev/null +++ b/dom/workers/test/xpcshell/data/worker.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +self.onmessage = function(msg) { + self.postMessage("OK"); +}; diff --git a/dom/workers/test/xpcshell/data/worker_fileReader.js b/dom/workers/test/xpcshell/data/worker_fileReader.js new file mode 100644 index 0000000000..fce6666316 --- /dev/null +++ b/dom/workers/test/xpcshell/data/worker_fileReader.js @@ -0,0 +1,7 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +self.onmessage = function(msg) { + var fr = new FileReader(); + self.postMessage("OK"); +}; diff --git a/dom/workers/test/xpcshell/test_ext_redirects_sw_scripts.js b/dom/workers/test/xpcshell/test_ext_redirects_sw_scripts.js new file mode 100644 index 0000000000..50525d5e8c --- /dev/null +++ b/dom/workers/test/xpcshell/test_ext_redirects_sw_scripts.js @@ -0,0 +1,415 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +const { TestUtils } = ChromeUtils.import( + "resource://testing-common/TestUtils.jsm" +); + +const { AddonTestUtils } = ChromeUtils.import( + "resource://testing-common/AddonTestUtils.jsm" +); + +const { ExtensionTestUtils } = ChromeUtils.import( + "resource://testing-common/ExtensionXPCShellUtils.jsm" +); + +const { createHttpServer } = AddonTestUtils; + +// Force ServiceWorkerRegistrar to init by calling do_get_profile. +// (This has to be called before AddonTestUtils.init, because it does +// also call do_get_profile internally but it doesn't notify +// profile-after-change). +do_get_profile(true); + +AddonTestUtils.init(this); +ExtensionTestUtils.init(this); + +const server = createHttpServer({ hosts: ["localhost"] }); + +server.registerPathHandler("/page.html", (request, response) => { + info(`/page.html is being requested: ${JSON.stringify(request)}`); + response.write(`<!DOCTYPE html>`); +}); + +server.registerPathHandler("/sw.js", (request, response) => { + info(`/sw.js is being requested: ${JSON.stringify(request)}`); + response.setHeader("Content-Type", "application/javascript"); + response.write(` + dump('Executing http://localhost/sw.js\\n'); + importScripts('sw-imported.js'); + dump('Executed importScripts from http://localhost/sw.js\\n'); + `); +}); + +server.registerPathHandler("/sw-imported.js", (request, response) => { + info(`/sw-imported.js is being requested: ${JSON.stringify(request)}`); + response.setHeader("Content-Type", "application/javascript"); + response.write(` + dump('importScript loaded from http://localhost/sw-imported.js\\n'); + self.onmessage = evt => evt.ports[0].postMessage('original-imported-script'); + `); +}); + +Services.prefs.setBoolPref("dom.serviceWorkers.testing.enabled", true); +// Make sure this test file doesn't run with the legacy behavior by +// setting explicitly the expected default value. +Services.prefs.setBoolPref( + "extensions.filterResponseServiceWorkerScript.disabled", + false +); +registerCleanupFunction(() => { + Services.prefs.clearUserPref("dom.serviceWorkers.testing.enabled"); + Services.prefs.clearUserPref( + "extensions.filterResponseServiceWorkerScript.disabled" + ); +}); + +// Helper function used to be sure to clear any data that a previous test case +// may have left (e.g. service worker registration, cached service worker +// scripts). +// +// NOTE: Given that xpcshell test are running isolated from each other (unlike +// mochitests), we can just clear every storage type supported by clear data +// (instead of cherry picking what we want to clear based on the test cases +// part of this test file). +async function ensureDataCleanup() { + info("Clear any service worker or data previous test cases may have left"); + await new Promise(resolve => + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, resolve) + ); +} + +// Note that the update algorithm (https://w3c.github.io/ServiceWorker/#update-algorithm) +// builds an "updatedResourceMap" as part of its check process. This means that only a +// single fetch will be performed for "sw-imported.js" as part of the update check and its +// resulting install invocation. The installation's call to importScripts when evaluated +// will load the script directly out of the Cache API. +function testSWUpdate(contentPage) { + return contentPage.spawn([], async () => { + const oldReg = await this.content.navigator.serviceWorker.ready; + const reg = await oldReg.update(); + const sw = reg.installing || reg.waiting || reg.active; + return new Promise(resolve => { + const { port1, port2 } = new MessageChannel(); + port1.onmessage = evt => resolve(evt.data); + sw.postMessage("worker-message", [port2]); + }); + }); +} + +add_task(async function test_extension_invalid_sw_scripts_redirect_ignored() { + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["<all_urls>", "webRequest", "webRequestBlocking"], + }, + background() { + browser.webRequest.onBeforeRequest.addListener( + req => { + if (req.url == "http://localhost/sw.js") { + const filter = browser.webRequest.filterResponseData(req.requestId); + filter.ondata = event => filter.write(event.data); + filter.onstop = event => filter.disconnect(); + filter.onerror = () => { + browser.test.sendMessage( + "filter-response-error:mainscript", + filter.error + ); + }; + return { + redirectUrl: browser.runtime.getURL("sw-unexpected-redirect.js"), + }; + } + + if (req.url == "http://localhost/sw-imported.js") { + const filter = browser.webRequest.filterResponseData(req.requestId); + filter.ondata = event => filter.write(event.data); + filter.onstop = event => filter.disconnect(); + filter.onerror = () => { + browser.test.sendMessage( + "filter-response-error:importscript", + filter.error + ); + }; + return { redirectUrl: "about:blank" }; + } + + return {}; + }, + { urls: ["http://localhost/sw.js", "http://localhost/sw-imported.js"] }, + ["blocking"] + ); + }, + files: { + "sw-unexpected-redirect.js": ` + dump('importScript redirected to moz-extension://UUID/sw-unexpected-redirect.js\\n'); + self.onmessage = evt => evt.ports[0].postMessage('sw-unexpected-redirect'); + `, + }, + }); + + // Start the test extension to redirect importScripts requests. + await extension.startup(); + + function awaitConsoleMessage(regexp) { + return new Promise(resolve => { + Services.console.registerListener(function listener(message) { + if (regexp.test(message.message)) { + Services.console.unregisterListener(listener); + resolve(message); + } + }); + }); + } + + const awaitIgnoredMainScriptRedirect = awaitConsoleMessage( + /Invalid redirectUrl .* on service worker main script/ + ); + const awaitIgnoredImportScriptRedirect = awaitConsoleMessage( + /Invalid redirectUrl .* on service worker imported script/ + ); + + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://localhost/page.html" + ); + + // Register the worker while the test extension isn't loaded and cannot + // intercept and redirect the importedScripts requests. + info("Register service worker from a content webpage"); + let workerMessage = await contentPage.spawn([], async () => { + const reg = await this.content.navigator.serviceWorker.register("/sw.js"); + return new Promise(resolve => { + const { port1, port2 } = new MessageChannel(); + port1.onmessage = evt => resolve(evt.data); + const sw = reg.active || reg.waiting || reg.installing; + sw.postMessage("worker-message", [port2]); + }); + }); + + equal( + workerMessage, + "original-imported-script", + "Got expected worker reply (importScripts not intercepted)" + ); + + info("Wait for the expected error message on main script redirect"); + const errorMsg = await awaitIgnoredMainScriptRedirect; + ok(errorMsg?.message, `Got error message: ${errorMsg?.message}`); + ok( + errorMsg?.message?.includes(extension.id), + "error message should include the addon id" + ); + ok( + errorMsg?.message?.includes("http://localhost/sw.js"), + "error message should include the sw main script url" + ); + + info("Wait for the expected error message on import script redirect"); + const errorMsg2 = await awaitIgnoredImportScriptRedirect; + ok(errorMsg2?.message, `Got error message: ${errorMsg2?.message}`); + ok( + errorMsg2?.message?.includes(extension.id), + "error message should include the addon id" + ); + ok( + errorMsg2?.message?.includes("http://localhost/sw-imported.js"), + "error message should include the sw main script url" + ); + + info("Wait filterResponse error on main script"); + equal( + await extension.awaitMessage("filter-response-error:mainscript"), + "Invalid request ID", + "Got expected error on main script" + ); + info("Wait filterResponse error on import script"); + equal( + await extension.awaitMessage("filter-response-error:importscript"), + "Invalid request ID", + "Got expected error on import script" + ); + + await extension.unload(); + await contentPage.close(); +}); + +add_task(async function test_filter_sw_script() { + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: [ + "<all_urls>", + "webRequest", + "webRequestBlocking", + "webRequestFilterResponse.serviceWorkerScript", + ], + }, + background() { + browser.webRequest.onBeforeRequest.addListener( + req => { + if (req.url == "http://localhost/sw.js") { + const filter = browser.webRequest.filterResponseData(req.requestId); + let decoder = new TextDecoder("utf-8"); + let encoder = new TextEncoder(); + filter.ondata = event => { + let str = decoder.decode(event.data, { stream: true }); + browser.test.log(`Got filter ondata event: ${str}\n`); + str = ` + dump('Executing filterResponse script for http://localhost/sw.js\\n'); + self.onmessage = evt => evt.ports[0].postMessage('filter-response-script'); + dump('Executed firlterResponse script for http://localhost/sw.js\\n'); + `; + filter.write(encoder.encode(str)); + filter.disconnect(); + }; + } + + return {}; + }, + { urls: ["http://localhost/sw.js", "http://localhost/sw-imported.js"] }, + ["blocking"] + ); + }, + }); + + // Start the test extension to redirect importScripts requests. + await extension.startup(); + + await ensureDataCleanup(); + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://localhost/page.html" + ); + + let workerMessage = await contentPage.spawn([], async () => { + const reg = await this.content.navigator.serviceWorker.register("/sw.js"); + return new Promise(resolve => { + const { port1, port2 } = new MessageChannel(); + port1.onmessage = evt => resolve(evt.data); + const sw = reg.active || reg.waiting || reg.installing; + sw.postMessage("worker-message", [port2]); + }); + }); + + equal( + workerMessage, + "filter-response-script", + "Got expected worker reply (filterResponse script)" + ); + + await extension.unload(); + workerMessage = await testSWUpdate(contentPage); + equal( + workerMessage, + "original-imported-script", + "Got expected worker reply (original script)" + ); + + await contentPage.close(); +}); + +add_task(async function test_extension_redirect_sw_imported_script() { + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["<all_urls>", "webRequest", "webRequestBlocking"], + web_accessible_resources: ["sw-imported-1.js", "sw-imported-2.js"], + }, + background() { + let i = 1; + browser.webRequest.onBeforeRequest.addListener( + req => { + browser.test.log( + "Extension is redirecting http://localhost/sw-imported.js" + ); + browser.test.sendMessage("request-redirected"); + return { + redirectUrl: browser.runtime.getURL(`sw-imported-${i++}.js`), + }; + }, + { urls: ["http://localhost/sw-imported.js"] }, + ["blocking"] + ); + }, + files: { + "sw-imported-1.js": ` + dump('importScript redirected to moz-extension://UUID/sw-imported1.js \\n'); + self.onmessage = evt => evt.ports[0].postMessage('redirected-imported-script-1'); + `, + "sw-imported-2.js": ` + dump('importScript redirected to moz-extension://UUID/sw-imported2.js \\n'); + self.onmessage = evt => evt.ports[0].postMessage('redirected-imported-script-2'); + `, + }, + }); + + await ensureDataCleanup(); + const contentPage = await ExtensionTestUtils.loadContentPage( + "http://localhost/page.html" + ); + + // Register the worker while the test extension isn't loaded and cannot + // intercept and redirect the importedScripts requests. + let workerMessage = await contentPage.spawn([], async () => { + const reg = await this.content.navigator.serviceWorker.register("/sw.js"); + return new Promise(resolve => { + const { port1, port2 } = new MessageChannel(); + port1.onmessage = evt => resolve(evt.data); + const sw = reg.active || reg.waiting || reg.installing; + sw.postMessage("worker-message", [port2]); + }); + }); + + equal( + workerMessage, + "original-imported-script", + "Got expected worker reply (importScripts not intercepted)" + ); + + // Start the test extension to redirect importScripts requests. + await extension.startup(); + + // Trigger an update on the registered service worker, then assert that the + // reply got is coming from the script where the extension is redirecting the + // request. + info("Update service worker and expect extension script to reply"); + workerMessage = await testSWUpdate(contentPage); + await extension.awaitMessage("request-redirected"); + equal( + workerMessage, + "redirected-imported-script-1", + "Got expected worker reply (importScripts redirected to moz-extension url)" + ); + + // Trigger a new update of the registered service worker, then assert that the + // reply got is coming from a different script where the extension is + // redirecting the second request (this confirms that the extension can + // intercept and can change the redirected imported scripts on new service + // worker updates). + info("Update service worker and expect new extension script to reply"); + workerMessage = await testSWUpdate(contentPage); + await extension.awaitMessage("request-redirected"); + equal( + workerMessage, + "redirected-imported-script-2", + "Got expected worker reply (importScripts redirected to moz-extension url again)" + ); + + // Uninstall the extension and trigger one more update of the registered + // service worker, then assert that the reply got is the one coming from the + // server (because difference from the one got from the cache). + // This verify that the service worker are updated as expected after the + // extension is uninstalled and the worker is not stuck on the script where + // the extension did redirect the request the last time. + info( + "Unload extension, update service worker and expect original script to reply" + ); + await extension.unload(); + workerMessage = await testSWUpdate(contentPage); + equal( + workerMessage, + "original-imported-script", + "Got expected worker reply (importScripts not intercepted)" + ); + + await contentPage.close(); +}); diff --git a/dom/workers/test/xpcshell/test_fileReader.js b/dom/workers/test/xpcshell/test_fileReader.js new file mode 100644 index 0000000000..84e91c6c02 --- /dev/null +++ b/dom/workers/test/xpcshell/test_fileReader.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Worker must be loaded from a chrome:// uri, not a file:// +// uri, so we first need to load it. +var WORKER_SOURCE_URI = "chrome://workers/content/worker_fileReader.js"; +do_load_manifest("data/chrome.manifest"); + +function talk_with_worker(worker) { + return new Promise((resolve, reject) => { + worker.onmessage = function(event) { + let success = true; + if (event.data == "OK") { + resolve(); + } else { + success = false; + reject(event); + } + Assert.ok(success); + worker.terminate(); + }; + worker.onerror = function(event) { + let error = new Error(event.message, event.filename, event.lineno); + worker.terminate(); + reject(error); + }; + worker.postMessage("START"); + }); +} + +add_task(function test_chrome_worker() { + return talk_with_worker(new ChromeWorker(WORKER_SOURCE_URI)); +}); diff --git a/dom/workers/test/xpcshell/test_remoteworker_launch_new_process.js b/dom/workers/test/xpcshell/test_remoteworker_launch_new_process.js new file mode 100644 index 0000000000..953940e39f --- /dev/null +++ b/dom/workers/test/xpcshell/test_remoteworker_launch_new_process.js @@ -0,0 +1,94 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const { TestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TestUtils.sys.mjs" +); + +const { AddonTestUtils } = ChromeUtils.import( + "resource://testing-common/AddonTestUtils.jsm" +); +const { createHttpServer } = AddonTestUtils; + +// Force ServiceWorkerRegistrar to init by calling do_get_profile. +// (This has to be called before AddonTestUtils.init, because it does +// also call do_get_profile internally but it doesn't notify +// profile-after-change). +do_get_profile(true); + +AddonTestUtils.init(this); + +const server = createHttpServer({ hosts: ["localhost"] }); + +server.registerPathHandler("/sw.js", (request, response) => { + info(`/sw.js is being requested: ${JSON.stringify(request)}`); + response.setHeader("Content-Type", "application/javascript"); + response.write(""); +}); + +add_task(async function setup_prefs() { + equal( + Services.prefs.getBoolPref("browser.tabs.remote.autostart"), + true, + "e10s is expected to be enabled" + ); + + // Enable nsIServiceWorkerManager.registerForTest. + Services.prefs.setBoolPref("dom.serviceWorkers.testing.enabled", true); + + registerCleanupFunction(() => { + Services.prefs.clearUserPref("dom.serviceWorkers.testing.enabled"); + }); +}); + +/** + * This test installs a ServiceWorker via test API and verify that the install + * process spawns a new process. (Normally ServiceWorker installation won't + * cause a new content process to be spawned because the call to register must + * be coming from within an existing content process, but the registerForTest + * API allows us to bypass this restriction.) + * + * This models the real-world situation of a push notification being received + * from the network which results in a ServiceWorker being spawned without their + * necessarily being an existing content process to host it (especially under Fission). + */ +add_task(async function launch_remoteworkers_in_new_processes() { + const swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService( + Ci.nsIServiceWorkerManager + ); + + const ssm = Services.scriptSecurityManager; + + const initialChildCount = Services.ppmm.childCount; + + // A test service worker that should spawn a regular web content child process. + const swRegInfoWeb = await swm.registerForTest( + ssm.createContentPrincipal(Services.io.newURI("http://localhost"), {}), + "http://localhost/scope", + "http://localhost/sw.js" + ); + swRegInfoWeb.QueryInterface(Ci.nsIServiceWorkerRegistrationInfo); + + info( + `web content service worker registered: ${JSON.stringify({ + principal: swRegInfoWeb.principal.spec, + scope: swRegInfoWeb.scope, + })}` + ); + + info("Wait new process to be launched"); + await TestUtils.waitForCondition(() => { + return Services.ppmm.childCount - initialChildCount >= 1; + }, "wait for a new child processes to be started"); + + // Wait both workers to become active to be sure that. besides spawning + // the new child processes as expected, the two remote worker have been + // able to run successfully (in other word their remote worker data did + // pass successfull the IsRemoteTypeAllowed check in RemoteworkerChild). + info("Wait for webcontent worker to become active"); + await TestUtils.waitForCondition( + () => swRegInfoWeb.activeWorker, + `wait workers for scope ${swRegInfoWeb.scope} to be active` + ); +}); diff --git a/dom/workers/test/xpcshell/test_workers.js b/dom/workers/test/xpcshell/test_workers.js new file mode 100644 index 0000000000..d070022664 --- /dev/null +++ b/dom/workers/test/xpcshell/test_workers.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Worker must be loaded from a chrome:// uri, not a file:// +// uri, so we first need to load it. +var WORKER_SOURCE_URI = "chrome://workers/content/worker.js"; +do_load_manifest("data/chrome.manifest"); + +function talk_with_worker(worker) { + return new Promise((resolve, reject) => { + worker.onmessage = function(event) { + let success = true; + if (event.data == "OK") { + resolve(); + } else { + success = false; + reject(event); + } + Assert.ok(success); + worker.terminate(); + }; + worker.onerror = function(event) { + let error = new Error(event.message, event.filename, event.lineno); + worker.terminate(); + reject(error); + }; + worker.postMessage("START"); + }); +} + +add_task(function test_chrome_worker() { + return talk_with_worker(new ChromeWorker(WORKER_SOURCE_URI)); +}); + +add_task(function test_worker() { + return talk_with_worker(new Worker(WORKER_SOURCE_URI)); +}); diff --git a/dom/workers/test/xpcshell/test_workers_clone_error.js b/dom/workers/test/xpcshell/test_workers_clone_error.js new file mode 100644 index 0000000000..32733bad01 --- /dev/null +++ b/dom/workers/test/xpcshell/test_workers_clone_error.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Worker must be loaded from a chrome:// uri, not a file:// +// uri, so we first need to load it. +var WORKER_SOURCE_URI = "chrome://workers/content/worker.js"; +do_load_manifest("data/chrome.manifest"); + +function talk_with_worker(worker) { + return new Promise((resolve, reject) => { + worker.onmessage = function(event) { + let success = true; + if (event.data == "OK") { + resolve(); + } else { + success = false; + reject(event); + } + Assert.ok(success); + worker.terminate(); + }; + worker.onerror = function(event) { + let error = new Error(event.message, event.filename, event.lineno); + worker.terminate(); + reject(error); + }; + + try { + eval("/"); + } catch (e) { + worker.postMessage(new ClonedErrorHolder(e)); + } + }); +} + +add_task(function test_chrome_worker() { + return talk_with_worker(new ChromeWorker(WORKER_SOURCE_URI)); +}); + +add_task(function test_worker() { + return talk_with_worker(new Worker(WORKER_SOURCE_URI)); +}); diff --git a/dom/workers/test/xpcshell/xpcshell.ini b/dom/workers/test/xpcshell/xpcshell.ini new file mode 100644 index 0000000000..7b24396197 --- /dev/null +++ b/dom/workers/test/xpcshell/xpcshell.ini @@ -0,0 +1,28 @@ +[DEFAULT] +head = +skip-if = toolkit == 'android' +support-files = + data/worker.js + data/worker_fileReader.js + data/chrome.manifest + +[test_ext_redirects_sw_scripts.js] +# The following firefox-appdir make sure that ExtensionTestUtils.loadExtension +# will be able to successfully start the background page (it does fail without +# it because there wouldn't be a global.tabTracker implementation as we would +# expect in a real Firefox, Fenix or Thunderbird instance). +firefox-appdir = browser +[test_workers.js] +[test_workers_clone_error.js] +[test_fileReader.js] +[test_remoteworker_launch_new_process.js] +# The following firefox-appdir make sure that this xpcshell test will run +# with e10s enabled (which is needed to make sure that the test case is +# going to launch the expected new processes) +firefox-appdir = browser +# Disable plugin loading to make it rr able to record and replay this test. +prefs = + plugin.disable=true +skip-if = + socketprocess_networking # Bug 1759035 + |