--- a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -82,20 +82,22 @@ function* runTests(options) {
let extension = ExtensionTestUtils.loadExtension({
manifest: options.manifest,
files: options.files || {},
background: `(${background})(${options.getTests})`,
});
+ let browserActionId;
+ function checkDetails(details) {
+ if (!browserActionId) {
+ browserActionId = `${makeWidgetId(extension.id)}-browser-action`;
+ }
- let browserActionId = makeWidgetId(extension.id) + "-browser-action";
-
- function checkDetails(details) {
let button = document.getElementById(browserActionId);
ok(button, "button exists");
let title = details.title || options.manifest.name;
is(getListStyleImage(button), details.icon, "icon URL is correct");
is(button.getAttribute("tooltiptext"), title, "image title is correct");
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js
@@ -251,23 +251,22 @@ add_task(function* testDetailsObjects()
"data/100.png": imageBuffer,
"data/a.png": imageBuffer,
"data/a-x2.png": imageBuffer,
},
});
const RESOLUTION_PREF = "layout.css.devPixelsPerPx";
- let pageActionId = makeWidgetId(extension.id) + "-page-action";
+ yield extension.startup();
+
+ let pageActionId = `${makeWidgetId(extension.id)}-page-action`;
let browserActionWidget = getBrowserActionWidget(extension);
-
- yield extension.startup();
let tests = yield extension.awaitMessage("ready");
-
for (let test of tests) {
extension.sendMessage("setIcon", test);
yield extension.awaitMessage("iconSet");
let browserActionButton = browserActionWidget.forWindow(window).node;
let pageActionImage = document.getElementById(pageActionId);
--- a/browser/components/extensions/test/browser/browser_ext_optionsPage_privileges.js
+++ b/browser/components/extensions/test/browser/browser_ext_optionsPage_privileges.js
@@ -24,20 +24,22 @@ add_task(function* test_tab_options_priv
}).then(tab => {
browser.runtime.sendMessage({msgName: "removeTabId", tabId: tab.id});
}).catch(error => {
browser.test.log(`Error: ${error} :: ${error.stack}`);
browser.test.notifyFail("options-ui-privileges");
});
}
+ const ID = "options_privileges@tests.mozilla.org";
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "temporary",
manifest: {
+ applications: {gecko: {id: ID}},
"permissions": ["tabs"],
"options_ui": {
"page": "options.html",
},
},
files: {
"options.html": `<!DOCTYPE html>
<html>
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
@@ -82,17 +82,17 @@ function* runTests(options) {
let extension = ExtensionTestUtils.loadExtension({
manifest: options.manifest,
files: options.files || {},
background: `(${background})(${options.getTests})`,
});
- let pageActionId = makeWidgetId(extension.id) + "-page-action";
+ let pageActionId;
let currentWindow = window;
let windows = [];
function checkDetails(details) {
let image = currentWindow.document.getElementById(pageActionId);
if (details == null) {
ok(image == null || image.hidden, "image is hidden");
} else {
@@ -106,16 +106,20 @@ function* runTests(options) {
// TODO: Popup URL.
}
}
let testNewWindows = 1;
let awaitFinish = new Promise(resolve => {
extension.onMessage("nextTest", (expecting, testsRemaining) => {
+ if (!pageActionId) {
+ pageActionId = `${makeWidgetId(extension.id)}-page-action`;
+ }
+
checkDetails(expecting);
if (testsRemaining) {
extension.sendMessage("runNextTest");
} else if (testNewWindows) {
testNewWindows--;
BrowserTestUtils.openNewBrowserWindow().then(window => {
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_popup.js
@@ -131,24 +131,24 @@ add_task(function* testPageActionPopup()
browser.pageAction.show(tabId).then(() => {
browser.test.sendMessage("next-test");
});
});
},
},
});
- let pageActionId = makeWidgetId(extension.id) + "-page-action";
- let panelId = makeWidgetId(extension.id) + "-panel";
-
extension.onMessage("send-click", () => {
clickPageAction(extension);
});
+ let pageActionId, panelId;
extension.onMessage("next-test", Task.async(function* (expecting = {}) {
+ pageActionId = `${makeWidgetId(extension.id)}-page-action`;
+ panelId = `${makeWidgetId(extension.id)}-panel`;
let panel = document.getElementById(panelId);
if (expecting.expectClosed) {
ok(panel, "Expect panel to exist");
yield promisePopupShown(panel);
extension.sendMessage("close-popup");
yield promisePopupHidden(panel);
--- a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
@@ -37,16 +37,17 @@ function* loadExtension(options) {
return extension;
}
add_task(function* test_inline_options() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let extension = yield loadExtension({
manifest: {
+ applications: {gecko: {id: "inline_options@tests.mozilla.org"}},
"options_ui": {
"page": "options.html",
},
},
background: function() {
let _optionsPromise;
let awaitOptions = () => {
@@ -130,16 +131,17 @@ add_task(function* test_inline_options()
yield BrowserTestUtils.removeTab(tab);
});
add_task(function* test_tab_options() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let extension = yield loadExtension({
manifest: {
+ applications: {gecko: {id: "tab_options@tests.mozilla.org"}},
"options_ui": {
"page": "options.html",
"open_in_tab": true,
},
},
background: function() {
let _optionsPromise;
@@ -224,17 +226,19 @@ add_task(function* test_tab_options() {
yield extension.awaitFinish("options-ui-tab");
yield extension.unload();
yield BrowserTestUtils.removeTab(tab);
});
add_task(function* test_options_no_manifest() {
let extension = yield loadExtension({
- manifest: {},
+ manifest: {
+ applications: {gecko: {id: "no_options@tests.mozilla.org"}},
+ },
background: function() {
browser.test.log("Try to open options page when not specified in the manifest.");
browser.runtime.openOptionsPage().then(
() => {
browser.test.fail("Opening options page without one specified in the manifest generated an error");
browser.test.notifyFail("options-no-manifest");
--- a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage_uninstall.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage_uninstall.js
@@ -37,16 +37,17 @@ function* loadExtension(options) {
return extension;
}
add_task(function* test_inline_options_uninstall() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let extension = yield loadExtension({
manifest: {
+ applications: {gecko: {id: "inline_options_uninstall@tests.mozilla.org"}},
"options_ui": {
"page": "options.html",
},
},
background: function() {
let _optionsPromise;
let awaitOptions = () => {
--- a/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
@@ -1,16 +1,17 @@
"use strict";
let {AddonManager} = Components.utils.import("resource://gre/modules/AddonManager.jsm", {});
let {Extension} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
function* makeAndInstallXPI(id, backgroundScript, loadedURL) {
- let xpi = Extension.generateXPI(id, {
- background: "(" + backgroundScript.toString() + ")()",
+ let xpi = Extension.generateXPI({
+ manifest: {applications: {gecko: {id}}},
+ background: backgroundScript,
});
SimpleTest.registerCleanupFunction(function cleanupXPI() {
Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
xpi.remove(false);
});
let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, loadedURL);
--- a/testing/mochitest/tests/SimpleTest/ExtensionTestUtils.js
+++ b/testing/mochitest/tests/SimpleTest/ExtensionTestUtils.js
@@ -1,11 +1,11 @@
var ExtensionTestUtils = {};
-ExtensionTestUtils.loadExtension = function(ext, id = null)
+ExtensionTestUtils.loadExtension = function(ext)
{
// Cleanup functions need to be registered differently depending on
// whether we're in browser chrome or plain mochitests.
var registerCleanup;
if (typeof registerCleanupFunction != "undefined") {
registerCleanup = registerCleanupFunction;
} else {
registerCleanup = SimpleTest.registerCleanupFunction.bind(SimpleTest);
@@ -78,17 +78,17 @@ ExtensionTestUtils.loadExtension = funct
} else {
messageQueue.add([msg, ...args]);
checkMessages();
}
},
};
- var extension = SpecialPowers.loadExtension(id, ext, handler);
+ var extension = SpecialPowers.loadExtension(ext, handler);
registerCleanup(() => {
if (extension.state == "pending" || extension.state == "running") {
SimpleTest.ok(false, "Extension left running at test shutdown")
return extension.unload();
} else if (extension.state == "unloading") {
SimpleTest.ok(false, "Extension not fully unloaded at test shutdown")
}
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -565,30 +565,17 @@ SpecialPowersObserverAPI.prototype = {
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
}
case "SPLoadExtension": {
let {Extension} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
let id = aMessage.data.id;
let ext = aMessage.data.ext;
- let extension;
- if (typeof(ext) == "string") {
- let target = "resource://testing-common/extensions/" + ext + "/";
- let resourceHandler = Services.io.getProtocolHandler("resource")
- .QueryInterface(Ci.nsISubstitutingProtocolHandler);
- let resURI = Services.io.newURI(target, null, null);
- let uri = Services.io.newURI(resourceHandler.resolveURI(resURI), null, null);
- extension = new Extension({
- id,
- resourceURI: uri
- });
- } else {
- extension = Extension.generate(id, ext);
- }
+ let extension = Extension.generate(ext);
let resultListener = (...args) => {
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "testResult", args});
};
let messageListener = (...args) => {
args.shift();
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "testMessage", args});
@@ -602,36 +589,44 @@ SpecialPowersObserverAPI.prototype = {
extension.on("test-message", messageListener);
this._extensions.set(id, extension);
return undefined;
}
case "SPStartupExtension": {
- let {ExtensionData} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
+ let {ExtensionData, Management} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
let id = aMessage.data.id;
let extension = this._extensions.get(id);
+ let startupListener = (msg, ext) => {
+ if (ext == extension) {
+ this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionSetId", args: [extension.id]});
+ Management.off("startup", startupListener);
+ }
+ };
+ Management.on("startup", startupListener);
// Make sure the extension passes the packaging checks when
// they're run on a bare archive rather than a running instance,
// as the add-on manager runs them.
let extensionData = new ExtensionData(extension.rootURI);
extensionData.readManifest().then(() => {
return extensionData.initAllLocales();
}).then(() => {
if (extensionData.errors.length) {
return Promise.reject("Extension contains packaging errors");
}
return extension.startup();
}).then(() => {
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionStarted", args: []});
}).catch(e => {
dump(`Extension startup failed: ${e}\n${e.stack}`);
+ Management.off("startup", startupListener);
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionFailed", args: []});
});
return undefined;
}
case "SPExtensionMessage": {
let id = aMessage.data.id;
let extension = this._extensions.get(id);
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1914,21 +1914,22 @@ SpecialPowersAPI.prototype = {
removeServiceWorkerDataForExampleDomain: function() {
this.notifyObserversInParentProcess(null, "browser:purge-domain-data", "example.com");
},
cleanUpSTSData: function(origin, flags) {
return this._sendSyncMessage('SPCleanUpSTSData', {origin: origin, flags: flags || 0});
},
- loadExtension: function(id, ext, handler) {
- if (!id) {
- let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
- id = uuidGenerator.generateUUID().number;
- }
+ _nextExtensionID: 0,
+ loadExtension: function(ext, handler) {
+ // Note, this is not the addon is as used by the AddonManager etc,
+ // this is just an identifier used for specialpowers messaging
+ // between this content process and the chrome process.
+ let id = this._nextExtensionID++;
let resolveStartup, resolveUnload, rejectStartup;
let startupPromise = new Promise((resolve, reject) => {
resolveStartup = resolve;
rejectStartup = reject;
});
let unloadPromise = new Promise(resolve => { resolveUnload = resolve; });
@@ -1937,18 +1938,16 @@ SpecialPowersAPI.prototype = {
});
handler = Cu.waiveXrays(handler);
ext = Cu.waiveXrays(ext);
let sp = this;
let state = "uninitialized";
let extension = {
- id,
-
get state() { return state; },
startup() {
state = "pending";
sp._sendAsyncMessage("SPStartupExtension", {id});
return startupPromise;
},
@@ -1965,16 +1964,18 @@ SpecialPowersAPI.prototype = {
this._sendAsyncMessage("SPLoadExtension", {ext, id});
let listener = (msg) => {
if (msg.data.id == id) {
if (msg.data.type == "extensionStarted") {
state = "running";
resolveStartup();
+ } else if (msg.data.type == "extensionSetId") {
+ extension.id = msg.data.args[0];
} else if (msg.data.type == "extensionFailed") {
state = "failed";
rejectStartup("startup failed");
} else if (msg.data.type == "extensionUnloaded") {
this._removeMessageListener("SPExtensionMessage", listener);
state = "unloaded";
resolveUnload();
} else if (msg.data.type in handler) {
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -63,16 +63,20 @@ XPCOMUtils.defineLazyGetter(this, "requi
let obj = {};
Cu.import("resource://devtools/shared/Loader.jsm", obj);
return obj.require;
});
Cu.import("resource://gre/modules/ExtensionContent.jsm");
Cu.import("resource://gre/modules/ExtensionManagement.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
+ "@mozilla.org/uuid-generator;1",
+ "nsIUUIDGenerator");
+
const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
const CATEGORY_EXTENSION_SCHEMAS = "webextension-schemas";
const CATEGORY_EXTENSION_SCRIPTS = "webextension-scripts";
let schemaURLs = new Set();
if (!AppConstants.RELEASE_BUILD) {
schemaURLs.add("chrome://extensions/content/schemas/experiments.json");
@@ -505,18 +509,17 @@ var UUIDMap = {
let map = this._read();
if (id in map) {
return map[id];
}
let uuid = null;
if (create) {
- let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
- uuid = uuidGenerator.generateUUID().number;
+ uuid = uuidGen.generateUUID().number;
uuid = uuid.slice(1, -1); // Strip { and } off the UUID.
map[id] = uuid;
this._write(map);
}
return uuid;
},
@@ -1156,27 +1159,29 @@ this.ExtensionData = class {
* uninstalles it on shutdown().
*
* @param {string} id
* @param {nsIFile} file
* @param {nsIURI} rootURI
* @param {string} installType
*/
class MockExtension {
- constructor(id, file, rootURI, installType) {
- this.id = id;
+ 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 (extension.id == this.id) {
+ if (this.addon && extension.id == this.addon.id) {
Management.off(eventName, onstartup);
+ this.id = extension.id;
this._extension = extension;
resolve(extension);
}
};
Management.on(eventName, onstartup);
});
this._extension = null;
@@ -1291,21 +1296,20 @@ this.Extension = class extends Extension
* 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 {string} id
* @param {object} data
* @returns {nsIFile}
*/
- static generateXPI(id, data) {
+ static generateXPI(data) {
let manifest = data.manifest;
if (!manifest) {
manifest = {};
}
let files = data.files;
if (!files) {
files = {};
@@ -1319,25 +1323,22 @@ this.Extension = class extends Extension
} else {
if (!(keys[0] in obj)) {
obj[keys[0]] = {};
}
provide(obj[keys[0]], keys.slice(1), value, override);
}
}
- provide(manifest, ["applications", "gecko", "id"], id);
-
provide(manifest, ["name"], "Generated extension");
provide(manifest, ["manifest_version"], 2);
provide(manifest, ["version"], "1.0");
if (data.background) {
- let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
- let bgScript = uuidGenerator.generateUUID().number + ".js";
+ let bgScript = uuidGen.generateUUID().number + ".js";
provide(manifest, ["background", "scripts"], [bgScript], true);
files[bgScript] = data.background;
}
provide(files, ["manifest.json"], manifest);
return this.generateZipFile(files);
@@ -1391,32 +1392,43 @@ this.Extension = class extends Extension
return file;
}
/**
* Generates a new extension using |Extension.generateXPI|, and initializes a
* new |Extension| instance which will execute it.
*
- * @param {string} id
* @param {object} data
* @returns {Extension}
*/
- static generate(id, data) {
- let file = this.generateXPI(id, data);
+ 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(id, file, jarURI, 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,
});
}
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -15,19 +15,16 @@ XPCOMUtils.defineLazyModuleGetter(this,
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
"resource://gre/modules/Schemas.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
-XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator",
- "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
-
/* exported ExtensionTestUtils */
let BASE_MANIFEST = Object.freeze({
"applications": Object.freeze({
"gecko": Object.freeze({
"id": "test@web.ext",
}),
}),
@@ -272,14 +269,14 @@ var ExtensionTestUtils = {
});
let manager = Cc["@mozilla.org/addons/integration;1"].getService(Ci.nsIObserver)
.QueryInterface(Ci.nsITimerCallback);
manager.observe(null, "addons-startup", null);
},
- loadExtension(data, id = uuidGenerator.generateUUID().number) {
- let extension = Extension.generate(id, data);
+ loadExtension(data) {
+ let extension = Extension.generate(data);
return new ExtensionWrapper(extension, this.currentScope);
},
};
--- a/toolkit/components/extensions/test/mochitest/test_chrome_ext_background_debug_global.html
+++ b/toolkit/components/extensions/test/mochitest/test_chrome_ext_background_debug_global.html
@@ -29,45 +29,48 @@ const {
* debugging is actually working correctly end-to-end.
*/
function backgroundScript() {
window.testThing = "test!";
browser.test.notifyPass("background script ran");
}
+const ID = "debug@tests.mozilla.org";
let extensionData = {
useAddonManager: "temporary",
background: "(" + backgroundScript.toString() + ")()",
- manifest: {},
+ manifest: {
+ applications: {gecko: {id: ID}},
+ },
files: {},
};
add_task(function* () {
let extension = ExtensionTestUtils.loadExtension(extensionData);
yield extension.startup();
yield extension.awaitFinish("background script ran");
yield new Promise(function(resolve) {
window.BrowserToolboxProcess.emit("connectionchange", "opened", {
setAddonOptions(id, options) {
- if (id === extension.id) {
+ if (id === ID) {
let context = Cu.waiveXrays(options.global);
ok(context.chrome, "global context has a chrome object");
ok(context.browser, "global context has a browser object");
is("test!", context.testThing, "global context is the background script context");
resolve();
}
},
});
});
let addon = yield new Promise((resolve, reject) => {
- AddonManager.getAddonByID(extension.id, addon => addon ? resolve(addon) : reject());
+ AddonManager.getAddonByID(ID, addon => addon ? resolve(addon) : reject());
});
ok(addon, `Got the addon wrapper for ${addon.id}`);
function waitForDebugGlobalChanges(times, initialAddonInstanceID) {
return new Promise((resolve) => {
AddonManager.addAddonListener({
count: 0,
--- a/toolkit/components/extensions/test/mochitest/test_chrome_ext_storage_cleanup.html
+++ b/toolkit/components/extensions/test/mochitest/test_chrome_ext_storage_cleanup.html
@@ -103,55 +103,58 @@ add_task(function* test_uninstall() {
});
yield SpecialPowers.pushPrefEnv({
set: [["extensions.webextensions.keepStorageOnUninstall", true]],
});
let extension = ExtensionTestUtils.loadExtension({
background: `(${writeData})()`,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["storage"],
},
useAddonManager: "temporary",
- }, ID);
+ });
yield extension.startup();
yield extension.awaitMessage("finished");
yield extension.unload();
// Check that we can still see data we wrote to storage but clear the
// "leave storage" flag so our storaged gets cleared on uninstall.
// This effectively tests the keepUuidOnUninstall logic, which ensures
// that when we read storage again and check that it is cleared, that
// it is actually a meaningful test!
yield SpecialPowers.popPrefEnv();
extension = ExtensionTestUtils.loadExtension({
background: `(${readData})()`,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["storage"],
},
useAddonManager: "temporary",
- }, ID);
+ });
yield extension.startup();
let results = yield extension.awaitMessage("results");
is(results.matchLocalStorage, true, "localStorage data is still present");
is(results.matchIDB, true, "indexedDB data is still present");
is(results.matchBrowserStorage, true, "browser.storage.local data is still present");
yield extension.unload();
// Read again. This time, our data should be gone.
extension = ExtensionTestUtils.loadExtension({
background: `(${readData})()`,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["storage"],
},
useAddonManager: "temporary",
- }, ID);
+ });
yield extension.startup();
results = yield extension.awaitMessage("results");
is(results.matchLocalStorage, false, "localStorage data was cleared");
is(results.matchIDB, false, "indexedDB data was cleared");
is(results.matchBrowserStorage, false, "browser.storage.local data was cleared");
yield extension.unload();
});
--- a/toolkit/components/extensions/test/mochitest/test_ext_contentscript.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_contentscript.html
@@ -40,16 +40,17 @@ add_task(function* test_contentscript()
function contentScript() {
let manifest = browser.runtime.getManifest();
void manifest.applications.gecko.id;
chrome.runtime.sendMessage(["chrome-namespace-ok"]);
}
let extensionData = {
manifest: {
+ applications: {gecko: {id: "contentscript@tests.mozilla.org"}},
content_scripts: [
{
"matches": ["http://mochi.test/*/file_sample.html"],
"js": ["content_script_start.js"],
"run_at": "document_start",
},
{
"matches": ["http://mochi.test/*/file_sample.html"],
--- a/toolkit/components/extensions/test/mochitest/test_ext_contentscript_create_iframe.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_contentscript_create_iframe.html
@@ -76,18 +76,20 @@ add_task(function* test_contentscript_cr
browser.runtime.sendMessage({
name: "content-script-iframe-loaded",
availableAPIs,
manifest,
testGetManifest,
});
}
+ const ID = "contentscript@tests.mozilla.org";
let extensionData = {
manifest: {
+ applications: {gecko: {id: ID}},
content_scripts: [
{
"matches": ["http://mochi.test/*/file_sample.html"],
"js": ["content_script.js"],
"run_at": "document_idle",
},
],
web_accessible_resources: [
--- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_id.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_id.html
@@ -23,29 +23,30 @@ add_task(function* test_runtime_id() {
browser.test.sendMessage("content-id", browser.runtime.id);
}
let uuidGenerator = SpecialPowers.Cc["@mozilla.org/uuid-generator;1"].getService(SpecialPowers.Ci.nsIUUIDGenerator);
let id = uuidGenerator.generateUUID().number;
let extension = ExtensionTestUtils.loadExtension({
manifest: {
+ applications: {gecko: {id}},
"content_scripts": [{
"matches": ["http://mochi.test/*/file_sample.html"],
"run_at": "document_start",
"js": ["content_script.js"],
}],
},
background: `(${background})()`,
files: {
"content_script.js": `(${content})()`,
},
- }, id);
+ });
yield extension.startup();
let backgroundId = yield extension.awaitMessage("background-id");
is(backgroundId, id, "runtime.id from background script is correct");
let win = window.open("file_sample.html");
let contentId = yield extension.awaitMessage("content-id");
is(contentId, id, "runtime.id from content script is correct");
--- a/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
@@ -77,27 +77,31 @@ add_task(function* test_experiments_api(
{"type": "string", "name": "text"},
],
},
],
},
],
});
- let addonFile = Extension.generateXPI("meh@web.extension", {
+ let addonFile = Extension.generateXPI({
manifest: {
+ applications: {gecko: {id: "meh@web.extension"}},
permissions: ["experiments.meh"],
},
background() {
browser.meh.hello("Here I am");
},
});
- let boringAddonFile = Extension.generateXPI("boring@web.extension", {
+ let boringAddonFile = Extension.generateXPI({
+ manifest: {
+ applications: {gecko: {id: "boring@web.extension"}},
+ },
background() {
if (browser.meh) {
browser.meh.hello("Here I should not be");
}
},
});
do_register_cleanup(() => {
--- a/toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js
@@ -1,16 +1,16 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* test_json_parser() {
const ID = "json@test.web.extension";
- let xpi = Extension.generateXPI(ID, {
+ let xpi = Extension.generateXPI({
files: {
"manifest.json": String.raw`{
// This is a manifest.
"applications": {"gecko": {"id": "${ID}"}},
"name": "This \" is // not a comment",
"version": "0.1\\" // , "description": "This is not a description"
}`,
},
--- a/toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js
@@ -21,26 +21,27 @@ function backgroundScript() {
localStorage.clear();
result = "cleared";
}
}
browser.test.sendMessage("result", result);
browser.test.notifyPass("localStorage");
}
+const ID = "test-webextension@mozilla.com";
let extensionData = {
+ manifest: {applications: {gecko: {id: ID}}},
background: backgroundScript,
};
add_task(function* test_localStorage() {
- let id = "test-webextension@mozilla.com";
const RESULTS = ["item1", "item2", "deleted", "cleared", "item1"];
for (let expected of RESULTS) {
- let extension = ExtensionTestUtils.loadExtension(extensionData, id);
+ let extension = ExtensionTestUtils.loadExtension(extensionData);
yield extension.startup();
let actual = yield extension.awaitMessage("result");
yield extension.awaitFinish("localStorage");
yield extension.unload();
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
@@ -83,19 +83,20 @@ add_task(function* test_happy_path() {
}
});
browser.test.sendMessage("ready");
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
yield extension.awaitMessage("ready");
const tests = [
{
data: "this is a string",
what: "simple string",
},
@@ -151,19 +152,20 @@ if (AppConstants.platform == "win") {
browser.test.sendMessage("done");
});
port.postMessage(MSG);
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
yield extension.awaitMessage("done");
let procCount = yield getSubprocessCount();
equal(procCount, 1, "subprocess is still running");
let exitPromise = waitForSubprocessExit();
yield extension.unload();
@@ -190,19 +192,20 @@ add_task(function* test_sendNativeMessag
browser.test.assertEq(expected, received, "Received echoed native message");
browser.test.sendMessage("finished");
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
yield extension.awaitMessage("finished");
// With sendNativeMessage(), the subprocess should be disconnected
// after exchanging a single message.
yield waitForSubprocessExit();
@@ -237,19 +240,20 @@ add_task(function* test_disconnect() {
}
});
browser.test.sendMessage("ready");
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
yield extension.awaitMessage("ready");
extension.sendMessage("send", "test");
let response = yield extension.awaitMessage("message");
equal(response, "test", "Echoed a string");
@@ -290,19 +294,20 @@ add_task(function* test_write_limit() {
} catch (ex) {
browser.test.sendMessage("result", ex.message);
}
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
let errmsg = yield extension.awaitMessage("result");
notEqual(errmsg, null, "native postMessage() failed for overly large message");
yield extension.unload();
yield waitForSubprocessExit();
@@ -328,19 +333,20 @@ add_task(function* test_read_limit() {
browser.test.sendMessage("result", "message");
});
port.postMessage(PAYLOAD);
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
let result = yield extension.awaitMessage("result");
equal(result, "disconnected", "native port disconnected on receiving large message");
yield extension.unload();
yield waitForSubprocessExit();
@@ -409,19 +415,20 @@ add_task(function* test_child_process()
port.onMessage.addListener(msg => {
browser.test.sendMessage("result", msg);
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
let msg = yield extension.awaitMessage("result");
equal(msg.args.length, 2, "Received one command line argument");
equal(msg.args[1], getPath("info.json"), "Command line argument is the path to the native host manifest");
equal(msg.cwd.replace(/^\/private\//, "/"), tmpDir.path,
"Working directory is the directory containing the native appliation");
@@ -438,19 +445,20 @@ add_task(function* test_stderr() {
browser.test.sendMessage("finished");
});
}
let {messages} = yield promiseConsoleOutput(function* () {
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
yield extension.awaitMessage("finished");
yield extension.unload();
yield waitForSubprocessExit();
});
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_perf.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_perf.js
@@ -103,19 +103,20 @@ add_task(function* test_round_trip_perf(
finish();
}
});
next();
});
},
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
let roundTripTime = Infinity;
for (let i = 0; i < MAX_RETRIES && roundTripTime > MAX_ROUND_TRIP_TIME_MS; i++) {
extension.sendMessage("run-tests");
roundTripTime = yield extension.awaitMessage("result");
}
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_unresponsive.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_unresponsive.js
@@ -57,19 +57,20 @@ add_task(function* test_unresponsive_nat
browser.test.sendMessage("ready");
});
port.postMessage(MSG);
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
+ applications: {gecko: {id: ID}},
permissions: ["nativeMessaging"],
},
- }, ID);
+ });
yield extension.startup();
yield extension.awaitMessage("ready");
let procCount = yield getSubprocessCount();
equal(procCount, 1, "subprocess is running");
let exitPromise = waitForSubprocessExit();
--- a/toolkit/components/extensions/test/xpcshell/test_locale_data.js
+++ b/toolkit/components/extensions/test/xpcshell/test_locale_data.js
@@ -4,17 +4,18 @@ Cu.import("resource://gre/modules/Extens
/* globals ExtensionData */
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
function* generateAddon(data) {
let id = uuidGenerator.generateUUID().number;
- let xpi = Extension.generateXPI(id, data);
+ data = Object.assign({applications: {gecko: {id}}}, data);
+ let xpi = Extension.generateXPI(data);
do_register_cleanup(() => {
Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
xpi.remove(false);
});
let fileURI = Services.io.newFileURI(xpi);
let jarURI = NetUtil.newURI(`jar:${fileURI.spec}!/`);
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
@@ -11,17 +11,21 @@ var gOtherAddon;
var gManagerWindow;
var gCategoryUtilities;
var installedAddons = [];
function installAddon(details) {
let id = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
.generateUUID().number;
- let xpi = Extension.generateXPI(id, details);
+ if (!details.manifest) {
+ details.manifest = {};
+ }
+ details.manifest.applications = {gecko: {id}};
+ let xpi = Extension.generateXPI(details);
return AddonManager.installTemporaryAddon(xpi).then(addon => {
SimpleTest.registerCleanupFunction(function() {
addon.uninstall();
Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
xpi.remove(false);
});
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -1280,22 +1280,17 @@ function createTempXPIFile(aData, aExtra
* returns the nsIFile for it. The file will be deleted when the test completes.
*
* @param aData
* The object holding data about the add-on, as expected by
* |Extension.generateXPI|.
* @return A file pointing to the created XPI file
*/
function createTempWebExtensionFile(aData) {
- if (!aData.id) {
- const uuidGenerator = AM_Cc["@mozilla.org/uuid-generator;1"].getService(AM_Ci.nsIUUIDGenerator);
- aData.id = uuidGenerator.generateUUID().number;
- }
-
- let file = Extension.generateXPI(aData.id, aData);
+ let file = Extension.generateXPI(aData);
temp_xpis.push(file);
return file;
}
/**
* Sets the last modified time of the extension, usually to trigger an update
* of its metadata. If the extension is unpacked, this function assumes that
* the extension contains only the install.rdf file.
--- a/toolkit/mozapps/extensions/test/xpcshell/test_update_webextensions.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_update_webextensions.js
@@ -56,18 +56,19 @@ var checkUpdates = Task.async(function*
obj[key] = {};
obj = obj[key];
}
if (!(prop in obj))
obj[prop] = value;
}
- provide(aData, "addon.id", uuidGenerator.generateUUID().number);
- let id = aData.addon.id;
+ let id = uuidGenerator.generateUUID().number;
+ provide(aData, "addon.id", id);
+ provide(aData, "addon.manifest.applications.gecko.id", id);
let updatePath = `/updates/${id}.json`.replace(/[{}]/g, "");
let updateUrl = `http://localhost:${gPort}${updatePath}`
let addonData = { updates: [] };
let manifestJSON = {
addons: { [id]: addonData }
};
@@ -77,16 +78,17 @@ var checkUpdates = Task.async(function*
let awaitInstall = promiseInstallWebExtension(aData.addon);
for (let version of Object.keys(aData.updates)) {
let update = aData.updates[version];
update.version = version;
provide(update, "addon.id", id);
+ provide(update, "addon.manifest.applications.gecko.id", id);
let addon = update.addon;
delete update.addon;
let file;
if (addon.rdf) {
provide(addon, "version", version);
provide(addon, "targetApplications", [{id: TOOLKIT_ID,
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
@@ -28,18 +28,16 @@ function promiseAddonStartup() {
}
function promiseInstallWebExtension(aData) {
let addonFile = createTempWebExtensionFile(aData);
return promiseInstallAllFiles([addonFile]).then(() => {
Services.obs.notifyObservers(addonFile, "flush-cache-entry", null);
return promiseAddonStartup();
- }).then(() => {
- return promiseAddonByID(aData.id);
});
}
add_task(function*() {
equal(GlobalManager.extensionMap.size, 0);
yield Promise.all([
promiseInstallAllFiles([do_get_addon("webextension_1")], true),
@@ -259,59 +257,65 @@ add_task(function*() {
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$/;
- let addon = yield promiseInstallWebExtension({
+ const ID = "webextension@tests.mozilla.org";
+ yield promiseInstallWebExtension({
manifest: {
+ applications: {gecko: {id: ID}},
"options_ui": {
"page": "options.html",
},
},
});
+ let addon = yield promiseAddonByID(ID);
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();
- addon = yield promiseInstallWebExtension({
+ 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_BUILD)
// Experiments are not enabled on release builds.
return;
let addonFile = createTempWebExtensionFile({
- id: "meh@experiment",
manifest: {
+ applications: {gecko: {id: "meh@experiment"}},
"permissions": ["experiments.meh"],
},
});
yield promiseInstallAllFiles([addonFile]);
let addon = yield new Promise(resolve => AddonManager.getAddonByID("meh@experiment", resolve));