Bug 1206133 - Fix browser_bug553455.js such that it does not make invalid assumptions about how panels work and refactored from callbacks to Tasks and Promises. r=rhelmer
authorKirk Steuber <ksteuber@mozilla.com>
Tue, 06 Sep 2016 11:04:06 -0700
changeset 315939 b0e0213a3b2bd5f0e449a41984414e7a64a45a8a
parent 315938 06f3f82059c82c6958a27f5c478325f22fdd4a7f
child 315940 4a6f6c64ae89d18931c50286076f8a0030c75095
push id20634
push usercbook@mozilla.com
push dateFri, 30 Sep 2016 10:10:13 +0000
treeherderfx-team@afe79b010d13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhelmer
bugs1206133, 553455
milestone52.0a1
Bug 1206133 - Fix browser_bug553455.js such that it does not make invalid assumptions about how panels work and refactored from callbacks to Tasks and Promises. r=rhelmer MozReview-Commit-ID: 79bsQGDVz19
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_bug553455.js
toolkit/modules/PopupNotifications.jsm
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -127,16 +127,17 @@ support-files =
   !/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html
   !/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs
   !/toolkit/mozapps/extensions/test/xpinstall/restartless-unsigned.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/theme.xpi
+  !/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs
 
 [browser_aboutAccounts.js]
 skip-if = os == "linux" # Bug 958026
 support-files =
   content_aboutAccounts.js
 [browser_aboutCertError.js]
 [browser_aboutNetError.js]
 [browser_aboutSupport_newtab_security_state.js]
--- a/browser/base/content/test/general/browser_bug553455.js
+++ b/browser/base/content/test/general/browser_bug553455.js
@@ -5,1154 +5,1147 @@
 const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
 const TESTROOT2 = "http://example.org/browser/toolkit/mozapps/extensions/test/xpinstall/";
 const SECUREROOT = "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
 const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
 const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
 const PROGRESS_NOTIFICATION = "addon-progress";
 
 const { REQUIRE_SIGNING } = Cu.import("resource://gre/modules/addons/AddonConstants.jsm", {});
+const { Task } = Cu.import("resource://gre/modules/Task.jsm");
 
 var rootDir = getRootDirectory(gTestPath);
 var path = rootDir.split('/');
 var chromeName = path[0] + '//' + path[2];
 var croot = chromeName + "/content/browser/toolkit/mozapps/extensions/test/xpinstall/";
 var jar = getJar(croot);
 if (jar) {
   var tmpdir = extractJarToTmp(jar);
   croot = 'file://' + tmpdir.path + '/';
 }
 const CHROMEROOT = croot;
 
 var gApp = document.getElementById("bundle_brand").getString("brandShortName");
 var gVersion = Services.appinfo.version;
 
-function get_observer_topic(aNotificationId) {
+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-install-restart")
     topic = "addon-install-complete";
   return topic;
 }
 
-function wait_for_progress_notification(aCallback, aExpectedCount = 1) {
-  wait_for_notification(PROGRESS_NOTIFICATION, aCallback, aExpectedCount, "popupshowing");
+function waitForProgressNotification(aPanelOpen = false, aExpectedCount = 1) {
+  return Task.spawn(function* () {
+    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, false);
+    });
+
+    let panelEventPromise;
+    if (aPanelOpen) {
+      panelEventPromise = Promise.resolve();
+    } else {
+      panelEventPromise = new Promise(resolve => {
+        PopupNotifications.panel.addEventListener("popupshowing", function eventListener() {
+          PopupNotifications.panel.removeEventListener("popupshowing", eventListener);
+          resolve();
+        });
+      });
+    }
+
+    yield observerPromise;
+    yield panelEventPromise;
+
+    info("Saw a notification");
+    ok(PopupNotifications.isPanelOpen, "Panel should be open");
+    is(PopupNotifications.panel.childNodes.length, aExpectedCount, "Should be the right number of notifications");
+    if (PopupNotifications.panel.childNodes.length) {
+      let nodes = Array.from(PopupNotifications.panel.childNodes);
+      let notification = nodes.find(n => n.id == notificationId + "-notification");
+      ok(notification, `Should have seen the right notification`);
+    }
+
+    return PopupNotifications.panel;
+  });
 }
 
-function wait_for_notification(aId, aCallback, aExpectedCount = 1, aEvent = "popupshown") {
-  info("Waiting for " + aId + " notification");
+function waitForNotification(aId, aExpectedCount = 1) {
+  return Task.spawn(function* () {
+    info("Waiting for " + aId + " notification");
 
-  let topic = get_observer_topic(aId);
-  function observer(aSubject, aTopic, aData) {
-    // Ignore the progress notification unless that is the notification we want
-    if (aId != PROGRESS_NOTIFICATION &&
-        aTopic == get_observer_topic(PROGRESS_NOTIFICATION))
-      return;
-
-    Services.obs.removeObserver(observer, topic);
+    let topic = getObserverTopic(aId);
 
-    if (PopupNotifications.isPanelOpen)
-      executeSoon(verify);
-    else
-      PopupNotifications.panel.addEventListener(aEvent, event_listener);
-  }
+    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 (aId != PROGRESS_NOTIFICATION &&
+            aTopic == getObserverTopic(PROGRESS_NOTIFICATION)) {
+          return;
+        }
+        Services.obs.removeObserver(observer, topic);
+        resolve();
+      }, topic, false);
+    });
 
-  function event_listener() {
-    // Ignore the progress notification unless that is the notification we want
-    if (aId != PROGRESS_NOTIFICATION &&
-        PopupNotifications.panel.childNodes[0].id == PROGRESS_NOTIFICATION + "-notification")
-      return;
+    let panelEventPromise = new Promise(resolve => {
+      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.indexOf(aId) == -1) {
+          return;
+        }
+        PopupNotifications.panel.removeEventListener("PanelUpdated", eventListener);
+        resolve();
+      });
+    });
 
-    PopupNotifications.panel.removeEventListener(aEvent, event_listener);
+    yield observerPromise;
+    yield panelEventPromise;
 
-    verify();
-  }
-
-  function verify() {
     info("Saw a notification");
     ok(PopupNotifications.isPanelOpen, "Panel should be open");
     is(PopupNotifications.panel.childNodes.length, aExpectedCount, "Should be the right number of notifications");
     if (PopupNotifications.panel.childNodes.length) {
       let nodes = Array.from(PopupNotifications.panel.childNodes);
       let notification = nodes.find(n => n.id == aId + "-notification");
-      ok(notification, "Should have seen the right notification");
+      ok(notification, `Should have seen the right notification`);
     }
-    aCallback(PopupNotifications.panel);
-  }
 
-  Services.obs.addObserver(observer, topic, false);
-}
-
-function wait_for_notification_close(aCallback) {
-  info("Waiting for notification to close");
-  PopupNotifications.panel.addEventListener("popuphidden", function() {
-    PopupNotifications.panel.removeEventListener("popuphidden", arguments.callee, false);
-    executeSoon(aCallback);
-  }, false);
+    return PopupNotifications.panel;
+  });
 }
 
