summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_webextension.js')
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/test_webextension.js421
1 files changed, 421 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
new file mode 100644
index 000000000..b51f47977
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
@@ -0,0 +1,421 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/AppConstants.jsm");
+
+const ID = "webextension1@tests.mozilla.org";
+
+const PREF_SELECTED_LOCALE = "general.useragent.locale";
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
+startupManager();
+
+const { GlobalManager, Management } = Components.utils.import("resource://gre/modules/Extension.jsm", {});
+
+function promiseAddonStartup() {
+ return new Promise(resolve => {
+ let listener = (evt, extension) => {
+ Management.off("ready", listener);
+ resolve(extension);
+ };
+
+ Management.on("ready", listener);
+ });
+}
+
+function promiseInstallWebExtension(aData) {
+ let addonFile = createTempWebExtensionFile(aData);
+
+ return promiseInstallAllFiles([addonFile]).then(() => {
+ Services.obs.notifyObservers(addonFile, "flush-cache-entry", null);
+ return promiseAddonStartup();
+ });
+}
+
+add_task(function*() {
+ equal(GlobalManager.extensionMap.size, 0);
+
+ yield Promise.all([
+ promiseInstallAllFiles([do_get_addon("webextension_1")], true),
+ promiseAddonStartup()
+ ]);
+
+ equal(GlobalManager.extensionMap.size, 1);
+ ok(GlobalManager.extensionMap.has(ID));
+
+ let chromeReg = AM_Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(AM_Ci.nsIChromeRegistry);
+ try {
+ chromeReg.convertChromeURL(NetUtil.newURI("chrome://webex/content/webex.xul"));
+ do_throw("Chrome manifest should not have been registered");
+ }
+ catch (e) {
+ // Expected the chrome url to not be registered
+ }
+
+ let addon = yield promiseAddonByID(ID);
+ do_check_neq(addon, null);
+ do_check_eq(addon.version, "1.0");
+ do_check_eq(addon.name, "Web Extension Name");
+ do_check_true(addon.isCompatible);
+ do_check_false(addon.appDisabled);
+ do_check_true(addon.isActive);
+ do_check_false(addon.isSystem);
+ do_check_eq(addon.type, "extension");
+ do_check_true(addon.isWebExtension);
+ do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+
+ let uri = do_get_addon_root_uri(profileDir, ID);
+
+ do_check_eq(addon.iconURL, uri + "icon48.png");
+ do_check_eq(addon.icon64URL, uri + "icon64.png");
+
+ // Should persist through a restart
+ yield promiseShutdownManager();
+
+ equal(GlobalManager.extensionMap.size, 0);
+
+ startupManager();
+ yield promiseAddonStartup();
+
+ equal(GlobalManager.extensionMap.size, 1);
+ ok(GlobalManager.extensionMap.has(ID));
+
+ addon = yield promiseAddonByID(ID);
+ do_check_neq(addon, null);
+ do_check_eq(addon.version, "1.0");
+ do_check_eq(addon.name, "Web Extension Name");
+ do_check_true(addon.isCompatible);
+ do_check_false(addon.appDisabled);
+ do_check_true(addon.isActive);
+ do_check_false(addon.isSystem);
+ do_check_eq(addon.type, "extension");
+ do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+
+ let file = getFileForAddon(profileDir, ID);
+ do_check_true(file.exists());
+
+ uri = do_get_addon_root_uri(profileDir, ID);
+
+ do_check_eq(addon.iconURL, uri + "icon48.png");
+ do_check_eq(addon.icon64URL, uri + "icon64.png");
+
+ addon.userDisabled = true;
+
+ equal(GlobalManager.extensionMap.size, 0);
+
+ addon.userDisabled = false;
+ yield promiseAddonStartup();
+
+ equal(GlobalManager.extensionMap.size, 1);
+ ok(GlobalManager.extensionMap.has(ID));
+
+ addon.uninstall();
+
+ equal(GlobalManager.extensionMap.size, 0);
+ do_check_false(GlobalManager.extensionMap.has(ID));
+
+ yield promiseShutdownManager();
+});
+
+// Writing the manifest direct to the profile should work
+add_task(function*() {
+ yield promiseWriteWebManifestForExtension({
+ name: "Web Extension Name",
+ version: "1.0",
+ manifest_version: 2,
+ applications: {
+ gecko: {
+ id: ID
+ }
+ }
+ }, profileDir);
+
+ startupManager();
+ yield promiseAddonStartup();
+
+ let addon = yield promiseAddonByID(ID);
+ do_check_neq(addon, null);
+ do_check_eq(addon.version, "1.0");
+ do_check_eq(addon.name, "Web Extension Name");
+ do_check_true(addon.isCompatible);
+ do_check_false(addon.appDisabled);
+ do_check_true(addon.isActive);
+ do_check_false(addon.isSystem);
+ do_check_eq(addon.type, "extension");
+ do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+
+ let file = getFileForAddon(profileDir, ID);
+ do_check_true(file.exists());
+
+ addon.uninstall();
+
+ yield promiseRestartManager();
+});
+
+add_task(function* test_manifest_localization() {
+ const extensionId = "webextension3@tests.mozilla.org";
+
+ yield promiseInstallAllFiles([do_get_addon("webextension_3")], true);
+ yield promiseAddonStartup();
+
+ let addon = yield promiseAddonByID(extensionId);
+ addon.userDisabled = true;
+
+ equal(addon.name, "Web Extensiøn foo ☹");
+ equal(addon.description, "Descriptïon bar ☹ of add-on");
+
+ Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "fr-FR");
+ yield promiseRestartManager();
+
+ addon = yield promiseAddonByID(extensionId);
+
+ equal(addon.name, "Web Extensiøn le foo ☺");
+ equal(addon.description, "Descriptïon le bar ☺ of add-on");
+
+ Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "de");
+ yield promiseRestartManager();
+
+ addon = yield promiseAddonByID(extensionId);
+
+ equal(addon.name, "Web Extensiøn foo ☹");
+ equal(addon.description, "Descriptïon bar ☹ of add-on");
+
+ addon.uninstall();
+});
+
+// Missing version should cause a failure
+add_task(function*() {
+ yield promiseWriteWebManifestForExtension({
+ name: "Web Extension Name",
+ manifest_version: 2,
+ applications: {
+ gecko: {
+ id: ID
+ }
+ }
+ }, profileDir);
+
+ yield promiseRestartManager();
+
+ let addon = yield promiseAddonByID(ID);
+ do_check_eq(addon, null);
+
+ let file = getFileForAddon(profileDir, ID);
+ do_check_false(file.exists());
+
+ yield promiseRestartManager();
+});
+
+// Incorrect manifest version should cause a failure
+add_task(function*() {
+ yield promiseWriteWebManifestForExtension({
+ name: "Web Extension Name",
+ version: "1.0",
+ manifest_version: 1,
+ applications: {
+ gecko: {
+ id: ID
+ }
+ }
+ }, profileDir);
+
+ yield promiseRestartManager();
+
+ let addon = yield promiseAddonByID(ID);
+ do_check_eq(addon, null);
+
+ let file = getFileForAddon(profileDir, ID);
+ do_check_false(file.exists());
+
+ yield promiseRestartManager();
+});
+
+// install.rdf should be read before manifest.json
+add_task(function*() {
+
+ yield Promise.all([
+ promiseInstallAllFiles([do_get_addon("webextension_2")], true)
+ ]);
+
+ yield promiseRestartManager();
+
+ let installrdf_id = "first-webextension2@tests.mozilla.org";
+ let first_addon = yield promiseAddonByID(installrdf_id);
+ do_check_neq(first_addon, null);
+ do_check_false(first_addon.appDisabled);
+ do_check_true(first_addon.isActive);
+ do_check_false(first_addon.isSystem);
+
+ let manifestjson_id= "last-webextension2@tests.mozilla.org";
+ let last_addon = yield promiseAddonByID(manifestjson_id);
+ do_check_eq(last_addon, null);
+
+ yield promiseRestartManager();
+});
+
+// Test that the "options_ui" manifest section is processed correctly.
+add_task(function* test_options_ui() {
+ let OPTIONS_RE = /^moz-extension:\/\/[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\/options\.html$/;
+
+ const extensionId = "webextension@tests.mozilla.org";
+ yield promiseInstallWebExtension({
+ manifest: {
+ applications: {gecko: {id: extensionId}},
+ "options_ui": {
+ "page": "options.html",
+ },
+ },
+ });
+
+ let addon = yield promiseAddonByID(extensionId);
+ equal(addon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_BROWSER,
+ "Addon should have an INLINE_BROWSER options type");
+
+ ok(OPTIONS_RE.test(addon.optionsURL),
+ "Addon should have a moz-extension: options URL for /options.html");
+
+ addon.uninstall();
+
+ const ID2 = "webextension2@tests.mozilla.org";
+ yield promiseInstallWebExtension({
+ manifest: {
+ applications: {gecko: {id: ID2}},
+ "options_ui": {
+ "page": "options.html",
+ "open_in_tab": true,
+ },
+ },
+ });
+
+ addon = yield promiseAddonByID(ID2);
+ equal(addon.optionsType, AddonManager.OPTIONS_TYPE_TAB,
+ "Addon should have a TAB options type");
+
+ ok(OPTIONS_RE.test(addon.optionsURL),
+ "Addon should have a moz-extension: options URL for /options.html");
+
+ addon.uninstall();
+});
+
+// Test that experiments permissions add the appropriate dependencies.
+add_task(function* test_experiments_dependencies() {
+ if (AppConstants.RELEASE_OR_BETA)
+ // Experiments are not enabled on release builds.
+ return;
+
+ let addonFile = createTempWebExtensionFile({
+ manifest: {
+ applications: {gecko: {id: "meh@experiment"}},
+ "permissions": ["experiments.meh"],
+ },
+ });
+
+ yield promiseInstallAllFiles([addonFile]);
+
+ let addon = yield new Promise(resolve => AddonManager.getAddonByID("meh@experiment", resolve));
+
+ deepEqual(addon.dependencies, ["meh@experiments.addons.mozilla.org"],
+ "Addon should have the expected dependencies");
+
+ equal(addon.appDisabled, true, "Add-on should be app disabled due to missing dependencies");
+
+ addon.uninstall();
+});
+
+// Test that experiments API extensions install correctly.
+add_task(function* test_experiments_api() {
+ if (AppConstants.RELEASE_OR_BETA)
+ // Experiments are not enabled on release builds.
+ return;
+
+ const extensionId = "meh@experiments.addons.mozilla.org";
+
+ let addonFile = createTempXPIFile({
+ id: extensionId,
+ type: 256,
+ version: "0.1",
+ name: "Meh API",
+ });
+
+ yield promiseInstallAllFiles([addonFile]);
+
+ let addons = yield new Promise(resolve => AddonManager.getAddonsByTypes(["apiextension"], resolve));
+ let addon = addons.pop();
+ equal(addon.id, extensionId, "Add-on should be installed as an API extension");
+
+ addons = yield new Promise(resolve => AddonManager.getAddonsByTypes(["extension"], resolve));
+ equal(addons.pop().id, extensionId, "Add-on type should be aliased to extension");
+
+ addon.uninstall();
+});
+
+add_task(function* developerShouldOverride() {
+ let addon = yield promiseInstallWebExtension({
+ manifest: {
+ default_locale: "en",
+ developer: {
+ name: "__MSG_name__",
+ url: "__MSG_url__"
+ },
+ author: "Will be overridden by developer",
+ homepage_url: "https://will.be.overridden",
+ },
+ files: {
+ "_locales/en/messages.json": `{
+ "name": {
+ "message": "en name"
+ },
+ "url": {
+ "message": "https://example.net/en"
+ }
+ }`
+ }
+ });
+
+ addon = yield promiseAddonByID(addon.id);
+ equal(addon.creator, "en name");
+ equal(addon.homepageURL, "https://example.net/en");
+ addon.uninstall();
+});
+
+add_task(function* developerEmpty() {
+ for (let developer of [{}, null, {name: null, url: null}]) {
+ let addon = yield promiseInstallWebExtension({
+ manifest: {
+ author: "Some author",
+ developer: developer,
+ homepage_url: "https://example.net",
+ manifest_version: 2,
+ name: "Web Extension Name",
+ version: "1.0",
+ }
+ });
+
+ addon = yield promiseAddonByID(addon.id);
+ equal(addon.creator, "Some author");
+ equal(addon.homepageURL, "https://example.net");
+ addon.uninstall();
+ }
+});
+
+add_task(function* authorNotString() {
+ for (let author of [{}, [], 42]) {
+ let addon = yield promiseInstallWebExtension({
+ manifest: {
+ author: author,
+ manifest_version: 2,
+ name: "Web Extension Name",
+ version: "1.0",
+ }
+ });
+
+ addon = yield promiseAddonByID(addon.id);
+ equal(addon.creator, null);
+ addon.uninstall();
+ }
+});