summaryrefslogtreecommitdiffstats
path: root/devtools/client/aboutdebugging/test/browser/helper-addons.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/aboutdebugging/test/browser/helper-addons.js')
-rw-r--r--devtools/client/aboutdebugging/test/browser/helper-addons.js262
1 files changed, 262 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/test/browser/helper-addons.js b/devtools/client/aboutdebugging/test/browser/helper-addons.js
new file mode 100644
index 0000000000..e3a8be3761
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/browser/helper-addons.js
@@ -0,0 +1,262 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+function _getSupportsFile(path) {
+ const cr = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(
+ Ci.nsIChromeRegistry
+ );
+ const uri = Services.io.newURI(CHROME_URL_ROOT + path);
+ const fileurl = cr.convertChromeURL(uri);
+ return fileurl.QueryInterface(Ci.nsIFileURL);
+}
+
+async function enableExtensionDebugging() {
+ // Disable security prompt
+ await pushPref("devtools.debugger.prompt-connection", false);
+}
+/* exported enableExtensionDebugging */
+
+/**
+ * Install an extension using the AddonManager so it does not show up as temporary.
+ */
+async function installRegularExtension(pathOrFile) {
+ const isFile = typeof pathOrFile.isFile === "function" && pathOrFile.isFile();
+ const file = isFile ? pathOrFile : _getSupportsFile(pathOrFile).file;
+ const install = await AddonManager.getInstallForFile(file);
+ return new Promise((resolve, reject) => {
+ if (!install) {
+ throw new Error(`An install was not created for ${file.path}`);
+ }
+ install.addListener({
+ onDownloadFailed: reject,
+ onDownloadCancelled: reject,
+ onInstallFailed: reject,
+ onInstallCancelled: reject,
+ onInstallEnded: resolve,
+ });
+ install.install();
+ });
+}
+/* exported installRegularExtension */
+
+/**
+ * Install a temporary extension at the provided path, with the provided name.
+ * Will use a mock file picker to select the file.
+ */
+async function installTemporaryExtension(pathOrFile, name, document) {
+ const { Management } = ChromeUtils.importESModule(
+ "resource://gre/modules/Extension.sys.mjs"
+ );
+
+ info("Install temporary extension named " + name);
+ // Mock the file picker to select a test addon
+ prepareMockFilePicker(pathOrFile);
+
+ const onAddonInstalled = new Promise(done => {
+ Management.on("startup", function listener(event, extension) {
+ if (extension.name != name) {
+ return;
+ }
+
+ Management.off("startup", listener);
+ done(extension);
+ });
+ });
+
+ // Trigger the file picker by clicking on the button
+ document.querySelector(".qa-temporary-extension-install-button").click();
+
+ info("Wait for addon to be installed");
+ return onAddonInstalled;
+}
+/* exported installTemporaryExtension */
+
+function createTemporaryXPI(xpiData) {
+ const { ExtensionTestCommon } = ChromeUtils.importESModule(
+ "resource://testing-common/ExtensionTestCommon.sys.mjs"
+ );
+
+ const { background, files, id, name, extraProperties } = xpiData;
+ info("Generate XPI file for " + id);
+
+ const manifest = Object.assign(
+ {},
+ {
+ browser_specific_settings: { gecko: { id } },
+ manifest_version: 2,
+ name,
+ version: "1.0",
+ },
+ extraProperties
+ );
+
+ const xpiFile = ExtensionTestCommon.generateXPI({
+ background,
+ files,
+ manifest,
+ });
+ registerCleanupFunction(() => xpiFile.exists() && xpiFile.remove(false));
+ return xpiFile;
+}
+/* exported createTemporaryXPI */
+
+/**
+ * Remove the existing temporary XPI file generated by ExtensionTestCommon and create a
+ * new one at the same location.
+ * @return {File} the temporary extension XPI file created
+ */
+function updateTemporaryXPI(xpiData, existingXPI) {
+ info("Delete and regenerate XPI for " + xpiData.id);
+
+ // Store the current name to check the xpi is correctly replaced.
+ const existingName = existingXPI.leafName;
+ info("Delete existing XPI named: " + existingName);
+ existingXPI.exists() && existingXPI.remove(false);
+
+ const xpiFile = createTemporaryXPI(xpiData);
+ // Check that the name of the new file is correct
+ if (xpiFile.leafName !== existingName) {
+ throw new Error(
+ "New XPI created with unexpected name: " + xpiFile.leafName
+ );
+ }
+ return xpiFile;
+}
+/* exported updateTemporaryXPI */
+
+/**
+ * Install a fake temporary extension by creating a temporary in-memory XPI file.
+ * @return {File} the temporary extension XPI file created
+ */
+async function installTemporaryExtensionFromXPI(xpiData, document) {
+ const xpiFile = createTemporaryXPI(xpiData);
+ const extension = await installTemporaryExtension(
+ xpiFile,
+ xpiData.name,
+ document
+ );
+
+ info("Wait until the addon debug target appears");
+ await waitUntil(() => findDebugTargetByText(xpiData.name, document));
+ return { extension, xpiFile };
+}
+/* exported installTemporaryExtensionFromXPI */
+
+async function removeTemporaryExtension(name, document) {
+ info(`Wait for removable extension with name: '${name}'`);
+ const buttonName = ".qa-temporary-extension-remove-button";
+ await waitUntil(() => {
+ const extension = findDebugTargetByText(name, document);
+ return extension && extension.querySelector(buttonName);
+ });
+ info(`Remove the temporary extension with name: '${name}'`);
+ const temporaryExtensionItem = findDebugTargetByText(name, document);
+ temporaryExtensionItem.querySelector(buttonName).click();
+
+ info("Wait until the debug target item disappears");
+ await waitUntil(() => !findDebugTargetByText(name, document));
+}
+/* exported removeTemporaryExtension */
+
+async function removeExtension(id, name, document) {
+ info(
+ "Retrieve the extension instance from the addon manager, and uninstall it"
+ );
+ const extension = await AddonManager.getAddonByID(id);
+ extension.uninstall();
+
+ info("Wait until the addon disappears from about:debugging");
+ await waitUntil(() => !findDebugTargetByText(name, document));
+}
+/* exported removeExtension */
+
+function prepareMockFilePicker(pathOrFile) {
+ const isFile = typeof pathOrFile.isFile === "function" && pathOrFile.isFile();
+ const file = isFile ? pathOrFile : _getSupportsFile(pathOrFile).file;
+
+ // Mock the file picker to select a test addon
+ const MockFilePicker = SpecialPowers.MockFilePicker;
+ MockFilePicker.init(window);
+ MockFilePicker.setFiles([file]);
+}
+/* exported prepareMockFilePicker */
+
+function promiseBackgroundContextEvent(extensionId, eventName) {
+ const { Management } = ChromeUtils.importESModule(
+ "resource://gre/modules/Extension.sys.mjs"
+ );
+
+ return new Promise(resolve => {
+ Management.on(eventName, function listener(_evtName, context) {
+ if (context.extension.id === extensionId) {
+ Management.off(eventName, listener);
+ resolve();
+ }
+ });
+ });
+}
+
+function promiseBackgroundContextLoaded(extensionId) {
+ return promiseBackgroundContextEvent(extensionId, "proxy-context-load");
+}
+/* exported promiseBackgroundContextLoaded */
+
+function promiseBackgroundContextUnloaded(extensionId) {
+ return promiseBackgroundContextEvent(extensionId, "proxy-context-unload");
+}
+/* exported promiseBackgroundContextUnloaded */
+
+async function assertBackgroundStatus(
+ extName,
+ { document, expectedStatus, targetElement }
+) {
+ const target = targetElement || findDebugTargetByText(extName, document);
+ const getBackgroundStatusElement = () =>
+ target.querySelector(".extension-backgroundscript__status");
+ await waitFor(
+ () =>
+ getBackgroundStatusElement()?.classList.contains(
+ `extension-backgroundscript__status--${expectedStatus}`
+ ),
+ `Wait ${extName} Background script status "${expectedStatus}" to be rendered`
+ );
+}
+/* exported assertBackgroundStatus */
+
+function getExtensionInstance(extensionId) {
+ const policy = WebExtensionPolicy.getByID(extensionId);
+ ok(policy, `Got a WebExtensionPolicy instance for ${extensionId}`);
+ ok(policy.extension, `Got an Extension class instance for ${extensionId}`);
+ return policy.extension;
+}
+/* exported getExtensionInstance */
+
+async function triggerExtensionEventPageIdleTimeout(extensionId) {
+ await getExtensionInstance(extensionId).terminateBackground();
+}
+/* exported triggerExtensionEventPageIdleTimeout */
+
+async function wakeupExtensionEventPage(extensionId) {
+ await getExtensionInstance(extensionId).wakeupBackground();
+}
+/* exported wakeupExtensionEventPage */
+
+function promiseTerminateBackgroundScriptIgnored(extensionId) {
+ const extension = getExtensionInstance(extensionId);
+ return new Promise(resolve => {
+ extension.once("background-script-suspend-ignored", resolve);
+ });
+}
+/* exported promiseTerminateBackgroundScriptIgnored */
+
+async function promiseBackgroundStatusUpdate(window) {
+ waitForDispatch(
+ window.AboutDebugging.store,
+ "EXTENSION_BGSCRIPT_STATUS_UPDATED"
+ );
+}
+/* exported promiseBackgroundStatusUpdate */