-function wait_for_install_dialog(aCallback) {
-  if (Preferences.get("xpinstall.customConfirmationUI", false)) {
-    wait_for_notification("addon-install-confirmation", function(aPanel) {
-      aCallback();
-    });
-    return;
-  }
-
-  info("Waiting for install dialog");
-
-  Services.wm.addListener({
-    onOpenWindow: function(aXULWindow) {
-      info("Install dialog opened, waiting for focus");
-      Services.wm.removeListener(this);
-
-      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindow);
-      waitForFocus(function() {
-        info("Saw install dialog");
-        is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
-
-        // Override the countdown timer on the accept button
-        var button = domwindow.document.documentElement.getButton("accept");
-        button.disabled = false;
-
-        aCallback();
-      }, domwindow);
-    },
-
-    onCloseWindow: function(aXULWindow) {
-    },
-
-    onWindowTitleChange: function(aXULWindow, aNewTitle) {
-    }
+function waitForNotificationClose() {
+  return new Promise(resolve => {
+    info("Waiting for notification to close");
+    PopupNotifications.panel.addEventListener("popuphidden", function listener() {
+      PopupNotifications.panel.removeEventListener("popuphidden", listener, false);
+      resolve();
+    }, false);
   });
 }
 
-function remove_tab_and_run_next_test() {
-  let eventCount = 0;
-  let nextTest = () => {
-    if (++eventCount == 2) {
-      runNextTest();
+function waitForInstallDialog() {
+  return Task.spawn(function* () {
+    if (Preferences.get("xpinstall.customConfirmationUI", false)) {
+      yield waitForNotification("addon-install-confirmation");
+      return;
     }
-  }
-  wait_for_notification_close(nextTest);
-  BrowserTestUtils.removeTab(gBrowser.selectedTab).then(nextTest);
+
+    info("Waiting for install dialog");
+
+    yield new Promise(resolve => {
+      Services.wm.addListener({
+        onOpenWindow: function(aXULWindow) {
+          Services.wm.removeListener(this);
+          resolve();
+        },
+        onCloseWindow: function(aXULWindow) {
+        },
+        onWindowTitleChange: function(aXULWindow, aNewTitle) {
+        }
+      });
+    });
+    info("Install dialog opened, waiting for focus");
+
+    let domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIDOMWindow);
+    yield new Promise(resolve => {
+      waitForFocus(function() {
+        resolve();
+      }, domwindow);
+    });
+    info("Saw install dialog");
+    is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
+
+    // Override the countdown timer on the accept button
+    let button = domwindow.document.documentElement.getButton("accept");
+    button.disabled = false;
+
+    return;
+  });
 }
 
-function accept_install_dialog() {
+function removeTab() {
+  return Promise.all([
+    waitForNotificationClose(),
+    BrowserTestUtils.removeTab(gBrowser.selectedTab)
+  ]);
+}
+
+function acceptInstallDialog() {
   if (Preferences.get("xpinstall.customConfirmationUI", false)) {
     document.getElementById("addon-install-confirmation-accept").click();
   } else {
     let win = Services.wm.getMostRecentWindow("Addons:Install");
     win.document.documentElement.acceptDialog();
   }
 }
 
-function cancel_install_dialog() {
+function cancelInstallDialog() {
   if (Preferences.get("xpinstall.customConfirmationUI", false)) {
     document.getElementById("addon-install-confirmation-cancel").click();
   } else {
     let win = Services.wm.getMostRecentWindow("Addons:Install");
     win.document.documentElement.cancelDialog();
   }
 }
 
-function wait_for_single_notification(aCallback) {
-  function inner_waiter() {
-    info("Waiting for single notification");
-    // Notification should never close while we wait
-    ok(PopupNotifications.isPanelOpen, "Notification should still be open");
-    if (PopupNotifications.panel.childNodes.length == 2) {
-      executeSoon(inner_waiter);
-      return;
+function waitForSingleNotification(aCallback) {
+  return Task.spawn(function* () {
+    while (PopupNotifications.panel.childNodes.length == 2) {
+      yield 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");
     }
-
-    aCallback();
-  }
-
-  executeSoon(inner_waiter);
+  });
 }
 
-function setup_redirect(aSettings) {
+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 = [
-function test_disabled_install() {
-  Services.prefs.setBoolPref("xpinstall.enabled", false);
+function getInstalls() {
+  return new Promise(resolve => {
+    AddonManager.getAllInstalls(installs => resolve(installs));
+  });
+}
 
-  // Wait for the disabled notification
-  wait_for_notification("xpinstall-disabled", function(aPanel) {
-    let notification = aPanel.childNodes[0];
+var TESTS = [
+function test_disabledInstall() {
+  return Task.spawn(function* () {
+    Services.prefs.setBoolPref("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 = yield 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.");
 
-    wait_for_notification_close(function() {
-      try {
-        ok(Services.prefs.getBoolPref("xpinstall.enabled"), "Installation should be enabled");
-      }
-      catch (e) {
-        ok(false, "xpinstall.enabled should be set");
-      }
-
-      BrowserTestUtils.removeTab(gBrowser.selectedTab).then(() => {
-        AddonManager.getAllInstalls(function(aInstalls) {
-          is(aInstalls.length, 0, "Shouldn't be any pending installs");
-
-          runNextTest();
-        });
-      });
-    });
-
+    let closePromise = waitForNotificationClose();
     // Click on Enable
     EventUtils.synthesizeMouseAtCenter(notification.button, {});
-  });
+    yield closePromise;
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "amosigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    try {
+      ok(Services.prefs.getBoolPref("xpinstall.enabled"), "Installation should be enabled");
+    }
+    catch (e) {
+      ok(false, "xpinstall.enabled should be set");
+    }
+
+    yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+    let installs = yield getInstalls();
+    is(installs.length, 0, "Shouldn't be any pending installs");
+  });
 },
 
-function test_blocked_install() {
-  // Wait for the blocked notification
-  wait_for_notification("addon-install-blocked", function(aPanel) {
-    let notification = aPanel.childNodes[0];
+function test_blockedInstall() {
+  return Task.spawn(function* () {
+    let notificationPromise = waitForNotification("addon-install-blocked");
+    let triggers = encodeURIComponent(JSON.stringify({
+      "XPI": "amosigned.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    let panel = yield notificationPromise;
+
+    let notification = panel.childNodes[0];
     is(notification.button.label, "Allow", "Should have seen the right button");
     is(notification.getAttribute("origin"), "example.com",
        "Should have seen the right origin host");
     is(notification.getAttribute("label"),
        gApp + " prevented this site from asking you to install software on your computer.",
        "Should have seen the right message");
 
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-restart", function(aPanel) {
-        let notification = aPanel.childNodes[0];
-        is(notification.button.label, "Restart Now", "Should have seen the right button");
-        is(notification.getAttribute("label"),
-           "XPI Test will be installed after you restart " + gApp + ".",
-           "Should have seen the right message");
-
-        AddonManager.getAllInstalls(function(aInstalls) {
-        is(aInstalls.length, 1, "Should be one pending install");
-          aInstalls[0].cancel();
-
-          remove_tab_and_run_next_test();
-        });
-      });
-
-      accept_install_dialog();
-    });
-
+    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 = aPanel.childNodes[0];
+    notification = panel.childNodes[0];
     is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
-  });
+    yield dialogPromise;
+
+    notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    panel = yield notificationPromise;
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "amosigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    notification = panel.childNodes[0];
+    is(notification.button.label, "Restart Now", "Should have seen the right button");
+    is(notification.getAttribute("label"),
+       "XPI Test will be installed after you restart " + gApp + ".",
+       "Should have seen the right message");
+
+    let installs = yield getInstalls();
+    is(installs.length, 1, "Should be one pending install");
+    installs[0].cancel();
+    yield removeTab();
+  });
 },
 
-function test_whitelisted_install() {
-  var originalTab = gBrowser.selectedTab;
-  var tab;
-
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
+function test_whitelistedInstall() {
+  return Task.spawn(function* () {
+    let originalTab = gBrowser.selectedTab;
+    let tab;
     gBrowser.selectedTab = originalTab;
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
+    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);
+    yield progressPromise;
+    yield dialogPromise;
+    yield BrowserTestUtils.waitForCondition(() => !!tab, "tab should be present");
 
-      BrowserTestUtils.waitForCondition(() => !!tab, "tab should be present").then(() => {
-        is(gBrowser.selectedTab, tab,
-           "tab selected in response to the addon-install-confirmation notification");
+    is(gBrowser.selectedTab, tab,
+       "tab selected in response to the addon-install-confirmation notification");
 
-        // Wait for the complete notification
-        wait_for_notification("addon-install-restart", function(aPanel) {
-          let notification = aPanel.childNodes[0];
-          is(notification.button.label, "Restart Now", "Should have seen the right button");
-          is(notification.getAttribute("label"),
+    let notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    let panel = yield notificationPromise;
+
+    let notification = panel.childNodes[0];
+    is(notification.button.label, "Restart Now", "Should have seen the right button");
+    is(notification.getAttribute("label"),
              "XPI Test will be installed after you restart " + gApp + ".",
              "Should have seen the right message");
 
-          AddonManager.getAllInstalls(function(aInstalls) {
-            is(aInstalls.length, 1, "Should be one pending install");
-            aInstalls[0].cancel();
-
-            Services.perms.remove(makeURI("http://example.com/"), "install");
-            remove_tab_and_run_next_test();
-          });
-        });
+    let installs = yield getInstalls();
+    is(installs.length, 1, "Should be one pending install");
+    installs[0].cancel();
 
-        accept_install_dialog();
-      });
-    });
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
   });
-
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "amosigned.xpi"
-  }));
-
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?"
-    + triggers).then(newTab => tab = newTab);
 },
 
-function test_failed_download() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the failed notification
-    wait_for_notification("addon-install-failed", function(aPanel) {
-      let notification = aPanel.childNodes[0];
-      is(notification.getAttribute("label"),
-         "The add-on could not be downloaded because of a connection failure.",
-         "Should have seen the right message");
+function test_failedDownload() {
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-      Services.perms.remove(makeURI("http://example.com/"), "install");
-      remove_tab_and_run_next_test();
-    });
-  });
+    let progressPromise = waitForProgressNotification();
+    let failPromise = waitForNotification("addon-install-failed");
+    let triggers = encodeURIComponent(JSON.stringify({
+      "XPI": "missing.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    let panel = yield failPromise;
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    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");
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "missing.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
+  });
 },
 
-function test_corrupt_file() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the failed notification
-    wait_for_notification("addon-install-failed", function(aPanel) {
-      let notification = aPanel.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");
+function test_corruptFile() {
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-      Services.perms.remove(makeURI("http://example.com/"), "install");
-      remove_tab_and_run_next_test();
-    });
-  });
+    let progressPromise = waitForProgressNotification();
+    let failPromise = waitForNotification("addon-install-failed");
+    let triggers = encodeURIComponent(JSON.stringify({
+      "XPI": "corrupt.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    let panel = yield failPromise;
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    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");
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "corrupt.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
+  });
 },
 
 function test_incompatible() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the failed notification
-    wait_for_notification("addon-install-failed", function(aPanel) {
-      let notification = aPanel.childNodes[0];
-      is(notification.getAttribute("label"),
-         "XPI Test could not be installed because it is not compatible with " +
-         gApp + " " + gVersion + ".",
-         "Should have seen the right message");
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-      Services.perms.remove(makeURI("http://example.com/"), "install");
-      remove_tab_and_run_next_test();
-    });
-  });
+    let progressPromise = waitForProgressNotification();
+    let failPromise = waitForNotification("addon-install-failed");
+    let triggers = encodeURIComponent(JSON.stringify({
+      "XPI": "incompatible.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    let panel = yield failPromise;
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    let notification = panel.childNodes[0];
+    is(notification.getAttribute("label"),
+       "XPI Test could not be installed because it is not compatible with " +
+       gApp + " " + gVersion + ".",
+       "Should have seen the right message");
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "incompatible.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
+  });
 },
 
 function test_restartless() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-complete", function(aPanel) {
-        let notification = aPanel.childNodes[0];
-        is(notification.getAttribute("label"),
-           "XPI Test has been installed successfully.",
-           "Should have seen the right message");
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-        AddonManager.getAllInstalls(function(aInstalls) {
-          is(aInstalls.length, 0, "Should be no pending installs");
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "XPI": "restartless.xpi"
+    }));
+    gBrowser.selectedTab = gBrowser.addTab();
+    gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
 
