diff options
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_scripting_contentScripts.js')
-rw-r--r-- | toolkit/components/extensions/test/xpcshell/test_ext_scripting_contentScripts.js | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_scripting_contentScripts.js b/toolkit/components/extensions/test/xpcshell/test_ext_scripting_contentScripts.js new file mode 100644 index 0000000000..a06f34a1b4 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_scripting_contentScripts.js @@ -0,0 +1,540 @@ +"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(); + +Services.prefs.setBoolPref("extensions.manifestV3.enabled", true); + +const makeExtension = ({ manifest: manifestProps, ...otherProps }) => { + return ExtensionTestUtils.loadExtension({ + manifest: { + manifest_version: 3, + permissions: ["scripting"], + host_permissions: ["http://localhost/*"], + granted_host_permissions: true, + ...manifestProps, + }, + temporarilyInstalled: true, + ...otherProps, + }); +}; + +add_task(async function test_registerContentScripts_runAt() { + let extension = makeExtension({ + async background() { + const TEST_CASES = [ + { + title: "runAt: document_idle", + params: [ + { + id: "script-idle", + js: ["script-idle.js"], + matches: ["http://*/*/file_sample.html"], + runAt: "document_idle", + persistAcrossSessions: false, + }, + ], + }, + { + title: "no runAt specified", + params: [ + { + id: "script-idle-default", + js: ["script-idle-default.js"], + matches: ["http://*/*/file_sample.html"], + // `runAt` defaults to `document_idle`. + persistAcrossSessions: false, + }, + ], + }, + { + title: "runAt: document_end", + params: [ + { + id: "script-end", + js: ["script-end.js"], + matches: ["http://*/*/file_sample.html"], + runAt: "document_end", + persistAcrossSessions: false, + }, + ], + }, + { + title: "runAt: document_start", + params: [ + { + id: "script-start", + js: ["script-start.js"], + matches: ["http://*/*/file_sample.html"], + runAt: "document_start", + persistAcrossSessions: false, + }, + ], + }, + ]; + + let scripts = await browser.scripting.getRegisteredContentScripts(); + browser.test.assertEq(0, scripts.length, "expected no registered script"); + + for (const { title, params } of TEST_CASES) { + const res = await browser.scripting.registerContentScripts(params); + browser.test.assertEq(undefined, res, `${title} - expected no result`); + } + + scripts = await browser.scripting.getRegisteredContentScripts(); + browser.test.assertEq( + TEST_CASES.length, + scripts.length, + `expected ${TEST_CASES.length} registered scripts` + ); + browser.test.assertEq( + JSON.stringify([ + { + id: "script-idle", + allFrames: false, + matches: ["http://*/*/file_sample.html"], + runAt: "document_idle", + persistAcrossSessions: false, + js: ["script-idle.js"], + }, + { + id: "script-idle-default", + allFrames: false, + matches: ["http://*/*/file_sample.html"], + runAt: "document_idle", + persistAcrossSessions: false, + js: ["script-idle-default.js"], + }, + { + id: "script-end", + allFrames: false, + matches: ["http://*/*/file_sample.html"], + runAt: "document_end", + persistAcrossSessions: false, + js: ["script-end.js"], + }, + { + id: "script-start", + allFrames: false, + matches: ["http://*/*/file_sample.html"], + runAt: "document_start", + persistAcrossSessions: false, + js: ["script-start.js"], + }, + ]), + JSON.stringify(scripts), + "got expected scripts" + ); + + browser.test.sendMessage("background-ready"); + }, + files: { + "script-start.js": () => { + browser.test.assertEq( + "loading", + document.readyState, + "expected state 'loading' at document_start" + ); + browser.test.sendMessage("script-ran", "script-start.js"); + }, + "script-end.js": () => { + browser.test.assertTrue( + ["interactive", "complete"].includes(document.readyState), + `expected state 'interactive' or 'complete' at document_end, got: ${document.readyState}` + ); + browser.test.sendMessage("script-ran", "script-end.js"); + }, + "script-idle.js": () => { + browser.test.assertEq( + "complete", + document.readyState, + "expected state 'complete' at document_idle" + ); + browser.test.sendMessage("script-ran", "script-idle.js"); + }, + "script-idle-default.js": () => { + browser.test.assertEq( + "complete", + document.readyState, + "expected state 'complete' at document_idle" + ); + browser.test.sendMessage("script-ran", "script-idle-default.js"); + }, + }, + }); + + let scriptsRan = []; + let completePromise = new Promise(resolve => { + extension.onMessage("script-ran", result => { + scriptsRan.push(result); + + // The value below should be updated when TEST_CASES above is changed. + if (scriptsRan.length === 4) { + resolve(); + } + }); + }); + + await extension.startup(); + await extension.awaitMessage("background-ready"); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + + await completePromise; + + Assert.deepEqual( + [ + "script-start.js", + "script-end.js", + "script-idle.js", + "script-idle-default.js", + ], + scriptsRan, + "got expected executed scripts" + ); + + await contentPage.close(); + await extension.unload(); +}); + +add_task(async function test_register_and_unregister() { + let extension = makeExtension({ + async background() { + const script = { + id: "a-script", + js: ["script.js"], + matches: ["http://*/*/file_sample.html"], + persistAcrossSessions: false, + }; + + let results = await Promise.allSettled([ + browser.scripting.registerContentScripts([script]), + browser.scripting.unregisterContentScripts(), + ]); + + browser.test.assertEq( + 2, + results.filter(result => result.status === "fulfilled").length, + "got expected number of fulfilled promises" + ); + + let scripts = await browser.scripting.getRegisteredContentScripts(); + browser.test.assertEq(0, scripts.length, "expected no registered script"); + + browser.test.sendMessage("background-done"); + }, + files: { + "script.js": "", + }, + }); + + await extension.startup(); + await extension.awaitMessage("background-done"); + + // Verify that the registered content scripts on the extension are correct. + let contentScripts = Array.from( + extension.extension.registeredContentScripts.values() + ); + Assert.equal(0, contentScripts.length, "expected no registered scripts"); + + await extension.unload(); +}); + +add_task(async function test_register_and_unregister_multiple_times() { + let extension = makeExtension({ + async background() { + // We use the same script `id` on purpose in this test. + let results = await Promise.allSettled([ + browser.scripting.registerContentScripts([ + { + id: "a-script", + js: ["script-1.js"], + matches: ["http://*/*/file_sample.html"], + persistAcrossSessions: false, + }, + ]), + browser.scripting.unregisterContentScripts(), + browser.scripting.registerContentScripts([ + { + id: "a-script", + js: ["script-2.js"], + matches: ["http://*/*/file_sample.html"], + persistAcrossSessions: false, + }, + ]), + browser.scripting.unregisterContentScripts(), + browser.scripting.registerContentScripts([ + { + id: "a-script", + js: ["script-3.js"], + matches: ["http://*/*/file_sample.html"], + persistAcrossSessions: false, + }, + ]), + ]); + + browser.test.assertEq( + 5, + results.filter(result => result.status === "fulfilled").length, + "got expected number of fulfilled promises" + ); + + let scripts = await browser.scripting.getRegisteredContentScripts(); + browser.test.assertEq(1, scripts.length, "expected 1 registered script"); + + browser.test.sendMessage("background-done"); + }, + files: { + "script-1.js": "", + "script-2.js": "", + "script-3.js": "", + }, + }); + + await extension.startup(); + await extension.awaitMessage("background-done"); + + // Verify that the registered content scripts on the extension are correct. + let contentScripts = Array.from( + extension.extension.registeredContentScripts.values() + ); + Assert.equal(1, contentScripts.length, "expected 1 registered script"); + Assert.ok( + contentScripts[0].jsPaths[0].endsWith("script-3.js"), + "got expected js file" + ); + + await extension.unload(); +}); + +add_task(async function test_register_update_and_unregister() { + let extension = makeExtension({ + async background() { + const script = { + id: "a-script", + js: ["script-1.js"], + matches: ["http://*/*/file_sample.html"], + persistAcrossSessions: false, + }; + const updatedScript1 = { ...script, js: ["script-2.js"] }; + const updatedScript2 = { ...script, js: ["script-3.js"] }; + + let results = await Promise.allSettled([ + browser.scripting.registerContentScripts([script]), + browser.scripting.updateContentScripts([updatedScript1]), + browser.scripting.updateContentScripts([updatedScript2]), + browser.scripting.getRegisteredContentScripts(), + browser.scripting.unregisterContentScripts(), + browser.scripting.updateContentScripts([script]), + ]); + + browser.test.assertEq(6, results.length, "expected 6 results"); + browser.test.assertEq( + "fulfilled", + results[0].status, + "expected fulfilled promise (registeredContentScripts)" + ); + browser.test.assertEq( + "fulfilled", + results[1].status, + "expected fulfilled promise (updateContentScripts)" + ); + browser.test.assertEq( + "fulfilled", + results[2].status, + "expected fulfilled promise (updateContentScripts)" + ); + browser.test.assertEq( + "fulfilled", + results[3].status, + "expected fulfilled promise (getRegisteredContentScripts)" + ); + browser.test.assertEq( + JSON.stringify([ + { + id: "a-script", + allFrames: false, + matches: ["http://*/*/file_sample.html"], + runAt: "document_idle", + persistAcrossSessions: false, + js: ["script-3.js"], + }, + ]), + JSON.stringify(results[3].value), + "expected updated content script" + ); + browser.test.assertEq( + "fulfilled", + results[4].status, + "expected fulfilled promise (unregisterContentScripts)" + ); + browser.test.assertEq( + "rejected", + results[5].status, + "expected rejected promise because script should have been unregistered" + ); + browser.test.assertEq( + `Content script with id "${script.id}" does not exist.`, + results[5].reason.message, + "expected error message about script not found" + ); + + let scripts = await browser.scripting.getRegisteredContentScripts(); + browser.test.assertEq(0, scripts.length, "expected no registered script"); + + browser.test.sendMessage("background-done"); + }, + files: { + "script-1.js": "", + "script-2.js": "", + "script-3.js": "", + }, + }); + + await extension.startup(); + await extension.awaitMessage("background-done"); + + // Verify that the registered content scripts on the extension are correct. + let contentScripts = Array.from( + extension.extension.registeredContentScripts.values() + ); + Assert.equal(0, contentScripts.length, "expected no registered scripts"); + + await extension.unload(); +}); + +// The following test case is a regression test for Bug 1851173. +add_task( + { + // contentScripts API not exposed to background service workers and + // Bug 1851173 can't be hit. + skip_if: () => ExtensionTestUtils.isInBackgroundServiceWorkerTests(), + }, + async function test_contentScriptsAPI_vs_scriptingGetRegistered() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + manifest_version: 2, + permissions: ["scripting", "<all_urls>"], + }, + async background() { + await browser.contentScripts.register({ + runAt: "document_start", + js: [{ file: "testcs.js" }], + matches: ["<all_urls>"], + }); + + const scriptingScripts = + await browser.scripting.getRegisteredContentScripts(); + browser.test.assertDeepEq( + [], + scriptingScripts, + "Expect an empty array" + ); + browser.test.sendMessage("background-done"); + }, + files: { + "testcs.js": "", + }, + }); + + await extension.startup(); + await extension.awaitMessage("background-done"); + await extension.unload(); + } +); + +async function test_matchAboutBlank_registerContentScripts_default({ + extId, + expectedMatchAboutBlankValue, +}) { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + manifest_version: 2, + permissions: ["scripting", "<all_urls>"], + browser_specific_settings: { + gecko: { id: extId }, + }, + }, + async background() { + await browser.scripting.registerContentScripts([ + { + id: "test-content-script", + matches: ["http://example.com/*"], + js: ["cs.js"], + }, + ]); + browser.test.sendMessage("background-done"); + }, + file: { + "cs.js": "", + }, + }); + + await extension.startup(); + await extension.awaitMessage("background-done"); + + equal( + extension.extension.registeredContentScripts.size, + 1, + "Got the expected number of registered content scripts" + ); + const [{ id, matchAboutBlank }] = Array.from( + extension.extension.registeredContentScripts.values() + ); + + equal(id, "test-content-script", "Got the expected content script id"); + equal( + matchAboutBlank, + expectedMatchAboutBlankValue, + "Expect matchAboutBlank to be false" + ); + + await extension.unload(); +} + +// The following test cases are regressions test for Bug 1853412, and it is +// currently making sure that content scripts registered dynamically +// by the webcompat built-in have matchAboutBlank set to false. +add_task(async function test_webcompat_matchAboutBlank_default() { + await test_matchAboutBlank_registerContentScripts_default({ + // This test extension has to have the same id that we expect + // the webcompat built-in to have. + extId: "webcompat@mozilla.org", + expectedMatchAboutBlankValue: false, + }); +}); + +// The following test task asserts that for any extension matchAboutBlank +// is still set by default to true +// TODO(Bug 1853411): should change this to default to false for all extensions +// and this test should be adjusted accordingly. +add_task(async function test_matchAboutBlank_default() { + await test_matchAboutBlank_registerContentScripts_default({ + extId: "some-unknown-extension-id@test.extension", + expectedMatchAboutBlankValue: true, + }); +}); + +// The following test task asserts that when the hidden pref +// "extensions.scripting.matchAboutBlankDefaultFalse" is set +// to true, then matchAboutBlank gets forcefully set to false +// TODO(Bug 1853411): may remove the hidden pref and this test along with it. +add_task( + { + pref_set: [["extensions.scripting.matchAboutBlankDefaultFalse", true]], + }, + async function test_matchAboutBlank_defaultChange_by_hiddenPref() { + await test_matchAboutBlank_registerContentScripts_default({ + extId: "some-unknown-extension-id@test.extension", + expectedMatchAboutBlankValue: false, + }); + } +); |