From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../test/xpcshell/test_ext_contentscript.js | 270 +++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_contentscript.js (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_contentscript.js') diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript.js b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript.js new file mode 100644 index 0000000000..cb2f342d4e --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript.js @@ -0,0 +1,270 @@ +"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(); + +add_task(async function test_contentscript_runAt() { + function background() { + browser.runtime.onMessage.addListener( + ([msg, expectedStates, readyState], sender) => { + if (msg == "chrome-namespace-ok") { + browser.test.sendMessage(msg); + return; + } + + browser.test.assertEq("script-run", msg, "message type is correct"); + browser.test.assertTrue( + expectedStates.includes(readyState), + `readyState "${readyState}" is one of [${expectedStates}]` + ); + browser.test.sendMessage("script-run-" + expectedStates[0]); + } + ); + } + + function contentScriptStart() { + browser.runtime.sendMessage([ + "script-run", + ["loading"], + document.readyState, + ]); + } + function contentScriptEnd() { + browser.runtime.sendMessage([ + "script-run", + ["interactive", "complete"], + document.readyState, + ]); + } + function contentScriptIdle() { + browser.runtime.sendMessage([ + "script-run", + ["complete"], + document.readyState, + ]); + } + + function contentScript() { + let manifest = browser.runtime.getManifest(); + void manifest.applications.gecko.id; + browser.runtime.sendMessage(["chrome-namespace-ok"]); + } + + let extensionData = { + manifest: { + browser_specific_settings: { + gecko: { id: "contentscript@tests.mozilla.org" }, + }, + content_scripts: [ + { + matches: ["http://*/*/file_sample.html"], + js: ["content_script_start.js"], + run_at: "document_start", + }, + { + matches: ["http://*/*/file_sample.html"], + js: ["content_script_end.js"], + run_at: "document_end", + }, + { + matches: ["http://*/*/file_sample.html"], + js: ["content_script_idle.js"], + run_at: "document_idle", + }, + { + matches: ["http://*/*/file_sample.html"], + js: ["content_script_idle.js"], + // Test default `run_at`. + }, + { + matches: ["http://*/*/file_sample.html"], + js: ["content_script.js"], + run_at: "document_idle", + }, + ], + }, + background, + + files: { + "content_script_start.js": contentScriptStart, + "content_script_end.js": contentScriptEnd, + "content_script_idle.js": contentScriptIdle, + "content_script.js": contentScript, + }, + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); + + let loadingCount = 0; + let interactiveCount = 0; + let completeCount = 0; + extension.onMessage("script-run-loading", () => { + loadingCount++; + }); + extension.onMessage("script-run-interactive", () => { + interactiveCount++; + }); + + let completePromise = new Promise(resolve => { + extension.onMessage("script-run-complete", () => { + completeCount++; + if (completeCount > 1) { + resolve(); + } + }); + }); + + let chromeNamespacePromise = extension.awaitMessage("chrome-namespace-ok"); + + await extension.startup(); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + + await Promise.all([completePromise, chromeNamespacePromise]); + + await contentPage.close(); + + equal(loadingCount, 1, "document_start script ran exactly once"); + equal(interactiveCount, 1, "document_end script ran exactly once"); + equal(completeCount, 2, "document_idle script ran exactly twice"); + + await extension.unload(); +}); + +add_task(async function test_contentscript_window_open() { + if (AppConstants.DEBUG && Services.appinfo.browserTabsRemoteAutostart) { + return; + } + + let script = async () => { + /* globals x */ + browser.test.assertEq(1, x, "Should only run once"); + + if (top !== window) { + // Wait for our parent page to load, then set a timeout to wait for the + // document.open call, so we make sure to not tear down the extension + // until after we've done the document.open. + await new Promise(resolve => { + top.addEventListener("load", () => setTimeout(resolve, 0), { + once: true, + }); + }); + } + + browser.test.sendMessage("content-script", [location.href, top === window]); + }; + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + browser_specific_settings: { + gecko: { id: "contentscript@tests.mozilla.org" }, + }, + content_scripts: [ + { + matches: [""], + js: ["content_script.js"], + run_at: "document_start", + match_about_blank: true, + all_frames: true, + }, + ], + }, + + files: { + "content_script.js": ` + var x = (x || 0) + 1; + (${script})(); + `, + }, + }); + + await extension.startup(); + + let url = `${BASE_URL}/file_document_open.html`; + let contentPage = await ExtensionTestUtils.loadContentPage(url); + + let [pageURL, pageIsTop] = await extension.awaitMessage("content-script"); + + // Sometimes we get a content script load for the initial about:blank + // top level frame here, sometimes we don't. Either way is fine, as long as we + // don't get two loads into the same document.open() document. + if (pageURL === "about:blank") { + equal(pageIsTop, true); + [pageURL, pageIsTop] = await extension.awaitMessage("content-script"); + } + + Assert.deepEqual([pageURL, pageIsTop], [url, true]); + + let [frameURL, isTop] = await extension.awaitMessage("content-script"); + Assert.deepEqual([frameURL, isTop], [url, false]); + + await contentPage.close(); + await extension.unload(); +}); + +// This test verify that a cached script is still able to catch the document +// while it is still loading (when we do not block the document parsing as +// we do for a non cached script). +add_task(async function test_cached_contentscript_on_document_start() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://localhost/*/file_document_open.html"], + js: ["content_script.js"], + run_at: "document_start", + }, + ], + }, + + files: { + "content_script.js": ` + browser.test.sendMessage("content-script-loaded", { + url: window.location.href, + documentReadyState: document.readyState, + }); + `, + }, + }); + + await extension.startup(); + + let url = `${BASE_URL}/file_document_open.html`; + let contentPage = await ExtensionTestUtils.loadContentPage(url); + + let msg = await extension.awaitMessage("content-script-loaded"); + Assert.deepEqual( + msg, + { + url, + documentReadyState: "loading", + }, + "Got the expected url and document.readyState from a non cached script" + ); + + // Reload the page and check that the cached content script is still able to + // run on document_start. + await contentPage.loadURL(url); + + let msgFromCached = await extension.awaitMessage("content-script-loaded"); + Assert.deepEqual( + msgFromCached, + { + url, + documentReadyState: "loading", + }, + "Got the expected url and document.readyState from a cached script" + ); + + await extension.unload(); + + await contentPage.close(); +}); -- cgit v1.2.3