diff options
Diffstat (limited to 'toolkit/components/webextensions/ExtensionTestCommon.jsm')
-rw-r--r-- | toolkit/components/webextensions/ExtensionTestCommon.jsm | 343 |
1 files changed, 0 insertions, 343 deletions
diff --git a/toolkit/components/webextensions/ExtensionTestCommon.jsm b/toolkit/components/webextensions/ExtensionTestCommon.jsm deleted file mode 100644 index 02453ddfd..000000000 --- a/toolkit/components/webextensions/ExtensionTestCommon.jsm +++ /dev/null @@ -1,343 +0,0 @@ -/* 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"; - -/** - * This module contains extension testing helper logic which is common - * between all test suites. - */ - -/* exported ExtensionTestCommon, MockExtension */ - -this.EXPORTED_SYMBOLS = ["ExtensionTestCommon", "MockExtension"]; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.importGlobalProperties(["TextEncoder"]); - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", - "resource://gre/modules/AppConstants.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Extension", - "resource://gre/modules/Extension.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent", - "resource://gre/modules/ExtensionParent.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", - "resource://gre/modules/FileUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); - -XPCOMUtils.defineLazyGetter(this, "apiManager", - () => ExtensionParent.apiManager); - -Cu.import("resource://gre/modules/ExtensionUtils.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "uuidGen", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -const { - flushJarCache, - instanceOf, -} = ExtensionUtils; - -XPCOMUtils.defineLazyGetter(this, "console", ExtensionUtils.getConsole); - - -/** - * A skeleton Extension-like object, used for testing, which installs an - * add-on via the add-on manager when startup() is called, and - * uninstalles it on shutdown(). - * - * @param {string} id - * @param {nsIFile} file - * @param {nsIURI} rootURI - * @param {string} installType - */ -class MockExtension { - constructor(file, rootURI, installType) { - this.id = null; - this.file = file; - this.rootURI = rootURI; - this.installType = installType; - this.addon = null; - - let promiseEvent = eventName => new Promise(resolve => { - let onstartup = (msg, extension) => { - if (this.addon && extension.id == this.addon.id) { - apiManager.off(eventName, onstartup); - - this.id = extension.id; - this._extension = extension; - resolve(extension); - } - }; - apiManager.on(eventName, onstartup); - }); - - this._extension = null; - this._extensionPromise = promiseEvent("startup"); - this._readyPromise = promiseEvent("ready"); - } - - testMessage(...args) { - return this._extension.testMessage(...args); - } - - on(...args) { - this._extensionPromise.then(extension => { - extension.on(...args); - }); - } - - off(...args) { - this._extensionPromise.then(extension => { - extension.off(...args); - }); - } - - startup() { - if (this.installType == "temporary") { - return AddonManager.installTemporaryAddon(this.file).then(addon => { - this.addon = addon; - return this._readyPromise; - }); - } else if (this.installType == "permanent") { - return new Promise((resolve, reject) => { - AddonManager.getInstallForFile(this.file, install => { - let listener = { - onInstallFailed: reject, - onInstallEnded: (install, newAddon) => { - this.addon = newAddon; - resolve(this._readyPromise); - }, - }; - - install.addListener(listener); - install.install(); - }); - }); - } - throw new Error("installType must be one of: temporary, permanent"); - } - - shutdown() { - this.addon.uninstall(); - return this.cleanupGeneratedFile(); - } - - cleanupGeneratedFile() { - flushJarCache(this.file); - return OS.File.remove(this.file.path); - } -} - -class ExtensionTestCommon { - /** - * This code is designed to make it easy to test a WebExtension - * without creating a bunch of files. Everything is contained in a - * single JSON blob. - * - * Properties: - * "background": "<JS code>" - * A script to be loaded as the background script. - * The "background" section of the "manifest" property is overwritten - * if this is provided. - * "manifest": {...} - * Contents of manifest.json - * "files": {"filename1": "contents1", ...} - * Data to be included as files. Can be referenced from the manifest. - * If a manifest file is provided here, it takes precedence over - * a generated one. Always use "/" as a directory separator. - * Directories should appear here only implicitly (as a prefix - * to file names) - * - * To make things easier, the value of "background" and "files"[] can - * be a function, which is converted to source that is run. - * - * The generated extension is stored in the system temporary directory, - * and an nsIFile object pointing to it is returned. - * - * @param {object} data - * @returns {nsIFile} - */ - static generateXPI(data) { - let manifest = data.manifest; - if (!manifest) { - manifest = {}; - } - - let files = data.files; - if (!files) { - files = {}; - } - - function provide(obj, keys, value, override = false) { - if (keys.length == 1) { - if (!(keys[0] in obj) || override) { - obj[keys[0]] = value; - } - } else { - if (!(keys[0] in obj)) { - obj[keys[0]] = {}; - } - provide(obj[keys[0]], keys.slice(1), value, override); - } - } - - provide(manifest, ["name"], "Generated extension"); - provide(manifest, ["manifest_version"], 2); - provide(manifest, ["version"], "1.0"); - - if (data.background) { - let bgScript = uuidGen.generateUUID().number + ".js"; - - provide(manifest, ["background", "scripts"], [bgScript], true); - files[bgScript] = data.background; - } - - provide(files, ["manifest.json"], manifest); - - if (data.embedded) { - // Package this as a webextension embedded inside a legacy - // extension. - - let xpiFiles = { - "install.rdf": `<?xml version="1.0" encoding="UTF-8"?> - <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - <Description about="urn:mozilla:install-manifest" - em:id="${manifest.applications.gecko.id}" - em:name="${manifest.name}" - em:type="2" - em:version="${manifest.version}" - em:description="" - em:hasEmbeddedWebExtension="true" - em:bootstrap="true"> - - <!-- Firefox --> - <em:targetApplication> - <Description - em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}" - em:minVersion="51.0a1" - em:maxVersion="*"/> - </em:targetApplication> - </Description> - </RDF> - `, - - "bootstrap.js": ` - function install() {} - function uninstall() {} - function shutdown() {} - - function startup(data) { - data.webExtension.startup(); - } - `, - }; - - for (let [path, data] of Object.entries(files)) { - xpiFiles[`webextension/${path}`] = data; - } - - files = xpiFiles; - } - - return this.generateZipFile(files); - } - - static generateZipFile(files, baseName = "generated-extension.xpi") { - let ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1", "nsIZipWriter"); - let zipW = new ZipWriter(); - - let file = FileUtils.getFile("TmpD", [baseName]); - file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); - - const MODE_WRONLY = 0x02; - const MODE_TRUNCATE = 0x20; - zipW.open(file, MODE_WRONLY | MODE_TRUNCATE); - - // Needs to be in microseconds for some reason. - let time = Date.now() * 1000; - - function generateFile(filename) { - let components = filename.split("/"); - let path = ""; - for (let component of components.slice(0, -1)) { - path += component + "/"; - if (!zipW.hasEntry(path)) { - zipW.addEntryDirectory(path, time, false); - } - } - } - - for (let filename in files) { - let script = files[filename]; - if (typeof(script) == "function") { - script = "(" + script.toString() + ")()"; - } else if (instanceOf(script, "Object") || instanceOf(script, "Array")) { - script = JSON.stringify(script); - } - - if (!instanceOf(script, "ArrayBuffer")) { - script = new TextEncoder("utf-8").encode(script).buffer; - } - - let stream = Cc["@mozilla.org/io/arraybuffer-input-stream;1"].createInstance(Ci.nsIArrayBufferInputStream); - stream.setData(script, 0, script.byteLength); - - generateFile(filename); - zipW.addEntryStream(filename, time, 0, stream, false); - } - - zipW.close(); - - return file; - } - - /** - * Generates a new extension using |Extension.generateXPI|, and initializes a - * new |Extension| instance which will execute it. - * - * @param {object} data - * @returns {Extension} - */ - static generate(data) { - let file = this.generateXPI(data); - - flushJarCache(file); - Services.ppmm.broadcastAsyncMessage("Extension:FlushJarCache", {path: file.path}); - - let fileURI = Services.io.newFileURI(file); - let jarURI = Services.io.newURI("jar:" + fileURI.spec + "!/", null, null); - - // This may be "temporary" or "permanent". - if (data.useAddonManager) { - return new MockExtension(file, jarURI, data.useAddonManager); - } - - let id; - if (data.manifest) { - if (data.manifest.applications && data.manifest.applications.gecko) { - id = data.manifest.applications.gecko.id; - } else if (data.manifest.browser_specific_settings && data.manifest.browser_specific_settings.gecko) { - id = data.manifest.browser_specific_settings.gecko.id; - } - } - if (!id) { - id = uuidGen.generateUUID().number; - } - - return new Extension({ - id, - resourceURI: jarURI, - cleanupFile: file, - }); - } -} |