-          AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
-            aAddon.uninstall();
+    let notificationPromise = waitForNotification("addon-install-complete");
+    acceptInstallDialog();
+    let panel = yield notificationPromise;
 
-            Services.perms.remove(makeURI("http://example.com/"), "install");
-            wait_for_notification_close(runNextTest);
-            gBrowser.removeTab(gBrowser.selectedTab);
-          });
-        });
+    let notification = panel.childNodes[0];
+    is(notification.getAttribute("label"),
+       "XPI Test has been installed successfully.",
+       "Should have seen the right message");
+
+    let installs = yield getInstalls();
+    is(installs.length, 0, "Should be no pending installs");
+
+    let addon = yield new Promise(resolve => {
+      AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", addon => {
+        resolve(addon);
       });
+    });
+    addon.uninstall();
 
-      accept_install_dialog();
-    });
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+
+    let closePromise = waitForNotificationClose();
+    gBrowser.removeTab(gBrowser.selectedTab);
+    yield closePromise;
   });
-
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "restartless.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 },
 
 function test_multiple() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-restart", function(aPanel) {
-        let notification = aPanel.childNodes[0];
-        is(notification.button.label, "Restart Now", "Should have seen the right button");
-        is(notification.getAttribute("label"),
-           "2 add-ons will be installed after you restart " + gApp + ".",
-           "Should have seen the right message");
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-        AddonManager.getAllInstalls(function(aInstalls) {
-          is(aInstalls.length, 1, "Should be one pending install");
-          aInstalls[0].cancel();
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "Unsigned XPI": "amosigned.xpi",
+      "Restartless XPI": "restartless.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    let panel = yield progressPromise;
+    yield dialogPromise;
 
-          AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
-            aAddon.uninstall();
+    let notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    yield notificationPromise;
 
-            Services.perms.remove(makeURI("http://example.com/"), "install");
-            remove_tab_and_run_next_test();
-          });
-        });
+    let notification = panel.childNodes[0];
+    is(notification.button.label, "Restart Now", "Should have seen the right button");
+    is(notification.getAttribute("label"),
+       "2 add-ons will be installed after you restart " + gApp + ".",
+       "Should have seen the right message");
+
+    let installs = yield getInstalls();
+    is(installs.length, 1, "Should be one pending install");
+    installs[0].cancel();
+
+    let addon = yield new Promise(resolve => {
+      AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function (addon) {
+        resolve(addon);
       });
-
-      accept_install_dialog();
     });
