Bug 1206133 - Fix browser_bug553455.js such that it does not make invalid assumptions about how panels work and refactor from callbacks to Tasks and Promises. r=rhelmer
☠☠ backed out by 0f0d055ed09a ☠ ☠
authorKirk Steuber <ksteuber@mozilla.com>
Tue, 06 Sep 2016 11:04:06 -0700
changeset 356965 baaf5f5624d32358ba3a1464dc5c5b3333103116
parent 356964 b99b5f17840568617f01a3e78d8f078283c9e371
child 356966 0f0d055ed09a8c234ae192a860c222be430878fd
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhelmer
bugs1206133, 553455
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1206133 - Fix browser_bug553455.js such that it does not make invalid assumptions about how panels work and refactor 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
@@ -126,16 +126,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");
     });
   },