diff options
Diffstat (limited to 'devtools/client/aboutdebugging/test/browser/helper-addons.js')
-rw-r--r-- | devtools/client/aboutdebugging/test/browser/helper-addons.js | 262 |
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 */ |