--- a/browser/base/content/test/webextensions/browser.ini
+++ b/browser/base/content/test/webextensions/browser.ini
@@ -1,10 +1,11 @@
[DEFAULT]
support-files =
+ head.js
file_install_extensions.html
browser_legacy.xpi
browser_legacy_webext.xpi
browser_webext_permissions.xpi
browser_webext_nopermissions.xpi
browser_webext_update1.xpi
browser_webext_update2.xpi
browser_webext_update_icon1.xpi
--- a/browser/base/content/test/webextensions/browser_extension_permissions.js
+++ b/browser/base/content/test/webextensions/browser_extension_permissions.js
@@ -1,58 +1,30 @@
"use strict";
// See but 1340586 for proposal to reorganize permissions tests to
// get rid of this...
requestLongerTimeout(2);
-const BASE = getRootDirectory(gTestPath)
- .replace("chrome://mochitests/content/", "https://example.com/");
-
const INSTALL_PAGE = `${BASE}/file_install_extensions.html`;
const PERMS_XPI = "browser_webext_permissions.xpi";
const NO_PERMS_XPI = "browser_webext_nopermissions.xpi";
const ID = "permissions@test.mozilla.org";
Services.perms.add(makeURI("https://example.com/"), "install",
Services.perms.ALLOW_ACTION);
-registerCleanupFunction(async function() {
- let addon = await AddonManager.getAddonByID(ID);
- if (addon) {
- ok(false, `Addon ${ID} was still installed at the end of the test`);
- addon.uninstall();
- }
-});
-
function isDefaultIcon(icon) {
// These are basically the same icon, but code within webextensions
// generates references to the former and generic add-ons manager code
// generates referces to the latter.
return (icon == "chrome://browser/content/extension.svg" ||
icon == "chrome://mozapps/skin/extensions/extensionGeneric.svg");
}
-function promisePopupNotificationShown(name) {
- return new Promise(resolve => {
- function popupshown() {
- let notification = PopupNotifications.getNotification(name);
- if (!notification) { return; }
-
- ok(notification, `${name} notification shown`);
- ok(PopupNotifications.isPanelOpen, "notification panel open");
-
- PopupNotifications.panel.removeEventListener("popupshown", popupshown);
- resolve(PopupNotifications.panel.firstChild);
- }
-
- PopupNotifications.panel.addEventListener("popupshown", popupshown);
- });
-}
-
function checkNotification(panel, filename) {
let icon = panel.getAttribute("icon");
let ul = document.getElementById("addon-webext-perm-list");
let header = document.getElementById("addon-webext-perm-intro");
if (filename == PERMS_XPI) {
// The icon should come from the extension, don't bother with the precise
--- a/browser/base/content/test/webextensions/browser_extension_sideloading.js
+++ b/browser/base/content/test/webextensions/browser_extension_sideloading.js
@@ -67,41 +67,24 @@ class MockProvider {
let addons = [];
if (!types || types.includes("extension")) {
addons = [...this.addons];
}
callback(addons);
}
}
-function promisePopupNotificationShown(name) {
- return new Promise(resolve => {
- function popupshown() {
- let notification = PopupNotifications.getNotification(name);
- if (!notification) {
- return;
- }
-
- ok(notification, `${name} notification shown`);
- ok(PopupNotifications.isPanelOpen, "notification panel open");
-
- PopupNotifications.panel.removeEventListener("popupshown", popupshown);
- resolve(PopupNotifications.panel.firstChild);
- }
-
- PopupNotifications.panel.addEventListener("popupshown", popupshown);
- });
-}
-
function promiseSetDisabled(addon) {
return new Promise(resolve => {
setCallbacks.set(addon, resolve);
});
}
+let cleanup;
+
add_task(function* () {
// XXX remove this when prompts are enabled by default
yield SpecialPowers.pushPrefEnv({set: [
["extensions.webextPermissionPrompts", true],
]});
// ICON_URL wouldn't ever appear as an actual webextension icon, but
// we're just mocking out the addon here, so all we care about is that
@@ -163,24 +146,25 @@ add_task(function* () {
let provider = new MockProvider(mock1, mock2, mock3, mock4);
AddonManagerPrivate.registerProvider(provider, [{
id: "extension",
name: "Extensions",
uiPriority: 4000,
flags: AddonManager.TYPE_UI_VIEW_LIST |
AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL,
}]);
- registerCleanupFunction(function*() {
+
+ testCleanup = async function() {
AddonManagerPrivate.unregisterProvider(provider);
// clear out ExtensionsUI state about sideloaded extensions so
// subsequent tests don't get confused.
ExtensionsUI.sideloaded.clear();
ExtensionsUI.emit("change");
- });
+ };
// Navigate away from the starting page to force about:addons to load
// in a new tab during the tests below.
gBrowser.selectedBrowser.loadURI("about:robots");
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
registerCleanupFunction(function*() {
// Return to about:blank when we're done
--- a/browser/base/content/test/webextensions/browser_extension_update_background.js
+++ b/browser/base/content/test/webextensions/browser_extension_update_background.js
@@ -1,41 +1,15 @@
const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
-const URL_BASE = "https://example.com/browser/browser/base/content/test/general";
const ID = "update2@tests.mozilla.org";
const ID_ICON = "update_icon2@tests.mozilla.org";
const ID_PERMS = "update_perms@tests.mozilla.org";
const ID_LEGACY = "legacy_update@tests.mozilla.org";
-registerCleanupFunction(async function() {
- for (let id of [ID, ID_ICON, ID_PERMS, ID_LEGACY]) {
- let addon = await AddonManager.getAddonByID(id);
- if (addon) {
- ok(false, `Addon ${id} was still installed at the end of the test`);
- addon.uninstall();
- }
- }
-});
-
-function promiseInstallAddon(url) {
- return AddonManager.getInstallForURL(url, null, "application/x-xpinstall")
- .then(install => {
- ok(install, "Created install");
- return new Promise(resolve => {
- install.addListener({
- onInstallEnded(_install, addon) {
- resolve(addon);
- },
- });
- install.install();
- });
- });
-}
-
function promiseViewLoaded(tab, viewid) {
let win = tab.linkedBrowser.contentWindow;
if (win.gViewController && !win.gViewController.isLoading &&
win.gViewController.currentViewId == viewid) {
return Promise.resolve();
}
return new Promise(resolve => {
@@ -45,51 +19,21 @@ function promiseViewLoaded(tab, viewid)
}
win.document.removeEventListener("ViewChanged", listener);
resolve();
}
win.document.addEventListener("ViewChanged", listener);
});
}
-function promisePopupNotificationShown(name) {
- return new Promise(resolve => {
- function popupshown() {
- let notification = PopupNotifications.getNotification(name);
- if (!notification) { return; }
-
- ok(notification, `${name} notification shown`);
- ok(PopupNotifications.isPanelOpen, "notification panel open");
-
- PopupNotifications.panel.removeEventListener("popupshown", popupshown);
- resolve(PopupNotifications.panel.firstChild);
- }
-
- PopupNotifications.panel.addEventListener("popupshown", popupshown);
- });
-}
-
function getBadgeStatus() {
let menuButton = document.getElementById("PanelUI-menu-button");
return menuButton.getAttribute("badge-status");
}
-function promiseInstallEvent(addon, event) {
- return new Promise(resolve => {
- let listener = {};
- listener[event] = (install, ...args) => {
- if (install.addon.id == addon.id) {
- AddonManager.removeInstallListener(listener);
- resolve(...args);
- }
- };
- AddonManager.addInstallListener(listener);
- });
-}
-
// Set some prefs that apply to all the tests in this file
add_task(function* setup() {
yield SpecialPowers.pushPrefEnv({set: [
// We don't have pre-pinned certificates for the local mochitest server
["extensions.install.requireBuiltInCerts", false],
["extensions.update.requireBuiltInCerts", false],
// XXX remove this when prompts are enabled by default
@@ -110,17 +54,17 @@ add_task(function* setup() {
// Helper function to test background updates.
function* backgroundUpdateTest(url, id, checkIconFn) {
yield SpecialPowers.pushPrefEnv({set: [
// Turn on background updates
["extensions.update.enabled", true],
// Point updates to the local mochitest server
- ["extensions.update.background.url", `${URL_BASE}/browser_webext_update.json`],
+ ["extensions.update.background.url", `${BASE}/browser_webext_update.json`],
]});
// Install version 1.0 of the test extension
let addon = yield promiseInstallAddon(url);
ok(addon, "Addon was installed");
is(getBadgeStatus(), "", "Should not start out with an addon alert badge");
@@ -223,38 +167,38 @@ function* backgroundUpdateTest(url, id,
yield SpecialPowers.popPrefEnv();
}
function checkDefaultIcon(icon) {
is(icon, "chrome://mozapps/skin/extensions/extensionGeneric.svg",
"Popup has the default extension icon");
}
-add_task(() => backgroundUpdateTest(`${URL_BASE}/browser_webext_update1.xpi`,
+add_task(() => backgroundUpdateTest(`${BASE}/browser_webext_update1.xpi`,
ID, checkDefaultIcon));
function checkNonDefaultIcon(icon) {
// The icon should come from the extension, don't bother with the precise
// path, just make sure we've got a jar url pointing to the right path
// inside the jar.
ok(icon.startsWith("jar:file://"), "Icon is a jar url");
ok(icon.endsWith("/icon.png"), "Icon is icon.png inside a jar");
}
-add_task(() => backgroundUpdateTest(`${URL_BASE}/browser_webext_update_icon1.xpi`,
+add_task(() => backgroundUpdateTest(`${BASE}/browser_webext_update_icon1.xpi`,
ID_ICON, checkNonDefaultIcon));
// Helper function to test an upgrade that should not show a prompt
async function testNoPrompt(origUrl, id) {
await SpecialPowers.pushPrefEnv({set: [
// Turn on background updates
["extensions.update.enabled", true],
// Point updates to the local mochitest server
- ["extensions.update.background.url", `${URL_BASE}/browser_webext_update.json`],
+ ["extensions.update.background.url", `${BASE}/browser_webext_update.json`],
]});
// Install version 1.0 of the test extension
let addon = await promiseInstallAddon(origUrl);
ok(addon, "Addon was installed");
let sawPopup = false;
@@ -281,16 +225,16 @@ async function testNoPrompt(origUrl, id)
is(addon.version, "2.0", "Update should have applied");
addon.uninstall();
await SpecialPowers.popPrefEnv();
}
// Test that an update that adds new non-promptable permissions is just
// applied without showing a notification dialog.
-add_task(() => testNoPrompt(`${URL_BASE}/browser_webext_update_perms1.xpi`,
+add_task(() => testNoPrompt(`${BASE}/browser_webext_update_perms1.xpi`,
ID_PERMS));
// Test that an update from a legacy extension to a webextension
// doesn't show a prompt even when the webextension uses
// promptable required permissions.
-add_task(() => testNoPrompt(`${URL_BASE}/browser_legacy.xpi`, ID_LEGACY));
+add_task(() => testNoPrompt(`${BASE}/browser_legacy.xpi`, ID_LEGACY));
--- a/browser/base/content/test/webextensions/browser_extension_update_interactive.js
+++ b/browser/base/content/test/webextensions/browser_extension_update_interactive.js
@@ -1,88 +1,13 @@
const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
-const URL_BASE = "https://example.com/browser/browser/base/content/test/webextensions";
const ID = "update2@tests.mozilla.org";
const ID_LEGACY = "legacy_update@tests.mozilla.org";
-registerCleanupFunction(async function() {
- for (let id of [ID, ID_LEGACY]) {
- let addon = await AddonManager.getAddonByID(id);
- if (addon) {
- ok(false, `Addon ${id} was still installed at the end of the test`);
- addon.uninstall();
- }
- }
-});
-
-function promiseInstallAddon(url) {
- return AddonManager.getInstallForURL(url, null, "application/x-xpinstall")
- .then(install => {
- ok(install, "Created install");
- return new Promise(resolve => {
- install.addListener({
- onInstallEnded(_install, addon) {
- resolve(addon);
- },
- });
- install.install();
- });
- });
-}
-
-function promiseViewLoaded(tab, viewid) {
- let win = tab.linkedBrowser.contentWindow;
- if (win.gViewController && !win.gViewController.isLoading &&
- win.gViewController.currentViewId == viewid) {
- return Promise.resolve();
- }
-
- return new Promise(resolve => {
- function listener() {
- if (win.gViewController.currentViewId != viewid) {
- return;
- }
- win.document.removeEventListener("ViewChanged", listener);
- resolve();
- }
- win.document.addEventListener("ViewChanged", listener);
- });
-}
-
-function promisePopupNotificationShown(name) {
- return new Promise(resolve => {
- function popupshown() {
- let notification = PopupNotifications.getNotification(name);
- if (!notification) { return; }
-
- ok(notification, `${name} notification shown`);
- ok(PopupNotifications.isPanelOpen, "notification panel open");
-
- PopupNotifications.panel.removeEventListener("popupshown", popupshown);
- resolve(PopupNotifications.panel.firstChild);
- }
-
- PopupNotifications.panel.addEventListener("popupshown", popupshown);
- });
-}
-
-function promiseInstallEvent(addon, event) {
- return new Promise(resolve => {
- let listener = {};
- listener[event] = (install, ...args) => {
- if (install.addon.id == addon.id) {
- AddonManager.removeInstallListener(listener);
- resolve(...args);
- }
- };
- AddonManager.addInstallListener(listener);
- });
-}
-
// Set some prefs that apply to all the tests in this file
add_task(function* setup() {
yield SpecialPowers.pushPrefEnv({set: [
// We don't have pre-pinned certificates for the local mochitest server
["extensions.install.requireBuiltInCerts", false],
["extensions.update.requireBuiltInCerts", false],
// XXX remove this when prompts are enabled by default
@@ -94,17 +19,17 @@ add_task(function* setup() {
// `checkFn` is a callable that triggers a check for updates.
// `autoUpdate` specifies whether the test should be run with
// updates applied automatically or not.
function* interactiveUpdateTest(autoUpdate, checkFn) {
yield SpecialPowers.pushPrefEnv({set: [
["extensions.update.autoUpdateDefault", autoUpdate],
// Point updates to the local mochitest server
- ["extensions.update.url", `${URL_BASE}/browser_webext_update.json`],
+ ["extensions.update.url", `${BASE}/browser_webext_update.json`],
]});
// Trigger an update check, manually applying the update if we're testing
// without auto-update.
function* triggerUpdate(win, addon) {
let manualUpdatePromise;
if (!autoUpdate) {
manualUpdatePromise = new Promise(resolve => {
@@ -128,39 +53,27 @@ function* interactiveUpdateTest(autoUpda
// Make sure we have XBL bindings
list.clientHeight;
let item = list.children.find(_item => _item.value == ID);
EventUtils.synthesizeMouseAtCenter(item._updateBtn, {}, win);
}
}
+ // Navigate away from the starting page to force about:addons to load
+ // in a new tab during the tests below.
+ gBrowser.selectedBrowser.loadURI("about:robots");
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
// Install version 1.0 of the test extension
- let addon = yield promiseInstallAddon(`${URL_BASE}/browser_webext_update1.xpi`);
+ let addon = yield promiseInstallAddon(`${BASE}/browser_webext_update1.xpi`);
ok(addon, "Addon was installed");
is(addon.version, "1.0", "Version 1 of the addon is installed");
- // Open add-ons manager and navigate to extensions list
- let loadPromise = new Promise(resolve => {
- let listener = (subject, topic) => {
- if (subject.location.href == "about:addons") {
- Services.obs.removeObserver(listener, topic);
- resolve(subject);
- }
- };
- Services.obs.addObserver(listener, "EM-loaded", false);
- });
- let tab = gBrowser.addTab("about:addons");
- gBrowser.selectedTab = tab;
- let win = yield loadPromise;
-
- const VIEW = "addons://list/extension";
- let viewPromise = promiseViewLoaded(tab, VIEW);
- win.loadView(VIEW);
- yield viewPromise;
+ let win = yield BrowserOpenAddonsMgr("addons://list/extension");
// Trigger an update check
let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
yield triggerUpdate(win, addon);
let panel = yield popupPromise;
// Click the cancel button, wait to see the cancel event
let cancelPromise = promiseInstallEvent(addon, "onInstallCancelled");
@@ -177,17 +90,17 @@ function* interactiveUpdateTest(autoUpda
// This time, accept the upgrade
let updatePromise = promiseInstallEvent(addon, "onInstallEnded");
panel = yield popupPromise;
panel.button.click();
addon = yield updatePromise;
is(addon.version, "2.0", "Should have upgraded");
- yield BrowserTestUtils.removeTab(tab);
+ yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
addon.uninstall();
yield SpecialPowers.popPrefEnv();
}
// Invoke the "Check for Updates" menu item
function checkAll(win) {
win.gViewController.doCommand("cmd_findAllUpdates");
}
@@ -206,25 +119,25 @@ function checkOne(win, addon) {
add_task(() => interactiveUpdateTest(true, checkOne));
add_task(() => interactiveUpdateTest(false, checkOne));
// Check that an update from a legacy extension to a webextensino
// does not display a prompt
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [
// Point updates to the local mochitest server
- ["extensions.update.url", `${URL_BASE}/browser_webext_update.json`],
+ ["extensions.update.url", `${BASE}/browser_webext_update.json`],
]});
// Navigate away to ensure that BrowserOpenAddonMgr() opens a new tab
gBrowser.selectedBrowser.loadURI("about:robots");
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
// Install initial version of the test extension
- let addon = await promiseInstallAddon(`${URL_BASE}/browser_legacy.xpi`);
+ let addon = await promiseInstallAddon(`${BASE}/browser_legacy.xpi`);
ok(addon, "Addon was installed");
is(addon.version, "1.1", "Version 1 of the addon is installed");
// Go to Extensions in about:addons
let win = await BrowserOpenAddonsMgr("addons://list/extension");
let sawPopup = false;
PopupNotifications.panel.addEventListener("popupshown",
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/webextensions/head.js
@@ -0,0 +1,282 @@
+
+const BASE = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content/", "https://example.com/");
+
+/**
+ * Wait for the given PopupNotification to display
+ *
+ * @param {string} name
+ * The name of the notification to wait for.
+ *
+ * @returns {Promise}
+ * Resolves with the notification window.
+ */
+function promisePopupNotificationShown(name) {
+ return new Promise(resolve => {
+ function popupshown() {
+ let notification = PopupNotifications.getNotification(name);
+ if (!notification) { return; }
+
+ ok(notification, `${name} notification shown`);
+ ok(PopupNotifications.isPanelOpen, "notification panel open");
+
+ PopupNotifications.panel.removeEventListener("popupshown", popupshown);
+ resolve(PopupNotifications.panel.firstChild);
+ }
+
+ PopupNotifications.panel.addEventListener("popupshown", popupshown);
+ });
+}
+
+/**
+ * Wait for a specific install event to fire for a given addon
+ *
+ * @param {AddonWrapper} addon
+ * The addon to watch for an event on
+ * @param {string}
+ * The name of the event to watch for (e.g., onInstallEnded)
+ *
+ * @returns {Promise}
+ * Resolves when the event triggers with the first argument
+ * to the event handler as the resolution value.
+ */
+function promiseInstallEvent(addon, event) {
+ return new Promise(resolve => {
+ let listener = {};
+ listener[event] = (install, arg) => {
+ if (install.addon.id == addon.id) {
+ AddonManager.removeInstallListener(listener);
+ resolve(arg);
+ }
+ };
+ AddonManager.addInstallListener(listener);
+ });
+}
+
+/**
+ * Install an (xpi packaged) extension
+ *
+ * @param {string} url
+ * URL of the .xpi file to install
+ *
+ * @returns {Promise}
+ * Resolves when the extension has been installed with the Addon
+ * object as the resolution value.
+ */
+function promiseInstallAddon(url) {
+ return AddonManager.getInstallForURL(url, null, "application/x-xpinstall")
+ .then(install => {
+ ok(install, "Created install");
+ return new Promise(resolve => {
+ install.addListener({
+ onInstallEnded(_install, addon) {
+ resolve(addon);
+ },
+ });
+ install.install();
+ });
+ });
+}
+
+function isDefaultIcon(icon) {
+ // These are basically the same icon, but code within webextensions
+ // generates references to the former and generic add-ons manager code
+ // generates referces to the latter.
+ return (icon == "chrome://browser/content/extension.svg" ||
+ icon == "chrome://mozapps/skin/extensions/extensionGeneric.svg");
+}
+
+function is_hidden(element) {
+ var style = element.ownerGlobal.getComputedStyle(element);
+ if (style.display == "none")
+ return true;
+ if (style.visibility != "visible")
+ return true;
+ if (style.display == "-moz-popup")
+ return ["hiding", "closed"].indexOf(element.state) != -1;
+
+ // Hiding a parent element will hide all its children
+ if (element.parentNode != element.ownerDocument)
+ return is_hidden(element.parentNode);
+
+ return false;
+}
+
+function is_visible(element) {
+ var style = element.ownerGlobal.getComputedStyle(element);
+ if (style.display == "none")
+ return false;
+ if (style.visibility != "visible")
+ return false;
+ if (style.display == "-moz-popup" && element.state != "open")
+ return false;
+
+ // Hiding a parent element will hide all its children
+ if (element.parentNode != element.ownerDocument)
+ return is_visible(element.parentNode);
+
+ return true;
+}
+
+/**
+ * Test that install-time permission prompts work for a given
+ * installation method.
+ *
+ * @param {Function} installFn
+ * Callable that takes the name of an xpi file to install and
+ * starts to install it. Should return a Promise that resolves
+ * when the install is finished or rejects if the install is canceled.
+ *
+ * @returns {Promise}
+ */
+async function testInstallMethod(installFn) {
+ const PERMS_XPI = "browser_webext_permissions.xpi";
+ const NO_PERMS_XPI = "browser_webext_nopermissions.xpi";
+ const ID = "permissions@test.mozilla.org";
+
+ await SpecialPowers.pushPrefEnv({set: [
+ ["extensions.webapi.testing", true],
+ ["extensions.install.requireBuiltInCerts", false],
+
+ // XXX remove this when prompts are enabled by default
+ ["extensions.webextPermissionPrompts", true],
+ ]});
+
+ let testURI = makeURI("https://example.com/");
+ Services.perms.add(testURI, "install", Services.perms.ALLOW_ACTION);
+ registerCleanupFunction(() => Services.perms.remove(testURI, "install"));
+
+ async function runOnce(filename, cancel) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
+
+ let installPromise = new Promise(resolve => {
+ let listener = {
+ onDownloadCancelled() {
+ AddonManager.removeInstallListener(listener);
+ resolve(false);
+ },
+
+ onDownloadFailed() {
+ AddonManager.removeInstallListener(listener);
+ resolve(false);
+ },
+
+ onInstallCancelled() {
+ AddonManager.removeInstallListener(listener);
+ resolve(false);
+ },
+
+ onInstallEnded() {
+ AddonManager.removeInstallListener(listener);
+ resolve(true);
+ },
+
+ onInstallFailed() {
+ AddonManager.removeInstallListener(listener);
+ resolve(false);
+ },
+ };
+ AddonManager.addInstallListener(listener);
+ });
+
+ let installMethodPromise = installFn(filename);
+
+ let panel = await promisePopupNotificationShown("addon-webext-permissions");
+ let icon = panel.getAttribute("icon");
+
+ let ul = document.getElementById("addon-webext-perm-list");
+ let header = document.getElementById("addon-webext-perm-intro");
+
+ if (filename == PERMS_XPI) {
+ // The icon should come from the extension, don't bother with the precise
+ // path, just make sure we've got a jar url pointing to the right path
+ // inside the jar.
+ ok(icon.startsWith("jar:file://"), "Icon is a jar url");
+ ok(icon.endsWith("/icon.png"), "Icon is icon.png inside a jar");
+
+ is(header.getAttribute("hidden"), "", "Permission list header is visible");
+ is(ul.childElementCount, 5, "Permissions list has 5 entries");
+ // Real checking of the contents here is deferred until bug 1316996 lands
+ } else if (filename == NO_PERMS_XPI) {
+ // This extension has no icon, it should have the default
+ ok(isDefaultIcon(icon), "Icon is the default extension icon");
+
+ is(header.getAttribute("hidden"), "true", "Permission list header is hidden");
+ is(ul.childElementCount, 0, "Permissions list has 0 entries");
+ }
+
+ if (cancel) {
+ panel.secondaryButton.click();
+ try {
+ await installMethodPromise;
+ } catch (err) {}
+ } else {
+ // Look for post-install notification
+ let postInstallPromise = promisePopupNotificationShown("addon-installed");
+ panel.button.click();
+
+ // Press OK on the post-install notification
+ panel = await postInstallPromise;
+ panel.button.click();
+
+ await installMethodPromise;
+ }
+
+ let result = await installPromise;
+ let addon = await AddonManager.getAddonByID(ID);
+ if (cancel) {
+ ok(!result, "Installation was cancelled");
+ is(addon, null, "Extension is not installed");
+ } else {
+ ok(result, "Installation completed");
+ isnot(addon, null, "Extension is installed");
+ addon.uninstall();
+ }
+
+ await BrowserTestUtils.removeTab(tab);
+ }
+
+ // A few different tests for each installation method:
+ // 1. Start installation of an extension that requests no permissions,
+ // verify the notification contents, then cancel the install
+ await runOnce(NO_PERMS_XPI, true);
+
+ // 2. Same as #1 but with an extension that requests some permissions.
+ await runOnce(PERMS_XPI, true);
+
+ // 3. Repeat with the same extension from step 2 but this time,
+ // accept the permissions to install the extension. (Then uninstall
+ // the extension to clean up.)
+ await runOnce(PERMS_XPI, false);
+
+ await SpecialPowers.popPrefEnv();
+}
+
+// The tests in this directory install a bunch of extensions but they
+// need to uninstall them before exiting, as a stray leftover extension
+// after one test can foul up subsequent tests.
+// So, add a task to run before any tests that grabs a list of all the
+// add-ons that are pre-installed in the test environment and then checks
+// the list of installed add-ons at the end of the test to make sure no
+// new add-ons have been added.
+// Individual tests can store a cleanup function in the testCleanup global
+// to ensure it gets called before the final check is performed.
+let testCleanup;
+add_task(async function() {
+ let addons = await AddonManager.getAllAddons();
+ let existingAddons = new Set(addons.map(a => a.id));
+
+ registerCleanupFunction(async function() {
+ if (testCleanup) {
+ await testCleanup();
+ testCleanup = null;
+ }
+
+ for (let addon of await AddonManager.getAllAddons()) {
+ if (!existingAddons.has(addon.id)) {
+ ok(false, `Addon ${addon.id} was left installed at the end of the test`);
+ addon.uninstall();
+ }
+ }
+ });
+});