summaryrefslogtreecommitdiffstats
path: root/testing/marionette/addon.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /testing/marionette/addon.js
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/marionette/addon.js')
-rw-r--r--testing/marionette/addon.js136
1 files changed, 136 insertions, 0 deletions
diff --git a/testing/marionette/addon.js b/testing/marionette/addon.js
new file mode 100644
index 0000000000..6702f015a3
--- /dev/null
+++ b/testing/marionette/addon.js
@@ -0,0 +1,136 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const EXPORTED_SYMBOLS = ["Addon"];
+
+const { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ AddonManager: "resource://gre/modules/AddonManager.jsm",
+ FileUtils: "resource://gre/modules/FileUtils.jsm",
+
+ error: "chrome://marionette/content/error.js",
+});
+
+// from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
+const ERRORS = {
+ [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
+ [-2]: "ERROR_INCORECT_HASH: The downloaded file did not match the expected hash.",
+ [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
+ [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
+ [-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
+};
+
+async function installAddon(file) {
+ let install = await AddonManager.getInstallForFile(file, null, {
+ source: "internal",
+ });
+
+ if (install.error) {
+ throw new error.UnknownError(ERRORS[install.error]);
+ }
+
+ return install.install().catch(err => {
+ throw new error.UnknownError(ERRORS[install.error]);
+ });
+}
+
+/** Installs addons by path and uninstalls by ID. */
+class Addon {
+ /**
+ * Install a Firefox addon.
+ *
+ * If the addon is restartless, it can be used right away. Otherwise a
+ * restart is required.
+ *
+ * Temporary addons will automatically be uninstalled on shutdown and
+ * do not need to be signed, though they must be restartless.
+ *
+ * @param {string} path
+ * Full path to the extension package archive.
+ * @param {boolean=} temporary
+ * True to install the addon temporarily, false (default) otherwise.
+ *
+ * @return {Promise.<string>}
+ * Addon ID.
+ *
+ * @throws {UnknownError}
+ * If there is a problem installing the addon.
+ */
+ static async install(path, temporary = false) {
+ let addon;
+ let file;
+
+ try {
+ file = new FileUtils.File(path);
+ } catch (e) {
+ throw new error.UnknownError(`Expected absolute path: ${e}`, e);
+ }
+
+ if (!file.exists()) {
+ throw new error.UnknownError(`No such file or directory: ${path}`);
+ }
+
+ try {
+ if (temporary) {
+ addon = await AddonManager.installTemporaryAddon(file);
+ } else {
+ addon = await installAddon(file);
+ }
+ } catch (e) {
+ throw new error.UnknownError(
+ `Could not install add-on: ${path}: ${e.message}`,
+ e
+ );
+ }
+
+ return addon.id;
+ }
+
+ /**
+ * Uninstall a Firefox addon.
+ *
+ * If the addon is restartless it will be uninstalled right away.
+ * Otherwise, Firefox must be restarted for the change to take effect.
+ *
+ * @param {string} id
+ * ID of the addon to uninstall.
+ *
+ * @return {Promise}
+ *
+ * @throws {UnknownError}
+ * If there is a problem uninstalling the addon.
+ */
+ static async uninstall(id) {
+ let candidate = await AddonManager.getAddonByID(id);
+
+ return new Promise(resolve => {
+ let listener = {
+ onOperationCancelled: addon => {
+ if (addon.id === candidate.id) {
+ AddonManager.removeAddonListener(listener);
+ throw new error.UnknownError(
+ `Uninstall of ${candidate.id} has been canceled`
+ );
+ }
+ },
+
+ onUninstalled: addon => {
+ if (addon.id === candidate.id) {
+ AddonManager.removeAddonListener(listener);
+ resolve();
+ }
+ },
+ };
+
+ AddonManager.addAddonListener(listener);
+ candidate.uninstall();
+ });
+ }
+}
+this.Addon = Addon;