Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'win' && socketprocess_networking && fission OR os == 'mac' && socketprocess_networking && fission OR os == 'mac' && debug OR os == 'linux' && socketprocess_networking
- Manifest: toolkit/components/extensions/test/xpcshell/xpcshell-remote.toml includes toolkit/components/extensions/test/xpcshell/xpcshell-common.toml
- Manifest: toolkit/components/extensions/test/xpcshell/xpcshell.toml includes toolkit/components/extensions/test/xpcshell/xpcshell-common.toml
/* Any copyright is dedicated to the Public Domain.
"use strict";
AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
AddonTestUtils.createAppInfo(
"xpcshell@tests.mozilla.org",
"XPCShell",
"1",
"42"
);
const { ExtensionScriptingStore } = ChromeUtils.importESModule(
"resource://gre/modules/ExtensionScriptingStore.sys.mjs"
);
const { TestUtils } = ChromeUtils.importESModule(
);
const { sinon } = ChromeUtils.importESModule(
);
add_setup(async () => {
await AddonTestUtils.promiseStartupManager();
});
add_task(async function test_hasPersistedScripts_startup_cache() {
let extension1 = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
manifest_version: 2,
permissions: ["scripting"],
},
background() {
browser.test.onMessage.addListener(async (msg, ...args) => {
switch (msg) {
case "registerContentScripts":
await browser.scripting.registerContentScripts(...args);
break;
case "unregisterContentScripts":
await browser.scripting.unregisterContentScripts(...args);
break;
default:
browser.test.fail(`Unexpected test message: ${msg}`);
}
browser.test.sendMessage(`${msg}:done`);
});
browser.test.sendMessage("bgpage:ready");
},
files: {
"script-1.js": "",
},
});
await extension1.startup();
await extension1.awaitMessage("bgpage:ready");
info(`Checking StartupCache for ${extension1.id} ${extension1.version}`);
await assertHasPersistedScriptsCachedFlag(extension1);
await assertIsPersistentScriptsCachedFlag(extension1, false);
const store = ExtensionScriptingStore._getStoreForTesting();
extension1.sendMessage("registerContentScripts", [
{
id: "some-script-id",
js: ["script-1.js"],
persistAcrossSessions: true,
},
]);
await extension1.awaitMessage("registerContentScripts:done");
// `registerContentScripts()` calls `ExtensionScriptingStore.persistAll()`
// without await it, which isn't a problem in practice but this becomes a
// problem in this test given that we should make sure the startup cache
// is updated before checking it.
await TestUtils.waitForCondition(async () => {
const scripts = await store.getAll(extension1.id);
return !!scripts.length;
}, "Wait for stored scripts list to not be empty");
await assertIsPersistentScriptsCachedFlag(extension1, true);
extension1.sendMessage("unregisterContentScripts", {
ids: ["some-script-id"],
});
await extension1.awaitMessage("unregisterContentScripts:done");
await TestUtils.waitForCondition(async () => {
const scripts = await store.getAll(extension1.id);
return !scripts.length;
}, "Wait for stored scripts list to be empty");
await assertIsPersistentScriptsCachedFlag(extension1, false);
const storeGetAllSpy = sinon.spy(store, "getAll");
const cleanupSpies = () => {
storeGetAllSpy.restore();
};
// Restart the AddonManager to ensure the test extension startupReason will
// be set to "APP_STARTUP". This is used to assert that the expected call to
// `ExtensionScriptingStore.init(extension)` is hit as expected on browser
// startups after the extension has been fully installed.
await AddonTestUtils.promiseRestartManager();
await extension1.awaitStartup();
info("Wait for the extension to be fully restarted");
await extension1.awaitMessage("bgpage:ready");
// NOTE: ExtensionScriptingStore.initExtension is usually only called once
// during the extension startup.
//
// This test calls the method after startup was completed, which does not
// happen in practice, but it allows us to simulate what happens under different
// store and startup cache conditions and more explicitly cover the expectation
// that store.getAll isn't going to be called more than once internally
// when the hasPersistedScripts boolean flag wasn't in the StartupCache
// and had to be recomputed.
equal(
extension1.extension.startupReason,
"APP_STARTUP",
"Got the expected extension.startupReason"
);
await ExtensionScriptingStore.initExtension(extension1.extension);
equal(storeGetAllSpy.callCount, 0, "Expect store.getAll to not be called");
Services.obs.notifyObservers(null, "startupcache-invalidate");
await ExtensionScriptingStore.initExtension(extension1.extension);
equal(storeGetAllSpy.callCount, 1, "Expect store.getAll to be called once");
extension1.sendMessage("registerContentScripts", [
{
id: "some-script-id",
js: ["script-1.js"],
persistAcrossSessions: true,
},
]);
await extension1.awaitMessage("registerContentScripts:done");
await TestUtils.waitForCondition(async () => {
const scripts = await store.getAll(extension1.id);
return !!scripts.length;
}, "Wait for stored scripts list to not be empty");
await assertIsPersistentScriptsCachedFlag(extension1, true);
// Make sure getAll is only called once when we don't have
// scripting.hasPersistedScripts flag cached.
storeGetAllSpy.resetHistory();
Services.obs.notifyObservers(null, "startupcache-invalidate");
await ExtensionScriptingStore.initExtension(extension1.extension);
equal(storeGetAllSpy.callCount, 1, "Expect store.getAll to be called once");
cleanupSpies();
const extId = extension1.id;
const extVersion = extension1.version;
await assertIsPersistentScriptsCachedFlag(
{ id: extId, version: extVersion },
true
);
await extension1.unload();
await assertIsPersistentScriptsCachedFlag(
{ id: extId, version: extVersion },
undefined
);
const { StartupCache } = ExtensionParent;
const allCachedGeneral = StartupCache._data.get("general");
equal(
allCachedGeneral.has(extId),
false,
"Expect the extension to have been removed from the StartupCache"
);
});