+    addon.uninstall();
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
   });
-
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Unsigned XPI": "amosigned.xpi",
-    "Restartless XPI": "restartless.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
 },
 
 function test_sequential() {
-  // This test is only relevant if using the new doorhanger UI
-  if (!Preferences.get("xpinstall.customConfirmationUI", false)) {
-    runNextTest();
-    return;
-  }
-
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the progress notification
-
-      // Should see the right add-on
-      let container = document.getElementById("addon-install-confirmation-content");
-      is(container.childNodes.length, 1, "Should be one item listed");
-      is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
+  return Task.spawn(function* () {
+    // This test is only relevant if using the new doorhanger UI
+    if (!Preferences.get("xpinstall.customConfirmationUI", false)) {
+      return;
+    }
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-      wait_for_progress_notification(function(aPanel) {
-        // Should still have the right add-on in the confirmation notification
-        is(container.childNodes.length, 1, "Should be one item listed");
-        is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "Restartless XPI": "restartless.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
 
-        // Wait for the install to complete, we won't see a new confirmation
-        // notification
-        Services.obs.addObserver(function observer() {
-          Services.obs.removeObserver(observer, "addon-install-confirmation");
+    // Should see the right add-on
+    let container = document.getElementById("addon-install-confirmation-content");
+    is(container.childNodes.length, 1, "Should be one item listed");
+    is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
 
-          // Make sure browser-addons.js executes first
-          executeSoon(function () {
-            // Should have dropped the progress notification
-            is(PopupNotifications.panel.childNodes.length, 1, "Should be the right number of notifications");
-            is(PopupNotifications.panel.childNodes[0].id, "addon-install-confirmation-notification",
-               "Should only be showing one install confirmation");
+    progressPromise = waitForProgressNotification(true, 2);
+    triggers = encodeURIComponent(JSON.stringify({
+      "Theme XPI": "theme.xpi"
+    }));
+    gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+
+    // Should still have the right add-on in the confirmation notification
+    is(container.childNodes.length, 1, "Should be one item listed");
+    is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
 
-            // Should still have the right add-on in the confirmation notification
-            is(container.childNodes.length, 1, "Should be one item listed");
-            is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
-
-            cancel_install_dialog();
+    // Wait for the install to complete, we won't see a new confirmation
+    // notification
+    yield new Promise(resolve => {
+      Services.obs.addObserver(function observer() {
+        Services.obs.removeObserver(observer, "addon-install-confirmation");
+        resolve();
+      }, "addon-install-confirmation", false);
+    });
 
-            ok(PopupNotifications.isPanelOpen, "Panel should still be open");
-            is(PopupNotifications.panel.childNodes.length, 1, "Should be the right number of notifications");
-            is(PopupNotifications.panel.childNodes[0].id, "addon-install-confirmation-notification",
-               "Should still have an install confirmation open");
+    // Make sure browser-addons.js executes first
+    yield new Promise(resolve => executeSoon(resolve));
 
-            // Should have the next add-on's confirmation dialog
-            is(container.childNodes.length, 1, "Should be one item listed");
-            is(container.childNodes[0].firstChild.getAttribute("value"), "Theme Test", "Should have the right add-on");
-
-            Services.perms.remove(makeURI("http://example.com"), "install");
-            wait_for_notification_close(() => {
-              BrowserTestUtils.removeTab(gBrowser.selectedTab).then(runNextTest);
-            });
+    // Should have dropped the progress notification
+    is(PopupNotifications.panel.childNodes.length, 1, "Should be the right number of notifications");
+    is(PopupNotifications.panel.childNodes[0].id, "addon-install-confirmation-notification",
+       "Should only be showing one install confirmation");
 
-            cancel_install_dialog();
-          });
-        }, "addon-install-confirmation", false);
-      }, 2);
+    // Should still have the right add-on in the confirmation notification
+    is(container.childNodes.length, 1, "Should be one item listed");
+    is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
+
+    cancelInstallDialog();
+
+    ok(PopupNotifications.isPanelOpen, "Panel should still be open");
+    is(PopupNotifications.panel.childNodes.length, 1, "Should be the right number of notifications");
+    is(PopupNotifications.panel.childNodes[0].id, "addon-install-confirmation-notification",
+       "Should still have an install confirmation open");
 
-      var triggers = encodeURIComponent(JSON.stringify({
-        "Theme XPI": "theme.xpi"
-      }));
-      gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-    });
-  });
+    // Should have the next add-on's confirmation dialog
+    is(container.childNodes.length, 1, "Should be one item listed");
+    is(container.childNodes[0].firstChild.getAttribute("value"), "Theme Test", "Should have the right add-on");
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Restartless XPI": "restartless.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com"), "install");
+    let closePromise = waitForNotificationClose();
+    cancelInstallDialog();
+    yield closePromise;
+    yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  });
 },
 
