diff options
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_contentscript_dynamic_registration.js')
-rw-r--r-- | toolkit/components/extensions/test/xpcshell/test_ext_contentscript_dynamic_registration.js | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_dynamic_registration.js b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_dynamic_registration.js new file mode 100644 index 0000000000..0133b5d86c --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_dynamic_registration.js @@ -0,0 +1,205 @@ +"use strict"; + +const server = createHttpServer(); +server.registerDirectory("/data/", do_get_file("data")); + +const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`; + +// ExtensionContent.jsm needs to know when it's running from xpcshell, to use +// the right timeout for content scripts executed at document_idle. +ExtensionTestUtils.mockAppInfo(); + +// Do not use preallocated processes. +Services.prefs.setBoolPref("dom.ipc.processPrelaunch.enabled", false); +// This is needed for Android. +Services.prefs.setIntPref("dom.ipc.keepProcessesAlive.web", 0); + +const makeExtension = ({ background, manifest }) => { + return ExtensionTestUtils.loadExtension({ + manifest: { + ...manifest, + permissions: + manifest.manifest_version === 3 ? ["scripting"] : ["http://*/*/*.html"], + }, + temporarilyInstalled: true, + background, + files: { + "script.js": () => { + browser.test.sendMessage( + `script-ran: ${location.pathname.split("/").pop()}` + ); + }, + "inject_browser.js": () => { + browser.userScripts.onBeforeScript.addListener(script => { + // Inject `browser.test.sendMessage()` so that it can be used in the + // `script.js` defined above when using "user scripts". + script.defineGlobals({ + browser: { + test: { + sendMessage(msg) { + browser.test.sendMessage(msg); + }, + }, + }, + }); + }); + }, + }, + }); +}; + +const verifyRegistrationWithNewProcess = async extension => { + // We override the `broadcast()` method to reliably verify Bug 1756495: when + // a new process is spawned while we register a content script, the script + // should be correctly registered and executed in this new process. Below, + // when we receive the `Extension:RegisterContentScripts`, we open a new tab + // (which is the "new process") and then we invoke the original "broadcast + // logic". The expected result is that the content script registered by the + // extension will run. + const originalBroadcast = Extension.prototype.broadcast; + + let broadcastCalledCount = 0; + let secondContentPage; + + extension.extension.broadcast = async function broadcast(msg, data) { + if (msg !== "Extension:RegisterContentScripts") { + return originalBroadcast.call(this, msg, data); + } + + broadcastCalledCount++; + Assert.equal( + 1, + broadcastCalledCount, + "broadcast override should be called once" + ); + + await originalBroadcast.call(this, msg, data); + + Assert.equal(extension.id, data.id, "got expected extension ID"); + Assert.equal(1, data.scripts.length, "expected 1 script to register"); + Assert.ok( + data.scripts[0].options.jsPaths[0].endsWith("script.js"), + "got expected js file" + ); + + const newPids = []; + const topic = "ipc:content-created"; + + let obs = (subject, topic, data) => { + newPids.push(parseInt(data, 10)); + }; + Services.obs.addObserver(obs, topic); + + secondContentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/dummy_page.html` + ); + + const { childID } = + secondContentPage.browsingContext.currentWindowGlobal.domProcess; + + Services.obs.removeObserver(obs, topic); + + // We expect to have a new process created for `secondContentPage`. + Assert.ok( + newPids.includes(childID), + `expected PID ${childID} to be in [${newPids.join(", ")}])` + ); + }; + + await extension.startup(); + await extension.awaitMessage("background-done"); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + + await Promise.all([ + extension.awaitMessage("script-ran: file_sample.html"), + extension.awaitMessage("script-ran: dummy_page.html"), + ]); + + // Unload extension first to avoid an issue on Windows platforms. + await extension.unload(); + await contentPage.close(); + await secondContentPage.close(); +}; + +add_task( + { + pref_set: [["extensions.manifestV3.enabled", true]], + }, + async function test_scripting_registerContentScripts() { + let extension = makeExtension({ + manifest: { + manifest_version: 3, + host_permissions: ["<all_urls>"], + granted_host_permissions: true, + }, + async background() { + const script = { + id: "a-script", + js: ["script.js"], + matches: ["http://*/*/*.html"], + persistAcrossSessions: false, + }; + + await browser.scripting.registerContentScripts([script]); + + browser.test.sendMessage("background-done"); + }, + }); + + await verifyRegistrationWithNewProcess(extension); + } +); + +add_task( + { + // We don't have WebIDL bindings for `browser.contentScripts`. + skip_if: () => ExtensionTestUtils.isInBackgroundServiceWorkerTests(), + }, + async function test_contentScripts_register() { + let extension = makeExtension({ + manifest: { + manifest_version: 2, + }, + async background() { + await browser.contentScripts.register({ + js: [{ file: "script.js" }], + matches: ["http://*/*/*.html"], + }); + + browser.test.sendMessage("background-done"); + }, + }); + + await verifyRegistrationWithNewProcess(extension); + } +); + +add_task( + { + // We don't have WebIDL bindings for `browser.userScripts`. + skip_if: () => ExtensionTestUtils.isInBackgroundServiceWorkerTests(), + }, + async function test_userScripts_register() { + let extension = makeExtension({ + manifest: { + manifest_version: 2, + user_scripts: { + api_script: "inject_browser.js", + }, + }, + async background() { + await browser.userScripts.register({ + js: [{ file: "script.js" }], + matches: ["http://*/*/*.html"], + }); + + browser.test.sendMessage("background-done"); + }, + }); + + await verifyRegistrationWithNewProcess(extension); + } +); |