summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/webextensions/test/xpcshell/test_webextension_embedded.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/webextensions/test/xpcshell/test_webextension_embedded.js')
-rw-r--r--toolkit/mozapps/webextensions/test/xpcshell/test_webextension_embedded.js306
1 files changed, 306 insertions, 0 deletions
diff --git a/toolkit/mozapps/webextensions/test/xpcshell/test_webextension_embedded.js b/toolkit/mozapps/webextensions/test/xpcshell/test_webextension_embedded.js
new file mode 100644
index 000000000..3bd8a2bd8
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/xpcshell/test_webextension_embedded.js
@@ -0,0 +1,306 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+BootstrapMonitor.init();
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
+startupManager();
+
+// NOTE: the following import needs to be called after the `createAppInfo`
+// or it will fail Extension.jsm internally imports AddonManager.jsm and
+// AddonManager will raise a ReferenceError exception because it tried to
+// access an undefined `Services.appinfo` object.
+const { Management } = Components.utils.import("resource://gre/modules/Extension.jsm", {});
+
+const {
+ EmbeddedExtensionManager,
+ LegacyExtensionsUtils,
+} = Components.utils.import("resource://gre/modules/LegacyExtensionsUtils.jsm");
+
+// Wait the startup of the embedded webextension.
+function promiseWebExtensionStartup() {
+ return new Promise(resolve => {
+ let listener = (event, extension) => {
+ Management.off("startup", listener);
+ resolve(extension);
+ };
+
+ Management.on("startup", listener);
+ });
+}
+
+function promiseWebExtensionShutdown() {
+ return new Promise(resolve => {
+ let listener = (event, extension) => {
+ Management.off("shutdown", listener);
+ resolve(extension);
+ };
+
+ Management.on("shutdown", listener);
+ });
+}
+
+const BOOTSTRAP = String.raw`
+ Components.utils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);
+`;
+
+const EMBEDDED_WEBEXT_MANIFEST = JSON.stringify({
+ name: "embedded webextension addon",
+ manifest_version: 2,
+ version: "1.0",
+});
+
+/**
+ * This test case checks that an hasEmbeddedWebExtension addon property
+ * is persisted and restored correctly across restarts.
+ */
+add_task(function* has_embedded_webextension_persisted() {
+ const ID = "embedded-webextension-addon-persist@tests.mozilla.org";
+
+ const xpiFile = createTempXPIFile({
+ id: ID,
+ name: "Test Add-on",
+ version: "1.0",
+ bootstrap: true,
+ hasEmbeddedWebExtension: true,
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "1.9.2"
+ }]
+ }, {
+ "bootstrap.js": BOOTSTRAP,
+ "webextension/manifest.json": EMBEDDED_WEBEXT_MANIFEST,
+ });
+
+ yield promiseInstallFile(xpiFile);
+
+ let addon = yield promiseAddonByID(ID);
+
+ notEqual(addon, null, "Got an addon object as expected");
+ equal(addon.version, "1.0", "Got the expected version");
+ equal(addon.hasEmbeddedWebExtension, true,
+ "Got the expected hasEmbeddedWebExtension value");
+
+ // Check that the addon has been installed and started.
+ BootstrapMonitor.checkAddonInstalled(ID, "1.0");
+ BootstrapMonitor.checkAddonStarted(ID, "1.0");
+
+ let startupInfo = BootstrapMonitor.started.get(ID);
+ ok(("webExtension" in startupInfo.data),
+ "Got an webExtension property in the startup bootstrap method params");
+ ok(("startup" in startupInfo.data.webExtension),
+ "Got the expected 'startup' property in the webExtension object");
+
+ // After restarting the manager, the add-on should still have the
+ // hasEmbeddedWebExtension property as expected.
+ yield promiseRestartManager();
+
+ let persisted = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
+ ok(ID in persisted, "Hybrid add-on persisted to bootstrappedAddons.");
+ equal(persisted[ID].hasEmbeddedWebExtension, true,
+ "hasEmbeddedWebExtension flag persisted to bootstrappedAddons.");
+
+ // Check that the addon has been installed and started.
+ BootstrapMonitor.checkAddonInstalled(ID, "1.0");
+ BootstrapMonitor.checkAddonStarted(ID, "1.0");
+
+ addon = yield promiseAddonByID(ID);
+ notEqual(addon, null, "Got an addon object as expected");
+ equal(addon.hasEmbeddedWebExtension, true, "Got the expected hasEmbeddedWebExtension value");
+
+ // Check that the addon has been installed and started.
+ let newStartupInfo = BootstrapMonitor.started.get(ID);
+ ok(("webExtension" in newStartupInfo.data),
+ "Got an webExtension property in the startup bootstrap method params");
+ ok(("startup" in newStartupInfo.data.webExtension),
+ "Got the expected 'startup' property in the webExtension object");
+
+ let waitUninstall = promiseAddonEvent("onUninstalled");
+ addon.uninstall();
+ yield waitUninstall;
+});
+
+/**
+ * This test case checks that an addon with hasEmbeddedWebExtension set to true
+ * in its install.rdf gets the expected `embeddedWebExtension` object in the
+ * parameters of its bootstrap methods.
+ */
+add_task(function* run_embedded_webext_bootstrap() {
+ const ID = "embedded-webextension-addon2@tests.mozilla.org";
+
+ const xpiFile = createTempXPIFile({
+ id: ID,
+ name: "Test Add-on",
+ version: "1.0",
+ bootstrap: true,
+ hasEmbeddedWebExtension: true,
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "1.9.2"
+ }]
+ }, {
+ "bootstrap.js": BOOTSTRAP,
+ "webextension/manifest.json": EMBEDDED_WEBEXT_MANIFEST,
+ });
+
+ yield AddonManager.installTemporaryAddon(xpiFile);
+
+ let addon = yield promiseAddonByID(ID);
+
+ notEqual(addon, null, "Got an addon object as expected");
+ equal(addon.version, "1.0", "Got the expected version");
+ equal(addon.hasEmbeddedWebExtension, true,
+ "Got the expected hasEmbeddedWebExtension value");
+
+ // Check that the addon has been installed and started.
+ BootstrapMonitor.checkAddonInstalled(ID, "1.0");
+
+ let installInfo = BootstrapMonitor.installed.get(ID);
+ ok(!("webExtension" in installInfo.data),
+ "No webExtension property is expected in the install bootstrap method params");
+
+ BootstrapMonitor.checkAddonStarted(ID, "1.0");
+
+ let startupInfo = BootstrapMonitor.started.get(ID);
+
+ ok(("webExtension" in startupInfo.data),
+ "Got an webExtension property in the startup bootstrap method params");
+
+ ok(("startup" in startupInfo.data.webExtension),
+ "Got the expected 'startup' property in the webExtension object");
+
+ const waitForWebExtensionStartup = promiseWebExtensionStartup();
+
+ const embeddedAPI = yield startupInfo.data.webExtension.startup();
+
+ // WebExtension startup should have been fully resolved.
+ yield waitForWebExtensionStartup;
+
+ Assert.deepEqual(
+ Object.keys(embeddedAPI.browser.runtime).sort(),
+ ["onConnect", "onMessage"],
+ `Got the expected 'runtime' in the 'browser' API object`
+ );
+
+ // Uninstall the addon and wait that the embedded webextension has been stopped and
+ // test the params of the shutdown and uninstall bootstrap method.
+ let waitForWebExtensionShutdown = promiseWebExtensionShutdown();
+ let waitUninstall = promiseAddonEvent("onUninstalled");
+ addon.uninstall();
+ yield waitForWebExtensionShutdown;
+ yield waitUninstall;
+
+ BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
+
+ let shutdownInfo = BootstrapMonitor.stopped.get(ID);
+ ok(!("webExtension" in shutdownInfo.data),
+ "No webExtension property is expected in the shutdown bootstrap method params");
+
+ let uninstallInfo = BootstrapMonitor.uninstalled.get(ID);
+ ok(!("webExtension" in uninstallInfo.data),
+ "No webExtension property is expected in the uninstall bootstrap method params");
+});
+
+/**
+ * This test case checks that an addon with hasEmbeddedWebExtension can be reloaded
+ * without raising unexpected exceptions due to race conditions.
+ */
+add_task(function* reload_embedded_webext_bootstrap() {
+ const ID = "embedded-webextension-addon2@tests.mozilla.org";
+
+ // No embedded webextension should be currently around.
+ equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 0,
+ "No embedded extension instance should be tracked here");
+
+ const xpiFile = createTempXPIFile({
+ id: ID,
+ name: "Test Add-on",
+ version: "1.0",
+ bootstrap: true,
+ hasEmbeddedWebExtension: true,
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "1.9.2"
+ }]
+ }, {
+ "bootstrap.js": BOOTSTRAP,
+ "webextension/manifest.json": EMBEDDED_WEBEXT_MANIFEST,
+ });
+
+ yield AddonManager.installTemporaryAddon(xpiFile);
+
+ let addon = yield promiseAddonByID(ID);
+
+ notEqual(addon, null, "Got an addon object as expected");
+ equal(addon.version, "1.0", "Got the expected version");
+ equal(addon.isActive, true, "The Addon is active");
+ equal(addon.appDisabled, false, "The addon is not app disabled");
+ equal(addon.userDisabled, false, "The addon is not user disabled");
+
+ // Check that the addon has been installed and started.
+ BootstrapMonitor.checkAddonInstalled(ID, "1.0");
+ BootstrapMonitor.checkAddonStarted(ID, "1.0");
+
+ // Only one embedded extension.
+ equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 1,
+ "Got the expected number of tracked extension instances");
+
+ const embeddedWebExtension = EmbeddedExtensionManager.embeddedExtensionsByAddonId.get(ID);
+
+ let startupInfo = BootstrapMonitor.started.get(ID);
+ yield startupInfo.data.webExtension.startup();
+
+ const waitForAddonDisabled = promiseAddonEvent("onDisabled");
+ addon.userDisabled = true;
+ yield waitForAddonDisabled;
+
+ // No embedded webextension should be currently around.
+ equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 0,
+ "No embedded extension instance should be tracked here");
+
+ const waitForAddonEnabled = promiseAddonEvent("onEnabled");
+ addon.userDisabled = false;
+ yield waitForAddonEnabled;
+
+ // Only one embedded extension.
+ equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 1,
+ "Got the expected number of tracked extension instances");
+
+ const embeddedWebExtensionAfterEnabled = EmbeddedExtensionManager.embeddedExtensionsByAddonId.get(ID);
+ notEqual(embeddedWebExtensionAfterEnabled, embeddedWebExtension,
+ "Got a new EmbeddedExtension instance after the addon has been disabled and then enabled");
+
+ startupInfo = BootstrapMonitor.started.get(ID);
+ yield startupInfo.data.webExtension.startup();
+
+ const waitForReinstalled = promiseAddonEvent("onInstalled");
+ addon.reload();
+ yield waitForReinstalled;
+
+ // No leaked embedded extension after the previous reloads.
+ equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 1,
+ "Got the expected number of tracked extension instances");
+
+ const embeddedWebExtensionAfterReload = EmbeddedExtensionManager.embeddedExtensionsByAddonId.get(ID);
+ notEqual(embeddedWebExtensionAfterReload, embeddedWebExtensionAfterEnabled,
+ "Got a new EmbeddedExtension instance after the addon has been reloaded");
+
+ startupInfo = BootstrapMonitor.started.get(ID);
+ yield startupInfo.data.webExtension.startup();
+
+ // Uninstall the test addon
+ let waitUninstalled = promiseAddonEvent("onUninstalled");
+ addon.uninstall();
+ yield waitUninstalled;
+
+ // No leaked embedded extension after uninstalling.
+ equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 0,
+ "No embedded extension instance should be tracked after the addon uninstall");
+});