-function test_someunverified() {
-  // This test is only relevant if using the new doorhanger UI and allowing
-  // unsigned add-ons
-  if (!Preferences.get("xpinstall.customConfirmationUI", false) ||
-      Preferences.get("xpinstall.signatures.required", true) ||
-      REQUIRE_SIGNING) {
-    runNextTest();
-    return;
-  }
+function test_someUnverified() {
+  return Task.spawn(function* () {
+    // This test is only relevant if using the new doorhanger UI and allowing
+    // unsigned add-ons
+    if (!Preferences.get("xpinstall.customConfirmationUI", false) ||
+        Preferences.get("xpinstall.signatures.required", true) ||
+        REQUIRE_SIGNING) {
+      return;
+    }
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      let notification = document.getElementById("addon-install-confirmation-notification");
-      let message = notification.getAttribute("label");
-      is(message, "Caution: This site would like to install 2 add-ons in " + gApp +
-         ", some of which are unverified. Proceed at your own risk.",
-         "Should see the right message");
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "Extension XPI": "restartless-unsigned.xpi",
+      "Theme XPI": "theme.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
 
-      let container = document.getElementById("addon-install-confirmation-content");
-      is(container.childNodes.length, 2, "Should be two items listed");
-      is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
-      is(container.childNodes[0].lastChild.getAttribute("class"),
-         "addon-install-confirmation-unsigned", "Should have the unverified marker");
-      is(container.childNodes[1].firstChild.getAttribute("value"), "Theme Test", "Should have the right add-on");
-      is(container.childNodes[1].childNodes.length, 1, "Shouldn't have the unverified marker");
+    let notification = document.getElementById("addon-install-confirmation-notification");
+    let message = notification.getAttribute("label");
+    is(message, "Caution: This site would like to install 2 add-ons in " + gApp +
+       ", some of which are unverified. Proceed at your own risk.",
+       "Should see the right message");
 
-      // Wait for the complete notification
-      wait_for_notification("addon-install-restart", function(aPanel) {
-        AddonManager.getAddonsByIDs(["restartless-xpi@tests.mozilla.org",
-                                     "theme-xpi@tests.mozilla.org"], function([a, t]) {
-          a.uninstall();
-          // Installing a new theme tries to switch to it, switch back to the
-          // default theme.
-          t.userDisabled = true;
-          t.uninstall();
+    let container = document.getElementById("addon-install-confirmation-content");
+    is(container.childNodes.length, 2, "Should be two items listed");
+    is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
+    is(container.childNodes[0].lastChild.getAttribute("class"),
+       "addon-install-confirmation-unsigned", "Should have the unverified marker");
+    is(container.childNodes[1].firstChild.getAttribute("value"), "Theme Test", "Should have the right add-on");
+    is(container.childNodes[1].childNodes.length, 1, "Shouldn't have the unverified marker");
 
-          Services.perms.remove(makeURI("http://example.com/"), "install");
-          remove_tab_and_run_next_test();
-        });
+    let notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    yield notificationPromise;
+
+    let [addon, theme] = yield new Promise(resolve => {
+      AddonManager.getAddonsByIDs(["restartless-xpi@tests.mozilla.org",
+                                  "theme-xpi@tests.mozilla.org"],
+                                  function(addons) {
+        resolve(addons);
       });
-
-      accept_install_dialog();
     });
-  });
+    addon.uninstall();
+    // Installing a new theme tries to switch to it, switch back to the
+    // default theme.
+    theme.userDisabled = true;
+    theme.uninstall();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Extension XPI": "restartless-unsigned.xpi",
-    "Theme XPI": "theme.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
+  });
 },
 
-function test_allunverified() {
-  // This test is only relevant if using the new doorhanger UI and allowing
-  // unsigned add-ons
-  if (!Preferences.get("xpinstall.customConfirmationUI", false) ||
-      Preferences.get("xpinstall.signatures.required", true) ||
-      REQUIRE_SIGNING) {
-    runNextTest();
-    return;
-  }
+function test_allUnverified() {
+  return Task.spawn(function* () {
+    // This test is only relevant if using the new doorhanger UI and allowing
+    // unsigned add-ons
+    if (!Preferences.get("xpinstall.customConfirmationUI", false) ||
+        Preferences.get("xpinstall.signatures.required", true) ||
+        REQUIRE_SIGNING) {
+      return;
+    }
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      let notification = document.getElementById("addon-install-confirmation-notification");
-      let message = notification.getAttribute("label");
-      is(message, "Caution: This site would like to install an unverified add-on in " + gApp + ". Proceed at your own risk.");
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "Extension XPI": "restartless-unsigned.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
 
-      let container = document.getElementById("addon-install-confirmation-content");
-      is(container.childNodes.length, 1, "Should be one item listed");
-      is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
-      is(container.childNodes[0].childNodes.length, 1, "Shouldn't have the unverified marker");
+    let notification = document.getElementById("addon-install-confirmation-notification");
+    let message = notification.getAttribute("label");
+    is(message, "Caution: This site would like to install an unverified add-on in " + gApp + ". Proceed at your own risk.");
 
-      // Wait for the complete notification
-      wait_for_notification("addon-install-complete", function(aPanel) {
-        AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
-          aAddon.uninstall();
+    let container = document.getElementById("addon-install-confirmation-content");
+    is(container.childNodes.length, 1, "Should be one item listed");
+    is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
+    is(container.childNodes[0].childNodes.length, 1, "Shouldn't have the unverified marker");
 
-          Services.perms.remove(makeURI("http://example.com/"), "install");
-          remove_tab_and_run_next_test();
-        });
+    let notificationPromise = waitForNotification("addon-install-complete");
+    acceptInstallDialog();
+    yield notificationPromise;
+
+    let addon = yield new Promise(resolve => {
+      AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(addon) {
+        resolve(addon);
       });
+    });
+    addon.uninstall();
 
-      accept_install_dialog();
-    });
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
   });
-
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Extension XPI": "restartless-unsigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
 },
 
 function test_url() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-restart", function(aPanel) {
-        let notification = aPanel.childNodes[0];
-        is(notification.button.label, "Restart Now", "Should have seen the right button");
-        is(notification.getAttribute("label"),
-           "XPI Test will be installed after you restart " + gApp + ".",
-           "Should have seen the right message");
+  return Task.spawn(function* () {
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    gBrowser.selectedTab = gBrowser.addTab("about:blank");
+    yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+    gBrowser.loadURI(TESTROOT + "amosigned.xpi");
+    yield progressPromise;
+    yield dialogPromise;
 
-        AddonManager.getAllInstalls(function(aInstalls) {
-          is(aInstalls.length, 1, "Should be one pending install");
-          aInstalls[0].cancel();
-
-          remove_tab_and_run_next_test();
-        });
-      });
+    let notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    let panel = yield notificationPromise;
 
-      accept_install_dialog();
-    });
-  });
+    let notification = panel.childNodes[0];
+    is(notification.button.label, "Restart Now", "Should have seen the right button");
+    is(notification.getAttribute("label"),
+       "XPI Test will be installed after you restart " + gApp + ".",
+       "Should have seen the right message");
 
-  gBrowser.selectedTab = gBrowser.addTab("about:blank");
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
-    gBrowser.loadURI(TESTROOT + "amosigned.xpi");
+    let installs = yield getInstalls();
+    is(installs.length, 1, "Should be one pending install");
+    installs[0].cancel();
+
+    yield removeTab();
   });
 },
 
-function test_localfile() {
-  // Wait for the install to fail
-  Services.obs.addObserver(function() {
-    Services.obs.removeObserver(arguments.callee, "addon-install-failed");
+function test_localFile() {
+  return Task.spawn(function* () {
+    let cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
+                       .getService(Components.interfaces.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", false);
+    });
+    gBrowser.selectedTab = gBrowser.addTab("about:blank");
+    yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+    gBrowser.loadURI(path);
+    yield failPromise;
 
     // Wait for the browser code to add the failure notification
-    wait_for_single_notification(function() {
-      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");
-
-      remove_tab_and_run_next_test();
-    });
-  }, "addon-install-failed", false);
+    yield waitForSingleNotification();
 
-  var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
-                     .getService(Components.interfaces.nsIChromeRegistry);
-  try {
-    var path = cr.convertChromeURL(makeURI(CHROMEROOT + "corrupt.xpi")).spec;
-  } catch (ex) {
+    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");
+
+    yield removeTab();
+  });
     path = CHROMEROOT + "corrupt.xpi";
-  }
-  gBrowser.selectedTab = gBrowser.addTab("about:blank");
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
-    gBrowser.loadURI(path);
-  });
 },
 
