summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js')
-rw-r--r--toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js1542
1 files changed, 1542 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js b/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
new file mode 100644
index 0000000000..cab0e91734
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
@@ -0,0 +1,1542 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// TODO(Bug 1789718): adapt to synthetic addon type implemented by the SitePermAddonProvider
+// or remove if redundant, after the deprecated XPIProvider-based implementation is also removed.
+
+const { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+const { ExtensionPermissions } = ChromeUtils.importESModule(
+ "resource://gre/modules/ExtensionPermissions.sys.mjs"
+);
+const { Management } = ChromeUtils.importESModule(
+ "resource://gre/modules/Extension.sys.mjs"
+);
+
+const SECUREROOT =
+ "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
+const PROGRESS_NOTIFICATION = "addon-progress";
+
+const CHROMEROOT = extractChromeRoot(gTestPath);
+
+AddonTestUtils.initMochitest(this);
+
+function waitForTick() {
+ return new Promise(resolve => executeSoon(resolve));
+}
+
+function getObserverTopic(aNotificationId) {
+ let topic = aNotificationId;
+ if (topic == "xpinstall-disabled") {
+ topic = "addon-install-disabled";
+ } else if (topic == "addon-progress") {
+ topic = "addon-install-started";
+ } else if (topic == "addon-installed") {
+ topic = "webextension-install-notify";
+ }
+ return topic;
+}
+
+async function waitForProgressNotification(
+ aPanelOpen = false,
+ aExpectedCount = 1,
+ wantDisabled = true,
+ expectedAnchorID = "unified-extensions-button",
+ win = window
+) {
+ let notificationId = PROGRESS_NOTIFICATION;
+ info("Waiting for " + notificationId + " notification");
+
+ let topic = getObserverTopic(notificationId);
+
+ let observerPromise = new Promise(resolve => {
+ Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+ // Ignore the progress notification unless that is the notification we want
+ if (
+ notificationId != PROGRESS_NOTIFICATION &&
+ aTopic == getObserverTopic(PROGRESS_NOTIFICATION)
+ ) {
+ return;
+ }
+ Services.obs.removeObserver(observer, topic);
+ resolve();
+ }, topic);
+ });
+
+ let panelEventPromise;
+ if (aPanelOpen) {
+ panelEventPromise = Promise.resolve();
+ } else {
+ panelEventPromise = new Promise(resolve => {
+ win.PopupNotifications.panel.addEventListener(
+ "popupshowing",
+ function () {
+ resolve();
+ },
+ { once: true }
+ );
+ });
+ }
+
+ await observerPromise;
+ await panelEventPromise;
+ await waitForTick();
+
+ info("Saw a notification");
+ ok(win.PopupNotifications.isPanelOpen, "Panel should be open");
+ is(
+ win.PopupNotifications.panel.childNodes.length,
+ aExpectedCount,
+ "Should be the right number of notifications"
+ );
+ if (win.PopupNotifications.panel.childNodes.length) {
+ let nodes = Array.from(win.PopupNotifications.panel.childNodes);
+ let notification = nodes.find(
+ n => n.id == notificationId + "-notification"
+ );
+ ok(notification, `Should have seen the right notification`);
+ is(
+ notification.button.hasAttribute("disabled"),
+ wantDisabled,
+ "The install button should be disabled?"
+ );
+
+ let n = win.PopupNotifications.getNotification(PROGRESS_NOTIFICATION);
+ is(
+ n?.anchorElement?.id || n?.anchorElement?.parentElement?.id,
+ expectedAnchorID,
+ "expected the right anchor ID"
+ );
+ }
+
+ return win.PopupNotifications.panel;
+}
+
+function acceptAppMenuNotificationWhenShown(
+ id,
+ extensionId,
+ {
+ dismiss = false,
+ checkIncognito = false,
+ incognitoChecked = false,
+ incognitoHidden = false,
+ global = window,
+ } = {}
+) {
+ const { AppMenuNotifications, PanelUI, document } = global;
+ return new Promise(resolve => {
+ let permissionChangePromise = null;
+ function appMenuPopupHidden() {
+ PanelUI.panel.removeEventListener("popuphidden", appMenuPopupHidden);
+ ok(
+ !PanelUI.menuButton.hasAttribute("badge-status"),
+ "badge is not set after addon-installed"
+ );
+ resolve(permissionChangePromise);
+ }
+ function appMenuPopupShown() {
+ PanelUI.panel.removeEventListener("popupshown", appMenuPopupShown);
+ PanelUI.menuButton.click();
+ }
+ function popupshown() {
+ let notification = AppMenuNotifications.activeNotification;
+ if (!notification) {
+ return;
+ }
+
+ is(notification.id, id, `${id} notification shown`);
+ ok(PanelUI.isNotificationPanelOpen, "notification panel open");
+
+ PanelUI.notificationPanel.removeEventListener("popupshown", popupshown);
+
+ let checkbox = document.getElementById("addon-incognito-checkbox");
+ is(checkbox.hidden, incognitoHidden, "checkbox visibility is correct");
+ is(checkbox.checked, incognitoChecked, "checkbox is marked as expected");
+
+ // If we're unchecking or checking the incognito property, this will
+ // trigger an update in ExtensionPermission, let's wait for it before
+ // returning from this promise.
+ if (incognitoChecked != checkIncognito) {
+ permissionChangePromise = new Promise(resolve => {
+ const listener = (type, change) => {
+ if (extensionId == change.extensionId) {
+ // Let's make sure we received the right message
+ let { permissions } = checkIncognito
+ ? change.added
+ : change.removed;
+ ok(permissions.includes("internal:privateBrowsingAllowed"));
+ resolve();
+ }
+ };
+ Management.once("change-permissions", listener);
+ });
+ }
+
+ checkbox.checked = checkIncognito;
+
+ if (dismiss) {
+ // Dismiss the panel by clicking on the appMenu button.
+ PanelUI.panel.addEventListener("popupshown", appMenuPopupShown);
+ PanelUI.panel.addEventListener("popuphidden", appMenuPopupHidden);
+ PanelUI.menuButton.click();
+ return;
+ }
+
+ // Dismiss the panel by clicking the primary button.
+ let popupnotificationID = PanelUI._getPopupId(notification);
+ let popupnotification = document.getElementById(popupnotificationID);
+
+ popupnotification.button.click();
+ resolve(permissionChangePromise);
+ }
+ PanelUI.notificationPanel.addEventListener("popupshown", popupshown);
+ });
+}
+
+async function waitForNotification(
+ aId,
+ aExpectedCount = 1,
+ expectedAnchorID = "unified-extensions-button",
+ win = window
+) {
+ info("Waiting for " + aId + " notification");
+
+ let topic = getObserverTopic(aId);
+
+ let observerPromise;
+ if (aId !== "addon-webext-permissions") {
+ observerPromise = new Promise(resolve => {
+ Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+ // Ignore the progress notification unless that is the notification we want
+ if (
+ aId != PROGRESS_NOTIFICATION &&
+ aTopic == getObserverTopic(PROGRESS_NOTIFICATION)
+ ) {
+ return;
+ }
+ Services.obs.removeObserver(observer, topic);
+ resolve();
+ }, topic);
+ });
+ }
+
+ let panelEventPromise = new Promise(resolve => {
+ win.PopupNotifications.panel.addEventListener(
+ "PanelUpdated",
+ function eventListener(e) {
+ // Skip notifications that are not the one that we are supposed to be looking for
+ if (!e.detail.includes(aId)) {
+ return;
+ }
+ win.PopupNotifications.panel.removeEventListener(
+ "PanelUpdated",
+ eventListener
+ );
+ resolve();
+ }
+ );
+ });
+
+ await observerPromise;
+ await panelEventPromise;
+ await waitForTick();
+
+ info("Saw a " + aId + " notification");
+ ok(win.PopupNotifications.isPanelOpen, "Panel should be open");
+ is(
+ win.PopupNotifications.panel.childNodes.length,
+ aExpectedCount,
+ "Should be the right number of notifications"
+ );
+ if (win.PopupNotifications.panel.childNodes.length) {
+ let nodes = Array.from(win.PopupNotifications.panel.childNodes);
+ let notification = nodes.find(n => n.id == aId + "-notification");
+ ok(notification, "Should have seen the " + aId + " notification");
+
+ let n = win.PopupNotifications.getNotification(aId);
+ is(
+ n?.anchorElement?.id || n?.anchorElement?.parentElement?.id,
+ expectedAnchorID,
+ "expected the right anchor ID"
+ );
+ }
+ await SimpleTest.promiseFocus(win.PopupNotifications.window);
+
+ return win.PopupNotifications.panel;
+}
+
+function waitForNotificationClose(win = window) {
+ if (!win.PopupNotifications.isPanelOpen) {
+ return Promise.resolve();
+ }
+ return new Promise(resolve => {
+ info("Waiting for notification to close");
+ win.PopupNotifications.panel.addEventListener(
+ "popuphidden",
+ function () {
+ resolve();
+ },
+ { once: true }
+ );
+ });
+}
+
+async function waitForInstallDialog(id = "addon-webext-permissions") {
+ let panel = await waitForNotification(id);
+ return panel.childNodes[0];
+}
+
+function removeTabAndWaitForNotificationClose() {
+ let closePromise = waitForNotificationClose();
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ return closePromise;
+}
+
+function acceptInstallDialog(installDialog) {
+ installDialog.button.click();
+}
+
+async function waitForSingleNotification(aCallback) {
+ while (PopupNotifications.panel.childNodes.length != 1) {
+ await new Promise(resolve => executeSoon(resolve));
+
+ info("Waiting for single notification");
+ // Notification should never close while we wait
+ ok(PopupNotifications.isPanelOpen, "Notification should still be open");
+ }
+}
+
+function setupRedirect(aSettings) {
+ var url =
+ "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs?mode=setup";
+ for (var name in aSettings) {
+ url += "&" + name + "=" + aSettings[name];
+ }
+
+ var req = new XMLHttpRequest();
+ req.open("GET", url, false);
+ req.send(null);
+}
+
+var TESTS = [
+ async function test_disabledInstall() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["xpinstall.enabled", false]],
+ });
+ let notificationPromise = waitForNotification("xpinstall-disabled");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "amosigned.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.button.label,
+ "Enable",
+ "Should have seen the right button"
+ );
+ is(
+ notification.getAttribute("label"),
+ "Software installation is currently disabled. Click Enable and try again.",
+ "notification label is correct"
+ );
+
+ let closePromise = waitForNotificationClose();
+ // Click on Enable
+ EventUtils.synthesizeMouseAtCenter(notification.button, {});
+ await closePromise;
+
+ try {
+ ok(
+ Services.prefs.getBoolPref("xpinstall.enabled"),
+ "Installation should be enabled"
+ );
+ } catch (e) {
+ ok(false, "xpinstall.enabled should be set");
+ }
+
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Shouldn't be any pending installs");
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_blockedInstall() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.postDownloadThirdPartyPrompt", false]],
+ });
+
+ let notificationPromise = waitForNotification("addon-install-blocked");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "amosigned.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.button.label,
+ "Continue to Installation",
+ "Should have seen the right button"
+ );
+ is(
+ notification
+ .querySelector("#addon-install-blocked-info")
+ .getAttribute("href"),
+ Services.urlFormatter.formatURLPref("app.support.baseURL") +
+ "unlisted-extensions-risks",
+ "Got the expected SUMO page as a learn more link in the addon-install-blocked panel"
+ );
+ let message = panel.ownerDocument.getElementById(
+ "addon-install-blocked-message"
+ );
+ is(
+ message.textContent,
+ "You are attempting to install an add-on from example.com. Make sure you trust this site before continuing.",
+ "Should have seen the right message"
+ );
+
+ let dialogPromise = waitForInstallDialog();
+ // Click on Allow
+ EventUtils.synthesizeMouse(notification.button, 20, 10, {});
+
+ // Notification should have changed to progress notification
+ ok(PopupNotifications.isPanelOpen, "Notification should still be open");
+ notification = panel.childNodes[0];
+ is(
+ notification.id,
+ "addon-progress-notification",
+ "Should have seen the progress notification"
+ );
+
+ let installDialog = await dialogPromise;
+
+ notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "amosigned-xpi@tests.mozilla.org"
+ );
+
+ installDialog.button.click();
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+ await addon.uninstall();
+
+ await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_blockedInstallDomain() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.postDownloadThirdPartyPrompt", true],
+ ["extensions.install_origins.enabled", true],
+ ],
+ });
+
+ let progressPromise = waitForProgressNotification();
+ let notificationPromise = waitForNotification("addon-install-failed");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: TESTROOT2 + "webmidi_permission.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ await progressPromise;
+ let panel = await notificationPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.getAttribute("label"),
+ "The add-on WebMIDI test addon can not be installed from this location.",
+ "Should have seen the right message"
+ );
+
+ await removeTabAndWaitForNotificationClose();
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_allowedInstallDomain() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.postDownloadThirdPartyPrompt", true],
+ ["extensions.install_origins.enabled", true],
+ ],
+ });
+
+ let notificationPromise = waitForNotification("addon-install-blocked");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: TESTROOT + "webmidi_permission.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.button.label,
+ "Continue to Installation",
+ "Should have seen the right button"
+ );
+ let message = panel.ownerDocument.getElementById(
+ "addon-install-blocked-message"
+ );
+ is(
+ message.textContent,
+ "You are attempting to install an add-on from example.com. Make sure you trust this site before continuing.",
+ "Should have seen the right message"
+ );
+
+ // Next we get the permissions prompt, which also warns of the unsigned state of the addon
+ notificationPromise = waitForNotification("addon-webext-permissions");
+ // Click on Allow on the 3rd party panel
+ notification.button.click();
+ panel = await notificationPromise;
+ notification = panel.childNodes[0];
+
+ is(notification.button.label, "Add", "Should have seen the right button");
+
+ is(
+ notification.id,
+ "addon-webext-permissions-notification",
+ "Should have seen the permissions panel"
+ );
+ let singlePerm = panel.ownerDocument.getElementById(
+ "addon-webext-perm-single-entry"
+ );
+ is(
+ singlePerm.textContent,
+ "Access MIDI devices",
+ "Should have seen the right permission text"
+ );
+
+ notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "webmidi@test.mozilla.org",
+ { incognitoHidden: false, checkIncognito: true }
+ );
+
+ // Click on Allow on the permissions panel
+ notification.button.click();
+
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID("webmidi@test.mozilla.org");
+ await TestUtils.topicObserved("webextension-sitepermissions-startup");
+
+ // This addon should have a site permission with private browsing.
+ let uri = Services.io.newURI(addon.siteOrigin);
+ let pbPrincipal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {
+ privateBrowsingId: 1,
+ }
+ );
+ let permission = Services.perms.testExactPermissionFromPrincipal(
+ pbPrincipal,
+ "midi"
+ );
+ is(
+ permission,
+ Services.perms.ALLOW_ACTION,
+ "api access in private browsing granted"
+ );
+
+ await addon.uninstall();
+
+ // Verify the permission has not been retained.
+ let { permissions } = await ExtensionPermissions.get(
+ "webmidi@test.mozilla.org"
+ );
+ ok(
+ !permissions.includes("internal:privateBrowsingAllowed"),
+ "permission is not set after uninstall"
+ );
+
+ await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_blockedPostDownload() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.postDownloadThirdPartyPrompt", true]],
+ });
+
+ let notificationPromise = waitForNotification("addon-install-blocked");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "amosigned.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.button.label,
+ "Continue to Installation",
+ "Should have seen the right button"
+ );
+ let message = panel.ownerDocument.getElementById(
+ "addon-install-blocked-message"
+ );
+ is(
+ message.textContent,
+ "You are attempting to install an add-on from example.com. Make sure you trust this site before continuing.",
+ "Should have seen the right message"
+ );
+
+ let dialogPromise = waitForInstallDialog();
+ // Click on Allow
+ EventUtils.synthesizeMouse(notification.button, 20, 10, {});
+
+ let installDialog = await dialogPromise;
+
+ notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "amosigned-xpi@tests.mozilla.org"
+ );
+
+ installDialog.button.click();
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+ await addon.uninstall();
+
+ await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_recommendedPostDownload() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.postDownloadThirdPartyPrompt", true]],
+ });
+
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "recommended.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+
+ let installDialog = await waitForInstallDialog();
+
+ let notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "{811d77f1-f306-4187-9251-b4ff99bad60b}"
+ );
+
+ installDialog.button.click();
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID(
+ "{811d77f1-f306-4187-9251-b4ff99bad60b}"
+ );
+ await addon.uninstall();
+
+ await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_priviledgedNo3rdPartyPrompt() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.postDownloadThirdPartyPrompt", true]],
+ });
+ AddonManager.checkUpdateSecurity = false;
+ registerCleanupFunction(() => {
+ AddonManager.checkUpdateSecurity = true;
+ });
+
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "privileged.xpi",
+ })
+ );
+
+ let installDialogPromise = waitForInstallDialog();
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+
+ let notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "test@tests.mozilla.org",
+ { incognitoHidden: true }
+ );
+
+ (await installDialogPromise).button.click();
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID("test@tests.mozilla.org");
+ await addon.uninstall();
+
+ await BrowserTestUtils.removeTab(tab);
+ await SpecialPowers.popPrefEnv();
+ AddonManager.checkUpdateSecurity = true;
+ },
+
+ async function test_permaBlockInstall() {
+ let notificationPromise = waitForNotification("addon-install-blocked");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "amosigned.xpi",
+ })
+ );
+ let target = TESTROOT + "installtrigger.html?" + triggers;
+
+ BrowserTestUtils.openNewForegroundTab(gBrowser, target);
+ let notification = (await notificationPromise).firstElementChild;
+ let neverAllowBtn = notification.menupopup.firstElementChild;
+
+ neverAllowBtn.click();
+
+ await TestUtils.waitForCondition(
+ () => !PopupNotifications.isPanelOpen,
+ "Waiting for notification to close"
+ );
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let installPerm = PermissionTestUtils.testPermission(
+ gBrowser.currentURI,
+ "install"
+ );
+ is(
+ installPerm,
+ Ci.nsIPermissionManager.DENY_ACTION,
+ "Addon installation should be blocked for site"
+ );
+
+ await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ PermissionTestUtils.remove(target, "install");
+ },
+
+ async function test_permaBlockedInstallNoPrompt() {
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "amosigned.xpi",
+ })
+ );
+ let target = TESTROOT + "installtrigger.html?" + triggers;
+
+ PermissionTestUtils.add(target, "install", Services.perms.DENY_ACTION);
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, target);
+
+ let panelOpened;
+ try {
+ panelOpened = await TestUtils.waitForCondition(
+ () => PopupNotifications.isPanelOpen,
+ 100,
+ 10
+ );
+ } catch (ex) {
+ panelOpened = false;
+ }
+ is(panelOpened, false, "Addon prompt should not open");
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ PermissionTestUtils.remove(target, "install");
+ },
+
+ async function test_whitelistedInstall() {
+ let originalTab = gBrowser.selectedTab;
+ let tab;
+ gBrowser.selectedTab = originalTab;
+ PermissionTestUtils.add(
+ "http://example.com/",
+ "install",
+ Services.perms.ALLOW_ACTION
+ );
+
+ let progressPromise = waitForProgressNotification();
+ let dialogPromise = waitForInstallDialog();
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "amosigned.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ ).then(newTab => (tab = newTab));
+ await progressPromise;
+ let installDialog = await dialogPromise;
+ await BrowserTestUtils.waitForCondition(
+ () => !!tab,
+ "tab should be present"
+ );
+
+ is(
+ gBrowser.selectedTab,
+ tab,
+ "tab selected in response to the addon-install-confirmation notification"
+ );
+
+ let notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "amosigned-xpi@tests.mozilla.org",
+ { dismiss: true }
+ );
+ acceptInstallDialog(installDialog);
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+
+ // Test that the addon does not have permission. Reload it to ensure it would
+ // have been set if possible.
+ await addon.reload();
+ let policy = WebExtensionPolicy.getByID(addon.id);
+ ok(
+ !policy.privateBrowsingAllowed,
+ "private browsing permission was not granted"
+ );
+
+ await addon.uninstall();
+
+ PermissionTestUtils.remove("http://example.com/", "install");
+
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_failedDownload() {
+ PermissionTestUtils.add(
+ "http://example.com/",
+ "install",
+ Services.perms.ALLOW_ACTION
+ );
+
+ let progressPromise = waitForProgressNotification();
+ let failPromise = waitForNotification("addon-install-failed");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "missing.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ await progressPromise;
+ let panel = await failPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.getAttribute("label"),
+ "The add-on could not be downloaded because of a connection failure.",
+ "Should have seen the right message"
+ );
+
+ PermissionTestUtils.remove("http://example.com/", "install");
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_corruptFile() {
+ PermissionTestUtils.add(
+ "http://example.com/",
+ "install",
+ Services.perms.ALLOW_ACTION
+ );
+
+ let progressPromise = waitForProgressNotification();
+ let failPromise = waitForNotification("addon-install-failed");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "corrupt.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ await progressPromise;
+ let panel = await failPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.getAttribute("label"),
+ "The add-on downloaded from this site could not be installed " +
+ "because it appears to be corrupt.",
+ "Should have seen the right message"
+ );
+
+ PermissionTestUtils.remove("http://example.com/", "install");
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_incompatible() {
+ PermissionTestUtils.add(
+ "http://example.com/",
+ "install",
+ Services.perms.ALLOW_ACTION
+ );
+
+ let progressPromise = waitForProgressNotification();
+ let failPromise = waitForNotification("addon-install-failed");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "incompatible.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ await progressPromise;
+ let panel = await failPromise;
+
+ let notification = panel.childNodes[0];
+ let brandBundle = Services.strings.createBundle(
+ "chrome://branding/locale/brand.properties"
+ );
+ let brandShortName = brandBundle.GetStringFromName("brandShortName");
+ let message = `XPI Test could not be installed because it is not compatible with ${brandShortName} ${Services.appinfo.version}.`;
+ is(
+ notification.getAttribute("label"),
+ message,
+ "Should have seen the right message"
+ );
+
+ PermissionTestUtils.remove("http://example.com/", "install");
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_localFile() {
+ let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(
+ Ci.nsIChromeRegistry
+ );
+ let path;
+ try {
+ path = cr.convertChromeURL(makeURI(CHROMEROOT + "corrupt.xpi")).spec;
+ } catch (ex) {
+ path = CHROMEROOT + "corrupt.xpi";
+ }
+
+ let failPromise = new Promise(resolve => {
+ Services.obs.addObserver(function observer() {
+ Services.obs.removeObserver(observer, "addon-install-failed");
+ resolve();
+ }, "addon-install-failed");
+ });
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ BrowserTestUtils.loadURIString(gBrowser, path);
+ await failPromise;
+
+ // Wait for the browser code to add the failure notification
+ await waitForSingleNotification();
+
+ let notification = PopupNotifications.panel.childNodes[0];
+ is(
+ notification.id,
+ "addon-install-failed-notification",
+ "Should have seen the install fail"
+ );
+ is(
+ notification.getAttribute("label"),
+ "This add-on could not be installed because it appears to be corrupt.",
+ "Should have seen the right message"
+ );
+
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_urlBar() {
+ let progressPromise = waitForProgressNotification();
+ let dialogPromise = waitForInstallDialog();
+
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ gURLBar.value = TESTROOT + "amosigned.xpi";
+ gURLBar.focus();
+ EventUtils.synthesizeKey("KEY_Enter");
+
+ await progressPromise;
+ let installDialog = await dialogPromise;
+
+ let notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "amosigned-xpi@tests.mozilla.org",
+ { checkIncognito: true }
+ );
+ installDialog.button.click();
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+ // The panel is reloading the addon due to the permission change, we need some way
+ // to wait for the reload to finish. addon.startupPromise doesn't do it for
+ // us, so we'll just restart again.
+ await addon.reload();
+
+ // This addon should have private browsing permission.
+ let policy = WebExtensionPolicy.getByID(addon.id);
+ ok(policy.privateBrowsingAllowed, "private browsing permission granted");
+
+ await addon.uninstall();
+
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_wrongHost() {
+ let requestedUrl = TESTROOT2 + "enabled.html";
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
+
+ let loadedPromise = BrowserTestUtils.browserLoaded(
+ gBrowser.selectedBrowser,
+ false,
+ requestedUrl
+ );
+ BrowserTestUtils.loadURIString(gBrowser, TESTROOT2 + "enabled.html");
+ await loadedPromise;
+
+ let progressPromise = waitForProgressNotification();
+ let notificationPromise = waitForNotification("addon-install-failed");
+ BrowserTestUtils.loadURIString(gBrowser, TESTROOT + "corrupt.xpi");
+ await progressPromise;
+ let panel = await notificationPromise;
+
+ let notification = panel.childNodes[0];
+ is(
+ notification.getAttribute("label"),
+ "The add-on downloaded from this site could not be installed " +
+ "because it appears to be corrupt.",
+ "Should have seen the right message"
+ );
+
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_renotifyBlocked() {
+ let notificationPromise = waitForNotification("addon-install-blocked");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "amosigned.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+
+ let closePromise = waitForNotificationClose();
+ // hide the panel (this simulates the user dismissing it)
+ panel.hidePopup();
+ await closePromise;
+
+ info("Timeouts after this probably mean bug 589954 regressed");
+
+ await new Promise(resolve => executeSoon(resolve));
+
+ notificationPromise = waitForNotification("addon-install-blocked");
+ BrowserTestUtils.loadURIString(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 2, "Should be two pending installs");
+
+ await removeTabAndWaitForNotificationClose(gBrowser.selectedTab);
+
+ installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should have cancelled the installs");
+ },
+
+ async function test_cancel() {
+ PermissionTestUtils.add(
+ "http://example.com/",
+ "install",
+ Services.perms.ALLOW_ACTION
+ );
+
+ let notificationPromise = waitForNotification(PROGRESS_NOTIFICATION);
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "slowinstall.sjs?file=amosigned.xpi",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+ let notification = panel.childNodes[0];
+
+ ok(PopupNotifications.isPanelOpen, "Notification should still be open");
+ is(
+ PopupNotifications.panel.childNodes.length,
+ 1,
+ "Should be only one notification"
+ );
+ is(
+ notification.id,
+ "addon-progress-notification",
+ "Should have seen the progress notification"
+ );
+
+ // Cancel the download
+ let install = notification.notification.options.installs[0];
+ let cancelledPromise = new Promise(resolve => {
+ install.addListener({
+ onDownloadCancelled() {
+ install.removeListener(this);
+ resolve();
+ },
+ });
+ });
+ EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
+ await cancelledPromise;
+
+ await waitForTick();
+
+ ok(!PopupNotifications.isPanelOpen, "Notification should be closed");
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending install");
+
+ PermissionTestUtils.remove("http://example.com/", "install");
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ },
+
+ async function test_failedSecurity() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_INSTALL_REQUIREBUILTINCERTS, false],
+ ["extensions.postDownloadThirdPartyPrompt", false],
+ ],
+ });
+
+ setupRedirect({
+ Location: TESTROOT + "amosigned.xpi",
+ });
+
+ let notificationPromise = waitForNotification("addon-install-blocked");
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: "redirect.sjs?mode=redirect",
+ })
+ );
+ BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ SECUREROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+
+ let notification = panel.childNodes[0];
+ // Click on Allow
+ EventUtils.synthesizeMouse(notification.button, 20, 10, {});
+
+ // Notification should have changed to progress notification
+ ok(PopupNotifications.isPanelOpen, "Notification should still be open");
+ is(
+ PopupNotifications.panel.childNodes.length,
+ 1,
+ "Should be only one notification"
+ );
+ notification = panel.childNodes[0];
+ is(
+ notification.id,
+ "addon-progress-notification",
+ "Should have seen the progress notification"
+ );
+
+ // Wait for it to fail
+ await new Promise(resolve => {
+ Services.obs.addObserver(function observer() {
+ Services.obs.removeObserver(observer, "addon-install-failed");
+ resolve();
+ }, "addon-install-failed");
+ });
+
+ // Allow the browser code to add the failure notification and then wait
+ // for the progress notification to dismiss itself
+ await waitForSingleNotification();
+ is(
+ PopupNotifications.panel.childNodes.length,
+ 1,
+ "Should be only one notification"
+ );
+ notification = panel.childNodes[0];
+ is(
+ notification.id,
+ "addon-install-failed-notification",
+ "Should have seen the install fail"
+ );
+
+ await removeTabAndWaitForNotificationClose();
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_incognito_checkbox() {
+ // Grant permission up front.
+ const permissionName = "internal:privateBrowsingAllowed";
+ let incognitoPermission = {
+ permissions: [permissionName],
+ origins: [],
+ };
+ await ExtensionPermissions.add(
+ "amosigned-xpi@tests.mozilla.org",
+ incognitoPermission
+ );
+
+ let progressPromise = waitForProgressNotification();
+ let dialogPromise = waitForInstallDialog();
+
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ gURLBar.value = TESTROOT + "amosigned.xpi";
+ gURLBar.focus();
+ EventUtils.synthesizeKey("KEY_Enter");
+
+ await progressPromise;
+ let installDialog = await dialogPromise;
+
+ let notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "amosigned-xpi@tests.mozilla.org",
+ { incognitoChecked: true }
+ );
+ installDialog.button.click();
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+ // The panel is reloading the addon due to the permission change, we need some way
+ // to wait for the reload to finish. addon.startupPromise doesn't do it for
+ // us, so we'll just restart again.
+ await AddonTestUtils.promiseWebExtensionStartup(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+
+ // This addon should no longer have private browsing permission.
+ let policy = WebExtensionPolicy.getByID(addon.id);
+ ok(!policy.privateBrowsingAllowed, "private browsing permission removed");
+
+ await addon.uninstall();
+
+ await removeTabAndWaitForNotificationClose();
+ },
+
+ async function test_incognito_checkbox_new_window() {
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await SimpleTest.promiseFocus(win);
+ // Grant permission up front.
+ const permissionName = "internal:privateBrowsingAllowed";
+ let incognitoPermission = {
+ permissions: [permissionName],
+ origins: [],
+ };
+ await ExtensionPermissions.add(
+ "amosigned-xpi@tests.mozilla.org",
+ incognitoPermission
+ );
+
+ let panelEventPromise = new Promise(resolve => {
+ win.PopupNotifications.panel.addEventListener(
+ "PanelUpdated",
+ function eventListener(e) {
+ if (e.detail.includes("addon-webext-permissions")) {
+ win.PopupNotifications.panel.removeEventListener(
+ "PanelUpdated",
+ eventListener
+ );
+ resolve();
+ }
+ }
+ );
+ });
+
+ win.gBrowser.selectedTab = BrowserTestUtils.addTab(
+ win.gBrowser,
+ "about:blank"
+ );
+ await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
+ win.gURLBar.value = TESTROOT + "amosigned.xpi";
+ win.gURLBar.focus();
+ EventUtils.synthesizeKey("KEY_Enter", {}, win);
+
+ await panelEventPromise;
+ await waitForTick();
+
+ let panel = win.PopupNotifications.panel;
+ let installDialog = panel.childNodes[0];
+
+ let notificationPromise = acceptAppMenuNotificationWhenShown(
+ "addon-installed",
+ "amosigned-xpi@tests.mozilla.org",
+ { incognitoChecked: true, global: win }
+ );
+ acceptInstallDialog(installDialog);
+ await notificationPromise;
+
+ let installs = await AddonManager.getAllInstalls();
+ is(installs.length, 0, "Should be no pending installs");
+
+ let addon = await AddonManager.getAddonByID(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+ // The panel is reloading the addon due to the permission change, we need some way
+ // to wait for the reload to finish. addon.startupPromise doesn't do it for
+ // us, so we'll just restart again.
+ await AddonTestUtils.promiseWebExtensionStartup(
+ "amosigned-xpi@tests.mozilla.org"
+ );
+
+ // This addon should no longer have private browsing permission.
+ let policy = WebExtensionPolicy.getByID(addon.id);
+ ok(!policy.privateBrowsingAllowed, "private browsing permission removed");
+
+ await addon.uninstall();
+
+ await BrowserTestUtils.closeWindow(win);
+ },
+
+ async function test_blockedInstallDomain_with_unified_extensions() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.install_origins.enabled", true]],
+ });
+
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await SimpleTest.promiseFocus(win);
+
+ let progressPromise = waitForProgressNotification(
+ false,
+ 1,
+ true,
+ "unified-extensions-button",
+ win
+ );
+ let notificationPromise = waitForNotification(
+ "addon-install-failed",
+ 1,
+ "unified-extensions-button",
+ win
+ );
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ XPI: TESTROOT2 + "webmidi_permission.xpi",
+ })
+ );
+ await BrowserTestUtils.openNewForegroundTab(
+ win.gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ await progressPromise;
+ await notificationPromise;
+
+ await BrowserTestUtils.closeWindow(win);
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_mv3_installOrigins_disallowed_with_unified_extensions() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ // Disable signature check because we load an unsigned MV3 extension.
+ ["xpinstall.signatures.required", false],
+ ["extensions.install_origins.enabled", true],
+ ],
+ });
+
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await SimpleTest.promiseFocus(win);
+
+ let notificationPromise = waitForNotification(
+ "addon-install-failed",
+ 1,
+ "unified-extensions-button",
+ win
+ );
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ // This XPI does not have any `install_origins` in its manifest.
+ XPI: "unsigned_mv3.xpi",
+ })
+ );
+ await BrowserTestUtils.openNewForegroundTab(
+ win.gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ await notificationPromise;
+
+ await BrowserTestUtils.closeWindow(win);
+ await SpecialPowers.popPrefEnv();
+ },
+
+ async function test_mv3_installOrigins_allowed_with_unified_extensions() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ // Disable signature check because we load an unsigned MV3 extension.
+ ["xpinstall.signatures.required", false],
+ // When this pref is disabled, install should be possible.
+ ["extensions.install_origins.enabled", false],
+ ],
+ });
+
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await SimpleTest.promiseFocus(win);
+
+ let notificationPromise = waitForNotification(
+ "addon-install-blocked",
+ 1,
+ "unified-extensions-button",
+ win
+ );
+ let triggers = encodeURIComponent(
+ JSON.stringify({
+ // This XPI does not have any `install_origins` in its manifest.
+ XPI: "unsigned_mv3.xpi",
+ })
+ );
+ await BrowserTestUtils.openNewForegroundTab(
+ win.gBrowser,
+ TESTROOT + "installtrigger.html?" + triggers
+ );
+ let panel = await notificationPromise;
+
+ let closePromise = waitForNotificationClose(win);
+ // hide the panel (this simulates the user dismissing it)
+ panel.hidePopup();
+ await closePromise;
+
+ await BrowserTestUtils.closeWindow(win);
+ await SpecialPowers.popPrefEnv();
+ },
+];
+
+var gTestStart = null;
+
+var XPInstallObserver = {
+ observe(aSubject, aTopic, aData) {
+ var installInfo = aSubject.wrappedJSObject;
+ info(
+ "Observed " + aTopic + " for " + installInfo.installs.length + " installs"
+ );
+ installInfo.installs.forEach(function (aInstall) {
+ info(
+ "Install of " +
+ aInstall.sourceURI.spec +
+ " was in state " +
+ aInstall.state
+ );
+ });
+ },
+};
+
+add_task(async function () {
+ requestLongerTimeout(4);
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.logging.enabled", true],
+ ["extensions.strictCompatibility", true],
+ ["extensions.install.requireSecureOrigin", false],
+ ["security.dialog_enable_delay", 0],
+ // These tests currently depends on InstallTrigger.install.
+ ["extensions.InstallTrigger.enabled", true],
+ ["extensions.InstallTriggerImpl.enabled", true],
+ // Relax the user input requirements while running this test.
+ ["xpinstall.userActivation.required", false],
+ ],
+ });
+
+ Services.obs.addObserver(XPInstallObserver, "addon-install-started");
+ Services.obs.addObserver(XPInstallObserver, "addon-install-blocked");
+ Services.obs.addObserver(XPInstallObserver, "addon-install-failed");
+
+ registerCleanupFunction(async function () {
+ // Make sure no more test parts run in case we were timed out
+ TESTS = [];
+
+ let aInstalls = await AddonManager.getAllInstalls();
+ aInstalls.forEach(function (aInstall) {
+ aInstall.cancel();
+ });
+
+ Services.obs.removeObserver(XPInstallObserver, "addon-install-started");
+ Services.obs.removeObserver(XPInstallObserver, "addon-install-blocked");
+ Services.obs.removeObserver(XPInstallObserver, "addon-install-failed");
+ });
+
+ for (let i = 0; i < TESTS.length; ++i) {
+ if (gTestStart) {
+ info("Test part took " + (Date.now() - gTestStart) + "ms");
+ }
+
+ ok(!PopupNotifications.isPanelOpen, "Notification should be closed");
+
+ let installs = await AddonManager.getAllInstalls();
+
+ is(installs.length, 0, "Should be no active installs");
+ info("Running " + TESTS[i].name);
+ gTestStart = Date.now();
+ await TESTS[i]();
+ }
+});