-function test_tabclose() {
-  if (!Preferences.get("xpinstall.customConfirmationUI", false)) {
-    runNextTest();
-    return;
-  }
-
-  // Wait for the progress notification
-  wait_for_progress_notification(aPanel => {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(() => {
-      AddonManager.getAllInstalls(aInstalls => {
-        is(aInstalls.length, 1, "Should be one pending install");
+function test_tabClose() {
+  return Task.spawn(function* () {
+    if (!Preferences.get("xpinstall.customConfirmationUI", false)) {
+      runNextTest();
+      return;
+    }
 
-        let eventCount = 0;
-        let nextTest = () => {
-          if (++eventCount == 2) {
-            runNextTest();
-          }
-        }
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    gBrowser.selectedTab = gBrowser.addTab("about:blank");
+    yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+    gBrowser.loadURI(TESTROOT + "amosigned.xpi");
+    yield progressPromise;
+    yield dialogPromise;
 
-        wait_for_notification_close(() => {
-          AddonManager.getAllInstalls(aInstalls => {
-            is(aInstalls.length, 0, "Should be no pending install since the tab is closed");
-            nextTest();
-          });
-        });
+    let installs = yield getInstalls();
+    is(installs.length, 1, "Should be one pending install");
 
-        BrowserTestUtils.removeTab(gBrowser.selectedTab).then(nextTest);
-      });
-    });
-  });
+    let closePromise = waitForNotificationClose();
+    yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+    yield closePromise;
 
-  gBrowser.selectedTab = gBrowser.addTab("about:blank");
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
-    gBrowser.loadURI(TESTROOT + "amosigned.xpi");
+    installs = yield getInstalls();
+    is(installs.length, 0, "Should be no pending install since the tab is closed");
   });
 },
 
 // Add-ons should be cancelled and the install notification destroyed when
 // navigating to a new origin
-function test_tabnavigate() {
-  if (!Preferences.get("xpinstall.customConfirmationUI", false)) {
-    runNextTest();
-    return;
-  }
-
-  // Wait for the progress notification
-  wait_for_progress_notification(aPanel => {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(() => {
-      wait_for_notification_close(() => {
-        AddonManager.getAllInstalls(aInstalls => {
-          is(aInstalls.length, 0, "Should be no pending install");
+function test_tabNavigate() {
+  return Task.spawn(function* () {
+    if (!Preferences.get("xpinstall.customConfirmationUI", false)) {
+      return;
+    }
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-          Services.perms.remove(makeURI("http://example.com/"), "install");
-          loadPromise.then(() => {
-            BrowserTestUtils.removeTab(gBrowser.selectedTab).then(runNextTest);
-          });
-        });
-      });
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "Extension XPI": "amosigned.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
 
-      let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-      gBrowser.loadURI("about:blank");
-    });
-  });
+    let closePromise = waitForNotificationClose();
+    let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+    gBrowser.loadURI("about:blank");
+    yield closePromise;
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    let installs = yield getInstalls();
+    is(installs.length, 0, "Should be no pending install");
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Extension XPI": "amosigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield loadPromise;
+    yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  });
 },
 
-function test_urlbar() {
-  wait_for_notification("addon-install-origin-blocked", function(aPanel) {
-    let notification = aPanel.childNodes[0];
-
-    is(notification.button.label, "", "Button to allow install should be hidden.");
-
-    remove_tab_and_run_next_test();
-  });
-
-  gBrowser.selectedTab = gBrowser.addTab("about:blank");
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
+function test_urlBar() {
+  return Task.spawn(function* () {
+    let notificationPromise = waitForNotification("addon-install-origin-blocked");
+    gBrowser.selectedTab = gBrowser.addTab("about:blank");
+    yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
     gURLBar.value = TESTROOT + "amosigned.xpi";
     gURLBar.focus();
     EventUtils.synthesizeKey("VK_RETURN", {});
+    let panel = yield notificationPromise;
+
+    let notification = panel.childNodes[0];
+    is(notification.button.label, "", "Button to allow install should be hidden.");
+    yield removeTab();
   });
 },
 
-function test_wronghost() {
-  gBrowser.selectedTab = gBrowser.addTab();
+function test_wrongHost() {
+  return Task.spawn(function* () {
+    let requestedUrl = TESTROOT2 + "enabled.html";
+    gBrowser.selectedTab = gBrowser.addTab();
+
+    let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, requestedUrl);
+    gBrowser.loadURI(TESTROOT2 + "enabled.html");
+    yield loadedPromise;
 
-  let requestedUrl = TESTROOT2 + "enabled.html";
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, requestedUrl).then(() => {
-    // Wait for the progress notification
-    wait_for_progress_notification(function(aPanel) {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-failed", function(aPanel) {
-        let notification = aPanel.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");
+    let progressPromise = waitForProgressNotification();
+    let notificationPromise = waitForNotification("addon-install-failed");
+    gBrowser.loadURI(TESTROOT + "corrupt.xpi");
+    yield progressPromise;
+    let panel = yield notificationPromise;
 
-        remove_tab_and_run_next_test();
-      });
-    });
+    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");
 
-    gBrowser.loadURI(TESTROOT + "corrupt.xpi");
+    yield removeTab();
   });
-  gBrowser.loadURI(TESTROOT2 + "enabled.html");
 },
 
 function test_reload() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-restart", function(aPanel) {
-        let notification = aPanel.childNodes[0];
-        is(notification.button.label, "Restart Now", "Should have seen the right button");
-        is(notification.getAttribute("label"),
-           "XPI Test will be installed after you restart " + gApp + ".",
-           "Should have seen the right message");
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-        function test_fail() {
-          ok(false, "Reloading should not have hidden the notification");
-        }
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "Unsigned XPI": "amosigned.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
 
-        PopupNotifications.panel.addEventListener("popuphiding", test_fail, false);
-
-        let requestedUrl = TESTROOT2 + "enabled.html";
-        BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, requestedUrl).then(() => {
-          PopupNotifications.panel.removeEventListener("popuphiding", test_fail, false);
+    let notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    let panel = yield notificationPromise;
 
-          AddonManager.getAllInstalls(function(aInstalls) {
-            is(aInstalls.length, 1, "Should be one pending install");
-            aInstalls[0].cancel();
-
-            Services.perms.remove(makeURI("http://example.com/"), "install");
-            remove_tab_and_run_next_test();
-          });
-        });
-        gBrowser.loadURI(TESTROOT2 + "enabled.html");
-      });
+    let notification = panel.childNodes[0];
+    is(notification.button.label, "Restart Now", "Should have seen the right button");
+    is(notification.getAttribute("label"),
+       "XPI Test will be installed after you restart " + gApp + ".",
+       "Should have seen the right message");
 
-      accept_install_dialog();
-    });
-  });
+    function testFail() {
+      ok(false, "Reloading should not have hidden the notification");
+    }
+    PopupNotifications.panel.addEventListener("popuphiding", testFail, false);
+    let requestedUrl = TESTROOT2 + "enabled.html";
+    let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, requestedUrl);
+    gBrowser.loadURI(TESTROOT2 + "enabled.html");
+    yield loadedPromise;
+    PopupNotifications.panel.removeEventListener("popuphiding", testFail, false);
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    let installs = yield getInstalls();
+    is(installs.length, 1, "Should be one pending install");
+    installs[0].cancel();
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Unsigned XPI": "amosigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
+  });
 },
 
 function test_theme() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-restart", function(aPanel) {
-        let notification = aPanel.childNodes[0];
-        is(notification.button.label, "Restart Now", "Should have seen the right button");
-        is(notification.getAttribute("label"),
-           "Theme Test will be installed after you restart " + gApp + ".",
-           "Should have seen the right message");
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-        AddonManager.getAddonByID("{972ce4c6-7e08-4474-a285-3208198ce6fd}", function(aAddon) {
-          ok(aAddon.userDisabled, "Should be switching away from the default theme.");
-          // Undo the pending theme switch
-          aAddon.userDisabled = false;
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "Theme XPI": "theme.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
+
+    let notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    let panel = yield notificationPromise;
 
-          AddonManager.getAddonByID("theme-xpi@tests.mozilla.org", function(aAddon) {
-            isnot(aAddon, null, "Test theme will have been installed");
-            aAddon.uninstall();
-
-            Services.perms.remove(makeURI("http://example.com/"), "install");
-            remove_tab_and_run_next_test();
-          });
-        });
-      });
+    let notification = panel.childNodes[0];
+    is(notification.button.label, "Restart Now", "Should have seen the right button");
+    is(notification.getAttribute("label"),
+       "Theme Test will be installed after you restart " + gApp + ".",
+       "Should have seen the right message");
 
-      accept_install_dialog();
+    let addon = yield new Promise(resolve => {
+      AddonManager.getAddonByID("{972ce4c6-7e08-4474-a285-3208198ce6fd}", function(addon) {
+        resolve(addon);
+      });
     });
-  });
+    ok(addon.userDisabled, "Should be switching away from the default theme.");
+    // Undo the pending theme switch
+    addon.userDisabled = false;
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    addon = yield new Promise(resolve => {
+      AddonManager.getAddonByID("theme-xpi@tests.mozilla.org", function(addon) {
+        resolve(addon);
+      });
+    });
+    isnot(addon, null, "Test theme will have been installed");
+    addon.uninstall();
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Theme XPI": "theme.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
+  });
 },
 
-function test_renotify_blocked() {
-  // Wait for the blocked notification
-  wait_for_notification("addon-install-blocked", function(aPanel) {
-    let notification = aPanel.childNodes[0];
+function test_renotifyBlocked() {
+  return Task.spawn(function* () {
+    let notificationPromise = waitForNotification("addon-install-blocked");
+    let triggers = encodeURIComponent(JSON.stringify({
+      "XPI": "amosigned.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    let panel = yield notificationPromise;
 
-    wait_for_notification_close(function () {
-      info("Timeouts after this probably mean bug 589954 regressed");
-      executeSoon(function () {
-        wait_for_notification("addon-install-blocked", function(aPanel) {
-          AddonManager.getAllInstalls(function(aInstalls) {
-            is(aInstalls.length, 2, "Should be two pending installs");
+    let closePromise = waitForNotificationClose();
+    // hide the panel (this simulates the user dismissing it)
+    panel.hidePopup();
+    yield closePromise;
 
-            let eventCount = 0;
-            let nextTest = () => {
-              if (++eventCount == 2) {
-                runNextTest();
-              }
-            }
+    info("Timeouts after this probably mean bug 589954 regressed");
 
-            wait_for_notification_close(() => {
-              AddonManager.getAllInstalls(function(aInstalls) {
-                is(aInstalls.length, 0, "Should have cancelled the installs");
-                nextTest();
-              });
-            });
+    yield new Promise(resolve => executeSoon(resolve));
 
-            info("Closing browser tab");
-            BrowserTestUtils.removeTab(gBrowser.selectedTab).then(nextTest);
-          });
-        });
+    notificationPromise = waitForNotification("addon-install-blocked");
+    gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+    yield notificationPromise;
 
-        gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-      });
-    });
+    let installs = yield getInstalls();
+    is(installs.length, 2, "Should be two pending installs");
 
-    // hide the panel (this simulates the user dismissing it)
-    aPanel.hidePopup();
-  });
+    closePromise = waitForNotificationClose();
+    yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+    yield closePromise;
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "amosigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    installs = yield getInstalls();
+    is(installs.length, 0, "Should have cancelled the installs");
+  });
 },
 
-function test_renotify_installed() {
-  // Wait for the progress notification
-  wait_for_progress_notification(function(aPanel) {
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function() {
-      // Wait for the complete notification
-      wait_for_notification("addon-install-restart", function(aPanel) {
-        // Dismiss the notification
-        wait_for_notification_close(function () {
-          // Install another
-          executeSoon(function () {
-            // Wait for the progress notification
-            wait_for_progress_notification(function(aPanel) {
-              // Wait for the install confirmation dialog
-              wait_for_install_dialog(function() {
-                info("Timeouts after this probably mean bug 589954 regressed");
+function test_renotifyInstalled() {
+  return Task.spawn(function* () {
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
-                // Wait for the complete notification
-                wait_for_notification("addon-install-restart", function(aPanel) {
-                  AddonManager.getAllInstalls(function(aInstalls) {
-                  is(aInstalls.length, 1, "Should be one pending installs");
-                    aInstalls[0].cancel();
+    let progressPromise = waitForProgressNotification();
+    let dialogPromise = waitForInstallDialog();
+    let triggers = encodeURIComponent(JSON.stringify({
+      "XPI": "amosigned.xpi"
+    }));
+    BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
+
+    // Wait for the complete notification
+    let notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    let panel = yield notificationPromise;
+
+    let closePromise = waitForNotificationClose();
+    // hide the panel (this simulates the user dismissing it)
+    panel.hidePopup();
+    yield closePromise;
 
-                    Services.perms.remove(makeURI("http://example.com/"), "install");
-                    remove_tab_and_run_next_test();
-                  });
-                });
+    // Install another
+    yield new Promise(resolve => executeSoon(resolve));
 
-                accept_install_dialog();
-              });
-            });
+    progressPromise = waitForProgressNotification();
+    dialogPromise = waitForInstallDialog();
+    gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+    yield progressPromise;
+    yield dialogPromise;
 
-            gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-          });
-        });
+    info("Timeouts after this probably mean bug 589954 regressed");
 
-        // hide the panel (this simulates the user dismissing it)
-        aPanel.hidePopup();
-      });
-
-      accept_install_dialog();
-    });
-  });
+    // Wait for the complete notification
+    notificationPromise = waitForNotification("addon-install-restart");
+    acceptInstallDialog();
+    yield notificationPromise;
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    let installs = yield getInstalls();
+    is(installs.length, 1, "Should be one pending installs");
+    installs[0].cancel();
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "amosigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield removeTab();
+  });
 },
 
 function test_cancel() {
-  function complete_install(callback) {
-    let url = TESTROOT + "slowinstall.sjs?continue=true"
-    NetUtil.asyncFetch({
-      uri: url,
-      loadUsingSystemPrincipal: true
-    }, callback || (() => {}));
-  }
+  return Task.spawn(function* () {
+    function complete_install(callback) {
+      let url = TESTROOT + "slowinstall.sjs?continue=true"
+      NetUtil.asyncFetch({
+        uri: url,
+        loadUsingSystemPrincipal: true
+      }, callback || (() => {}));
+    }
 
-  // Wait for the progress notification
-  wait_for_notification(PROGRESS_NOTIFICATION, function(aPanel) {
-    let notification = aPanel.childNodes[0];
+    let pm = Services.perms;
+    pm.add(makeURI("http://example.com/"), "install", pm.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 = yield notificationPromise;
+
+    let notification = panel.childNodes[0];
     // Close the notification
     let anchor = document.getElementById("addons-notification-icon");
     anchor.click();
     // Reopen the notification
     anchor.click();
 
     ok(PopupNotifications.isPanelOpen, "Notification should still be open");
     is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
-    notification = aPanel.childNodes[0];
+    notification = panel.childNodes[0];
     is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
     let button = document.getElementById("addon-progress-cancel");
 
-    // Wait for the install to fully cancel
+    // Cancel the download
     let install = notification.notification.options.installs[0];
-    install.addListener({
-      onDownloadCancelled: function() {
-        install.removeListener(this);
+    let cancelledPromise = new Promise(resolve => {
+      install.addListener({
+        onDownloadCancelled: function() {
+          install.removeListener(this);
+          resolve();
+        }
+      });
+    });
+    EventUtils.synthesizeMouseAtCenter(button, {});
+    yield cancelledPromise;
 
-        executeSoon(function() {
-          ok(!PopupNotifications.isPanelOpen, "Notification should be closed");
+    yield new Promise(resolve => executeSoon(resolve));
 
-          AddonManager.getAllInstalls(function(aInstalls) {
-            is(aInstalls.length, 0, "Should be no pending install");
+    ok(!PopupNotifications.isPanelOpen, "Notification should be closed");
+
+    let installs = yield getInstalls();
+    is(installs.length, 0, "Should be no pending install");
 
-            Services.perms.remove(makeURI("http://example.com/"), "install");
-            BrowserTestUtils.removeTab(gBrowser.selectedTab).then(runNextTest);
-          });
-        });
-      }
+    Services.perms.remove(makeURI("http://example.com/"), "install");
+    yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  });
+},
+
+function test_failedSecurity() {
+  return Task.spawn(function* () {
+    Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+    setupRedirect({
+      "Location": TESTROOT + "amosigned.xpi"
     });
 
-    // Cancel the download
-    EventUtils.synthesizeMouseAtCenter(button, {});
-  });
-
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    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 = yield notificationPromise;
 
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "slowinstall.sjs?file=amosigned.xpi"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
-},
-
-function test_failed_security() {
-  Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
-
-  setup_redirect({
-    "Location": TESTROOT + "amosigned.xpi"
-  });
-
-  // Wait for the blocked notification
-  wait_for_notification("addon-install-blocked", function(aPanel) {
-    let notification = aPanel.childNodes[0];
-
+    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 = aPanel.childNodes[0];
+    notification = panel.childNodes[0];
     is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
 
     // Wait for it to fail
-    Services.obs.addObserver(function() {
-      Services.obs.removeObserver(arguments.callee, "addon-install-failed");
-
-      // Allow the browser code to add the failure notification and then wait
-      // for the progress notification to dismiss itself
-      wait_for_single_notification(function() {
-        is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
-        notification = aPanel.childNodes[0];
-        is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
+    yield new Promise(resolve => {
+      Services.obs.addObserver(function observer() {
+        Services.obs.removeObserver(observer, "addon-install-failed");
+        resolve();
+      }, "addon-install-failed", false);
+    });
 
-        Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, true);
-        remove_tab_and_run_next_test();
-      });
-    }, "addon-install-failed", false);
+    // Allow the browser code to add the failure notification and then wait
+    // for the progress notification to dismiss itself
+    yield 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");
+
+    Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, true);
+    yield removeTab();
   });
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "redirect.sjs?mode=redirect"
-  }));
-  BrowserTestUtils.openNewForegroundTab(gBrowser, SECUREROOT + "installtrigger.html?" + triggers);
 }
 ];
 
 var gTestStart = null;
 
-function runNextTest() {
-  if (gTestStart)
-    info("Test part took " + (Date.now() - gTestStart) + "ms");
-
-  ok(!PopupNotifications.isPanelOpen, "Notification should be closed");
-
-  AddonManager.getAllInstalls(function(aInstalls) {
-    is(aInstalls.length, 0, "Should be no active installs");
-
-    if (TESTS.length == 0) {
-      finish();
-      return;
-    }
-
-    info("Running " + TESTS[0].name);
-    gTestStart = Date.now();
-    TESTS.shift()();
-  });
-}
-
 var XPInstallObserver = {
   observe: function (aSubject, aTopic, aData) {
     var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
     info("Observed " + aTopic + " for " + installInfo.installs.length + " installs");
     installInfo.installs.forEach(function(aInstall) {
       info("Install of " + aInstall.sourceURI.spec + " was in state " + aInstall.state);
     });
   }
 };
 
-function test() {
+add_task(function* () {
   requestLongerTimeout(4);
-  waitForExplicitFinish();
 
   Services.prefs.setBoolPref("extensions.logging.enabled", true);
   Services.prefs.setBoolPref("extensions.strictCompatibility", true);
   Services.prefs.setBoolPref("extensions.install.requireSecureOrigin", false);
   Services.prefs.setIntPref("security.dialog_enable_delay", 0);
 
   Services.obs.addObserver(XPInstallObserver, "addon-install-started", false);
   Services.obs.addObserver(XPInstallObserver, "addon-install-blocked", false);
@@ -1175,10 +1168,26 @@ function test() {
     Services.prefs.clearUserPref("security.dialog_enable_delay");
 
     Services.obs.removeObserver(XPInstallObserver, "addon-install-started");
     Services.obs.removeObserver(XPInstallObserver, "addon-install-blocked");
     Services.obs.removeObserver(XPInstallObserver, "addon-install-failed");
     Services.obs.removeObserver(XPInstallObserver, "addon-install-complete");
   });
 
-  runNextTest();
-}
+  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 = yield new Promise(resolve => {
+      AddonManager.getAllInstalls(function(aInstalls) {
+        resolve(aInstalls);
+      });
+    });
+
+    is(installs.length, 0, "Should be no active installs");
+    info("Running " + TESTS[i].name);
+    gTestStart = Date.now();
+    yield TESTS[i]();
+  }
+});
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -799,23 +799,30 @@ PopupNotifications.prototype = {
     notificationsToShow = notificationsToShow.filter(n => {
       let dismiss = this._fireCallback(n, NOTIFICATION_EVENT_SHOWING);
       if (dismiss)
         n.dismissed = true;
       return !dismiss;
     });
     if (!notificationsToShow.length)
       return;
+    let notificationIds = notificationsToShow.map(n => n.id);
 
     this._refreshPanel(notificationsToShow);
 
     if (this.isPanelOpen && this._currentAnchorElement == anchorElement) {
       notificationsToShow.forEach(function (n) {
         this._fireCallback(n, NOTIFICATION_EVENT_SHOWN);
       }, this);
+      // Let tests know that the panel was updated and what notifications it was
+      // updated with so that tests can wait for the correct notifications to be
+      // added.
+      let event = new this.window.CustomEvent("PanelUpdated",
+                                              {"detail": notificationIds});
+      this.panel.dispatchEvent(event);
       return;
     }
 
     // If the panel is already open but we're changing anchors, we need to hide
     // it first.  Otherwise it can appear in the wrong spot.  (_hidePanel is
     // safe to call even if the panel is already hidden.)
     let promise = this._hidePanel().then(() => {
       // If the anchor element is hidden or null, use the tab as the anchor. We
@@ -864,19 +871,22 @@ PopupNotifications.prototype = {
       }
       this._popupshownListener = function (e) {
         target.removeEventListener("popupshown", this._popupshownListener, true);
         this._popupshownListener = null;
 
         notificationsToShow.forEach(function (n) {
           this._fireCallback(n, NOTIFICATION_EVENT_SHOWN);
         }, this);
-        // This notification is used by tests to know when all the processing
+        // These notifications are used by tests to know when all the processing
         // required to display the panel has happened.
         this.panel.dispatchEvent(new this.window.CustomEvent("Shown"));
+        let event = new this.window.CustomEvent("PanelUpdated",
+                                                {"detail": notificationIds});
+        this.panel.dispatchEvent(event);
       };
       this._popupshownListener = this._popupshownListener.bind(this);
       target.addEventListener("popupshown", this._popupshownListener, true);
 
       this.panel.openPopup(anchorElement, "bottomcenter topleft");
     });
   },