Bug 1315872: Refactor tests that check for promise rejection to use assertRejects. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Mon, 07 Nov 2016 22:04:49 -0800
changeset 435221 f6ebc5d9665d33993d1d627c654e6f2484eb21c2
parent 435220 f961ab661da5728b1e0afab4d486f2d69256bbb1
child 435222 6209a00f1dc055785ef2c6deafd2352b1d63914a
push id34962
push usermaglione.k@gmail.com
push dateTue, 08 Nov 2016 06:10:49 +0000
reviewersaswan
bugs1315872
milestone52.0a1
Bug 1315872: Refactor tests that check for promise rejection to use assertRejects. r?aswan MozReview-Commit-ID: 1fBE7B2OdH7
browser/components/extensions/ext-contextMenus.js
browser/components/extensions/test/browser/browser_ext_browserAction_context.js
browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon_permissions.js
browser/components/extensions/test/browser/browser_ext_contextMenus.js
browser/components/extensions/test/browser/browser_ext_popup_sendMessage.js
browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
browser/components/extensions/test/browser/browser_ext_tabs_move.js
browser/components/extensions/test/browser/browser_ext_tabs_move_window.js
browser/components/extensions/test/browser/browser_ext_tabs_query.js
browser/components/extensions/test/browser/browser_ext_tabs_zoom.js
browser/components/extensions/test/browser/browser_ext_webNavigation_getFrames.js
browser/components/extensions/test/browser/browser_ext_windows_create_params.js
browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
browser/components/extensions/test/browser/browser_ext_windows_update.js
browser/components/extensions/test/browser/head_pageAction.js
toolkit/components/extensions/ExtensionUtils.jsm
toolkit/components/extensions/test/mochitest/test_ext_sendmessage_no_receiver.html
toolkit/components/extensions/test/xpcshell/test_ext_downloads.js
toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js
toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js
toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_self.js
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -4,16 +4,17 @@
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 Cu.import("resource://gre/modules/MatchPattern.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var {
   EventManager,
+  ExtensionError,
   IconDetails,
 } = ExtensionUtils;
 
 // Map[Extension -> Map[ID -> MenuItem]]
 // Note: we want to enumerate all the menu items so
 // this cannot be a weak map.
 var gContextMenuMap = new Map();
 
@@ -321,17 +322,17 @@ MenuItem.prototype = {
       return;
     }
     let menuMap = gContextMenuMap.get(this.extension);
     if (!menuMap.has(parentId)) {
       throw new Error("Could not find any MenuItem with id: " + parentId);
     }
     for (let item = menuMap.get(parentId); item; item = item.parent) {
       if (item === this) {
-        throw new Error("MenuItem cannot be an ancestor (or self) of its new parent.");
+        throw new ExtensionError("MenuItem cannot be an ancestor (or self) of its new parent.");
       }
     }
   },
 
   set parentId(parentId) {
     this.ensureValidParentId(parentId);
 
     if (this.parent) {
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -1,14 +1,14 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 function* runTests(options) {
-  function background(getTests) {
+  async function background(getTests) {
     async function checkDetails(expecting, tabId) {
       let title = await browser.browserAction.getTitle({tabId});
       browser.test.assertEq(expecting.title, title,
                             "expected value from getTitle");
 
       let popup = await browser.browserAction.getPopup({tabId});
       browser.test.assertEq(expecting.popup, popup,
                             "expected value from getPopup");
@@ -38,29 +38,20 @@ function* runTests(options) {
         () => browser.browserAction.setTitle({tabId, title: "foo"}),
         () => browser.browserAction.setIcon({tabId, path: "foo.png"}),
         () => browser.browserAction.setPopup({tabId, popup: "foo.html"}),
         () => browser.browserAction.setBadgeText({tabId, text: "foo"}),
         () => browser.browserAction.setBadgeBackgroundColor({tabId, color: [0xff, 0, 0, 0xff]}),
       ];
 
       for (let call of calls) {
-        let checkError = e => {
-          browser.test.assertTrue(e.message.includes(`Invalid tab ID: ${tabId}`),
-                                  `Expected invalid tab ID error, got ${e}`);
-        };
-        try {
-          call().then(() => {
-            browser.test.fail(`Expected call to fail: ${call}`);
-          }, e => {
-            checkError(e);
-          });
-        } catch (e) {
-          checkError(e);
-        }
+        await browser.test.assertRejects(
+          new Promise(resolve => resolve(call())),
+          RegExp(`Invalid tab ID: ${tabId}`),
+          "Expected invalid tab ID error");
       }
     }
 
     // Runs the next test in the `tests` array, checks the results,
     // and passes control back to the outer test scope.
     function nextTest() {
       let test = tests.shift();
 
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon_permissions.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon_permissions.js
@@ -15,24 +15,20 @@ add_task(function* testInvalidIconSizes(
         let tabId = tabs[0].id;
 
         let promises = [];
         for (let api of ["pageAction", "browserAction"]) {
           // helper function to run setIcon and check if it fails
           let assertSetIconThrows = function(detail, error, message) {
             detail.tabId = tabId;
             promises.push(
-              browser[api].setIcon(detail).then(
-                () => {
-                  browser.test.fail("Expected an error on invalid icon size.");
-                  browser.test.notifyFail("setIcon with invalid icon size");
-                },
-                error => {
-                  browser.test.succeed("setIcon with invalid icon size");
-                }));
+              browser.test.assertRejects(
+                browser[api].setIcon(detail),
+                /must be an integer/,
+                "setIcon with invalid icon size"));
           };
 
           let imageData = new ImageData(1, 1);
 
           // test invalid icon size inputs
           for (let type of ["path", "imageData"]) {
             let img = type == "imageData" ? imageData : "test.png";
 
@@ -143,24 +139,20 @@ add_task(function* testSecureURLsDenied(
 
         let urls = ["chrome://browser/content/browser.xul",
                     "javascript:true"];
 
         let promises = [];
         for (let url of urls) {
           for (let api of ["pageAction", "browserAction"]) {
             promises.push(
-              browser[api].setIcon({tabId, path: url}).then(
-                () => {
-                  browser.test.fail(`Load of '${url}' succeeded. Expected failure.`);
-                  browser.test.notifyFail("setIcon security tests");
-                },
-                error => {
-                  browser.test.succeed(`Load of '${url}' failed. Expected failure. ${error}`);
-                }));
+              browser.test.assertRejects(
+                browser[api].setIcon({tabId, path: url}),
+                /Illegal URL/,
+                `Load of '${url}' should fail.`));
           }
         }
 
         Promise.all(promises).then(() => {
           browser.test.notifyPass("setIcon security tests");
         });
       });
     },
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus.js
@@ -47,17 +47,17 @@ add_task(function* () {
 
   gBrowser.selectedTab = tab1;
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["contextMenus"],
     },
 
-    background: function() {
+    background: async function() {
       // A generic onclick callback function.
       function genericOnClick(info, tab) {
         browser.test.sendMessage("onclick", {info, tab});
       }
 
       browser.contextMenus.onClicked.addListener((info, tab) => {
         browser.test.sendMessage("browser.contextMenus.onClicked", {info, tab});
       });
@@ -117,24 +117,22 @@ add_task(function* () {
       });
       browser.contextMenus.remove(parentToDel);
 
       browser.contextMenus.create({
         title: "Without onclick property",
         id: "ext-without-onclick",
       });
 
-      browser.contextMenus.update(parent, {parentId: child2}).then(
-        () => {
-          browser.test.notifyFail("contextmenus");
-        },
-        () => {
-          browser.test.notifyPass("contextmenus");
-        }
-      );
+      await browser.test.assertRejects(
+        browser.contextMenus.update(parent, {parentId: child2}),
+        /cannot be an ancestor/,
+        "Should not be able to reparent an item as descendent of itself");
+
+      browser.test.notifyPass("contextmenus");
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("contextmenus");
 
   let expectedClickInfo = {
     menuItemId: "ext-image",
--- a/browser/components/extensions/test/browser/browser_ext_popup_sendMessage.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_sendMessage.js
@@ -15,55 +15,54 @@ add_task(function* test_popup_sendMessag
       "page_action": {
         "default_popup": "popup.html",
         "browser_style": true,
       },
     },
 
     files: {
       "popup.html": scriptPage("popup.js"),
-      "popup.js": function() {
-        browser.runtime.onMessage.addListener(msg => {
+      "popup.js": async function() {
+        browser.runtime.onMessage.addListener(async msg => {
           if (msg == "popup-ping") {
             return Promise.resolve("popup-pong");
           }
         });
 
-        browser.runtime.sendMessage("background-ping").then(response => {
-          browser.test.sendMessage("background-ping-response", response);
-        });
+        let response = await browser.runtime.sendMessage("background-ping");
+        browser.test.sendMessage("background-ping-response", response);
       },
     },
 
-    background() {
-      browser.tabs.query({active: true, currentWindow: true}).then(([tab]) => {
-        return browser.pageAction.show(tab.id);
-      }).then(() => {
-        browser.test.sendMessage("page-action-ready");
-      });
+    async background() {
+      browser.runtime.onMessage.addListener(async msg => {
+        if (msg == "background-ping") {
+          let response = await browser.runtime.sendMessage("popup-ping");
 
-      browser.runtime.onMessage.addListener(msg => {
-        if (msg == "background-ping") {
-          browser.runtime.sendMessage("popup-ping").then(response => {
-            browser.test.sendMessage("popup-ping-response", response);
-          });
+          browser.test.sendMessage("popup-ping-response", response);
 
-          return new Promise(resolve => {
+          await new Promise(resolve => {
             // Wait long enough that we're relatively sure the docShells have
             // been swapped. Note that this value is fairly arbitrary. The load
             // event that triggers the swap should happen almost immediately
             // after the message is sent. The extra quarter of a second gives us
             // enough leeway that we can expect to respond after the swap in the
             // vast majority of cases.
             setTimeout(resolve, 250);
-          }).then(() => {
-            return "background-pong";
           });
+
+          return "background-pong";
         }
       });
+
+      let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+
+      await browser.pageAction.show(tab.id);
+
+      browser.test.sendMessage("page-action-ready");
     },
   });
 
   yield extension.startup();
 
   {
     clickBrowserAction(extension);
 
--- a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
@@ -254,34 +254,23 @@ add_tasks(function* test_tab_options(ext
 add_tasks(function* test_options_no_manifest(extraOptions) {
   info(`Test with no manifest key (${JSON.stringify(extraOptions)})`);
 
   let extension = yield loadExtension(Object.assign({}, extraOptions, {
     manifest: {
       applications: {gecko: {id: "no_options@tests.mozilla.org"}},
     },
 
-    background: function() {
+    async background() {
       browser.test.log("Try to open options page when not specified in the manifest.");
 
-      browser.runtime.openOptionsPage().then(
-        () => {
-          browser.test.fail("Opening options page without one specified in the manifest generated an error");
-          browser.test.notifyFail("options-no-manifest");
-        },
-        error => {
-          let expected = "No `options_ui` declared";
-          browser.test.assertTrue(
-            error.message.includes(expected),
-            `Got expected error (got: '${error.message}', expected: '${expected}'`);
-        }
-      ).then(() => {
-        browser.test.notifyPass("options-no-manifest");
-      }).catch(error => {
-        browser.test.fail(`Error: ${error} :: ${error.stack}`);
-        browser.test.notifyFail("options-no-manifest");
-      });
+      await browser.test.assertRejects(
+        browser.runtime.openOptionsPage(),
+        /No `options_ui` declared/,
+        "Expected error from openOptionsPage()");
+
+      browser.test.notifyPass("options-no-manifest");
     },
   }));
 
   yield extension.awaitFinish("options-no-manifest");
   yield extension.unload();
 });
--- a/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
@@ -25,41 +25,32 @@ function* makeAndInstallXPI(id, backgrou
   let loadTab = yield loadPromise;
   yield BrowserTestUtils.removeTab(loadTab);
 
   return addon;
 }
 
 
 add_task(function* test_setuninstallurl_badargs() {
-  async function backgroundScript() {
-    let promises = [
-      browser.runtime.setUninstallURL("this is not a url")
-        .then(() => {
-          browser.test.notifyFail("setUninstallURL should have failed with bad url");
-        })
-        .catch(error => {
-          browser.test.assertTrue(/Invalid URL/.test(error.message), "error message indicates malformed url");
-        }),
+  async function background() {
+    await browser.test.assertRejects(
+      browser.runtime.setUninstallURL("this is not a url"),
+      /Invalid URL/,
+      "setUninstallURL with an invalid URL should fail");
 
-      browser.runtime.setUninstallURL("file:///etc/passwd")
-        .then(() => {
-          browser.test.notifyFail("setUninstallURL should have failed with non-http[s] url");
-        })
-        .catch(error => {
-          browser.test.assertTrue(/must have the scheme http or https/.test(error.message), "error message indicates bad scheme");
-        }),
-    ];
+    await browser.test.assertRejects(
+      browser.runtime.setUninstallURL("file:///etc/passwd"),
+      /must have the scheme http or https/,
+      "setUninstallURL with an illegal URL should fail");
 
-    await Promise.all(promises);
     browser.test.notifyPass("setUninstallURL bad params");
   }
 
   let extension = ExtensionTestUtils.loadExtension({
-    background: "(" + backgroundScript.toString() + ")()",
+    background,
   });
   yield extension.startup();
   yield extension.awaitFinish();
   yield extension.unload();
 });
 
 // Test the documented behavior of setUninstallURL() that passing an
 // empty string is equivalent to not setting an uninstall URL
--- a/browser/components/extensions/test/browser/browser_ext_tabs_move.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_move.js
@@ -8,109 +8,94 @@ add_task(function* () {
 
   gBrowser.selectedTab = tab1;
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["tabs"],
     },
 
-    background: function() {
-      browser.tabs.query({
-        lastFocusedWindow: true,
-      }, function(tabs) {
-        let tab = tabs[0];
-        browser.tabs.move(tab.id, {index: 0});
-        browser.tabs.query(
-          {lastFocusedWindow: true},
-          tabs => {
-            browser.test.assertEq(tabs[0].url, tab.url, "should be first tab");
-            browser.test.notifyPass("tabs.move.single");
-          });
-      });
+    background: async function() {
+      let [tab] = await browser.tabs.query({lastFocusedWindow: true});
+
+      browser.tabs.move(tab.id, {index: 0});
+      let tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+      browser.test.assertEq(tabs[0].url, tab.url, "should be first tab");
+      browser.test.notifyPass("tabs.move.single");
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.single");
   yield extension.unload();
 
   extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["tabs"],
     },
 
-    background: function() {
-      browser.tabs.query(
-        {lastFocusedWindow: true},
-        tabs => {
-          tabs.sort(function(a, b) { return a.url > b.url; });
-          browser.tabs.move(tabs.map(tab => tab.id), {index: 0});
-          browser.tabs.query(
-            {lastFocusedWindow: true},
-            tabs => {
-              browser.test.assertEq(tabs[0].url, "about:blank", "should be first tab");
-              browser.test.assertEq(tabs[1].url, "about:config", "should be second tab");
-              browser.test.assertEq(tabs[2].url, "about:robots", "should be third tab");
-              browser.test.notifyPass("tabs.move.multiple");
-            });
-        });
+    background: async function() {
+      let tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+      tabs.sort(function(a, b) { return a.url > b.url; });
+
+      browser.tabs.move(tabs.map(tab => tab.id), {index: 0});
+
+      tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+      browser.test.assertEq(tabs[0].url, "about:blank", "should be first tab");
+      browser.test.assertEq(tabs[1].url, "about:config", "should be second tab");
+      browser.test.assertEq(tabs[2].url, "about:robots", "should be third tab");
+
+      browser.test.notifyPass("tabs.move.multiple");
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.multiple");
   yield extension.unload();
 
   extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["tabs"],
     },
 
     async background() {
       let [, tab] = await browser.tabs.query({lastFocusedWindow: true});
 
       // Assuming that tab.id of 12345 does not exist.
-      await browser.tabs.move([tab.id, 12345], {index: 0}).then(
-        tabs => {
-          browser.test.fail("Promise should not resolve");
-        },
-        e => {
-          browser.test.assertTrue(/Invalid tab/.test(e),
-                                  "Invalid tab should be in error");
-        });
+      await browser.test.assertRejects(
+        browser.tabs.move([tab.id, 12345], {index: 0}),
+        /Invalid tab/,
+        "Should receive invalid tab error");
 
       let tabs = await browser.tabs.query({lastFocusedWindow: true});
       browser.test.assertEq(tabs[1].url, tab.url, "should be second tab");
       browser.test.notifyPass("tabs.move.invalid");
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.invalid");
   yield extension.unload();
 
   extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["tabs"],
     },
 
-    background: function() {
-      browser.tabs.query(
-        {lastFocusedWindow: true},
-        tabs => {
-          let tab = tabs[0];
-          browser.tabs.move(tab.id, {index: -1});
-          browser.tabs.query(
-            {lastFocusedWindow: true},
-            tabs => {
-              browser.test.assertEq(tabs[2].url, tab.url, "should be last tab");
-              browser.test.notifyPass("tabs.move.last");
-            });
-        });
+    background: async function() {
+      let [tab] = await browser.tabs.query({lastFocusedWindow: true});
+      browser.tabs.move(tab.id, {index: -1});
+
+      let tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+      browser.test.assertEq(tabs[2].url, tab.url, "should be last tab");
+      browser.test.notifyPass("tabs.move.last");
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.last");
   yield extension.unload();
 
   yield BrowserTestUtils.removeTab(tab1);
--- a/browser/components/extensions/test/browser/browser_ext_tabs_move_window.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_move_window.js
@@ -13,24 +13,20 @@ add_task(function* () {
     },
 
     async background() {
       let tabs = await browser.tabs.query({url: "<all_urls>"});
       let destination = tabs[0];
       let source = tabs[1]; // skip over about:blank in window1
 
       // Assuming that this windowId does not exist.
-      await browser.tabs.move(source.id, {windowId: 123144576, index: 0}).then(
-        tabs => {
-          browser.test.fail("Promise should not resolve");
-        },
-        e => {
-          browser.test.assertTrue(/Invalid window/.test(e),
-                                  "Invalid window should be in error");
-        });
+      await browser.test.assertRejects(
+        browser.tabs.move(source.id, {windowId: 123144576, index: 0}),
+        /Invalid window/,
+        "Should receive invalid window error");
 
       browser.tabs.move(source.id, {windowId: destination.windowId, index: 0});
 
       tabs = await browser.tabs.query({url: "<all_urls>"});
       browser.test.assertEq(tabs[0].url, "http://example.com/");
       browser.test.assertEq(tabs[0].windowId, destination.windowId);
       browser.test.notifyPass("tabs.move.window");
     },
--- a/browser/components/extensions/test/browser/browser_ext_tabs_query.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_query.js
@@ -201,24 +201,23 @@ add_task(function* testQueryPermissions(
 });
 
 add_task(function* testQueryWithURLPermissions() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": [],
     },
 
-    background: function() {
-      browser.tabs.query({"url": "http://www.bbc.com/"}).then(() => {
-        browser.test.notifyFail("queryWithURLPermissions");
-      }).catch((e) => {
-        browser.test.assertEq('The "tabs" permission is required to use the query API with the "url" parameter',
-                              e.message, "Expected permissions error message");
-        browser.test.notifyPass("queryWithURLPermissions");
-      });
+    async background() {
+      await browser.test.assertRejects(
+        browser.tabs.query({"url": "http://www.bbc.com/"}),
+        'The "tabs" permission is required to use the query API with the "url" parameter',
+        "Expected tabs.query with 'url' to fail with permissions error message");
+
+      browser.test.notifyPass("queryWithURLPermissions");
     },
   });
 
   yield extension.startup();
 
   yield extension.awaitFinish("queryWithURLPermissions");
 
   yield extension.unload();
--- a/browser/components/extensions/test/browser/browser_ext_tabs_zoom.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_zoom.js
@@ -156,25 +156,20 @@ add_task(function* () {
       ]);
       await Promise.all([
         checkZoom(tabIds[0], 1, 1.1),
         checkZoom(tabIds[1], 1, 1.5),
       ]);
 
 
       browser.test.log("Check that invalid zoom values throw an error");
-      await browser.tabs.setZoom(tabIds[0], 42).then(
-        () => {
-          browser.test.fail("Expected an error");
-        },
-        error => {
-          browser.test.assertTrue(error.message.includes("Zoom value 42 out of range"),
-                                  "Got expected error");
-        });
-
+      await browser.test.assertRejects(
+        browser.tabs.setZoom(tabIds[0], 42),
+        /Zoom value 42 out of range/,
+        "Expected an out of range error");
 
       browser.test.log("Disable site-specific zoom, expect correct scope");
       await msg("site-specific", false);
       zoomSettings = await browser.tabs.getZoomSettings(tabIds[0]);
 
       browser.test.assertEq("per-tab", zoomSettings.scope, `Scope should be "per-tab"`);
       await msg("site-specific", null);
 
--- a/browser/components/extensions/test/browser/browser_ext_webNavigation_getFrames.js
+++ b/browser/components/extensions/test/browser/browser_ext_webNavigation_getFrames.js
@@ -1,36 +1,28 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(function* testWebNavigationGetNonExistentTab() {
   let extension = ExtensionTestUtils.loadExtension({
     background: async function() {
-      let results = [
-        // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
-        // starts from 1.
-        browser.webNavigation.getAllFrames({tabId: 0}).then(() => {
-          browser.test.fail("getAllFrames Promise should be rejected on error");
-        }, (error) => {
-          browser.test.assertEq("Invalid tab ID: 0", error.message,
-                                "getAllFrames rejected Promise should pass the expected error");
-        }),
+      // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
+      // starts from 1.
+      await browser.test.assertRejects(
+        browser.webNavigation.getAllFrames({tabId: 0}),
+        "Invalid tab ID: 0",
+        "getAllFrames rejected Promise should pass the expected error");
 
-        // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
-        // starts from 1, processId is currently marked as optional and it is ignored.
-        browser.webNavigation.getFrame({tabId: 0, frameId: 15, processId: 20}).then(() => {
-          browser.test.fail("getFrame Promise should be rejected on error");
-        }, (error) => {
-          browser.test.assertEq("Invalid tab ID: 0", error.message,
-                                "getFrame rejected Promise should pass the expected error");
-        }),
-      ];
-
-      await Promise.all(results);
+      // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
+      // starts from 1, processId is currently marked as optional and it is ignored.
+      await browser.test.assertRejects(
+        browser.webNavigation.getFrame({tabId: 0, frameId: 15, processId: 20}),
+        "Invalid tab ID: 0",
+        "getFrame rejected Promise should pass the expected error");
 
       browser.test.sendMessage("getNonExistentTab.done");
     },
     manifest: {
       permissions: ["webNavigation"],
     },
   });
   info("load complete");
@@ -74,24 +66,20 @@ add_task(function* testWebNavigationFram
         let nonExistentFrameId = Math.floor(Math.random() * 10000);
 
         // Increment the picked random nonExistentFrameId until it doesn't exists.
         while (getAllFramesDetails.filter((details) => details.frameId == nonExistentFrameId).length > 0) {
           nonExistentFrameId += 1;
         }
 
         // Check that getFrame Promise is rejected with the expected error message on nonexistent frameId.
-        await browser.webNavigation.getFrame({tabId, frameId: nonExistentFrameId, processId: 20}).then(
-          () => {
-            browser.test.fail("getFrame promise should be rejected for an unexistent frameId");
-          },
-          error => {
-            browser.test.assertEq(`No frame found with frameId: ${nonExistentFrameId}`, error.message,
-                                  "getFrame promise should be rejected with the expected error message on unexistent frameId");
-          });
+        await browser.test.assertRejects(
+          browser.webNavigation.getFrame({tabId, frameId: nonExistentFrameId, processId: 20}),
+          `No frame found with frameId: ${nonExistentFrameId}`,
+          "getFrame promise should be rejected with the expected error message on unexistent frameId");
 
         await browser.tabs.remove(tabId);
         browser.test.sendMessage("webNavigationFrames.done");
       });
 
       let tab = await browser.tabs.create({url: "tab.html"});
       tabId = tab.id;
     },
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_params.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_params.js
@@ -2,36 +2,27 @@
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 
 // Tests that incompatible parameters can't be used together.
 add_task(function* testWindowCreateParams() {
   let extension = ExtensionTestUtils.loadExtension({
     async background() {
-      function* getCalls() {
+      try {
         for (let state of ["minimized", "maximized", "fullscreen"]) {
           for (let param of ["left", "top", "width", "height"]) {
             let expected = `"state": "${state}" may not be combined with "left", "top", "width", or "height"`;
 
-            yield browser.windows.create({state, [param]: 100}).then(
-              val => {
-                browser.test.fail(`Expected error but got "${val}" instead`);
-              },
-              error => {
-                browser.test.assertTrue(
-                  error.message.includes(expected),
-                  `Got expected error (got: '${error.message}', expected: '${expected}'`);
-              });
+            await browser.test.assertRejects(
+              browser.windows.create({state, [param]: 100}),
+              RegExp(expected),
+              `Got expected error from create(${param}=100)`);
           }
         }
-      }
-
-      try {
-        await Promise.all(getCalls());
 
         browser.test.notifyPass("window-create-params");
       } catch (e) {
         browser.test.fail(`${e} :: ${e.stack}`);
         browser.test.notifyFail("window-create-params");
       }
     },
   });
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
@@ -71,46 +71,33 @@ add_task(function* testWindowCreate() {
 
         browser.test.log("Close the private window");
         await browser.windows.remove(privateWindow.id);
       }
 
 
       browser.test.log("Try to create a window with both a tab and a URL");
       [tab] = await browser.tabs.query({windowId, active: true});
-      await browser.windows.create({tabId: tab.id, url: "http://example.com/"}).then(
-        window => {
-          browser.test.fail("Create call should have failed");
-        },
-        error => {
-          browser.test.assertTrue(/`tabId` may not be used in conjunction with `url`/.test(error.message),
-                                  "Create call failed as expected");
-        });
-
+      await browser.test.assertRejects(
+        browser.windows.create({tabId: tab.id, url: "http://example.com/"}),
+        /`tabId` may not be used in conjunction with `url`/,
+        "Create call failed as expected");
 
       browser.test.log("Try to create a window with both a tab and an invalid incognito setting");
-      await browser.windows.create({tabId: tab.id, incognito: true}).then(
-        window => {
-          browser.test.fail("Create call should have failed");
-        },
-        error => {
-          browser.test.assertTrue(/`incognito` property must match the incognito state of tab/.test(error.message),
-                                  "Create call failed as expected");
-        });
+      await browser.test.assertRejects(
+        browser.windows.create({tabId: tab.id, incognito: true}),
+        /`incognito` property must match the incognito state of tab/,
+        "Create call failed as expected");
 
 
       browser.test.log("Try to create a window with an invalid tabId");
-      await browser.windows.create({tabId: 0}).then(
-        window => {
-          browser.test.fail("Create call should have failed");
-        },
-        error => {
-          browser.test.assertTrue(/Invalid tab ID: 0/.test(error.message),
-                                  "Create call failed as expected");
-        });
+      await browser.test.assertRejects(
+        browser.windows.create({tabId: 0}),
+        /Invalid tab ID: 0/,
+        "Create call failed as expected");
 
 
       browser.test.log("Try to create a window with two URLs");
       [, , window] = await Promise.all([
         // tabs.onUpdated can be invoked between the call of windows.create and
         // the invocation of its callback/promise, so set up the listeners
         // before creating the window.
         promiseTabUpdated("http://example.com/"),
--- a/browser/components/extensions/test/browser/browser_ext_windows_update.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_update.js
@@ -157,37 +157,29 @@ add_task(function* () {
   yield BrowserTestUtils.closeWindow(window2);
 });
 
 
 // Tests that incompatible parameters can't be used together.
 add_task(function* testWindowUpdateParams() {
   let extension = ExtensionTestUtils.loadExtension({
     async background() {
-      function* getCalls() {
+      try {
         for (let state of ["minimized", "maximized", "fullscreen"]) {
           for (let param of ["left", "top", "width", "height"]) {
             let expected = `"state": "${state}" may not be combined with "left", "top", "width", or "height"`;
 
             let windowId = browser.windows.WINDOW_ID_CURRENT;
-            yield browser.windows.update(windowId, {state, [param]: 100}).then(
-              val => {
-                browser.test.fail(`Expected error but got "${val}" instead`);
-              },
-              error => {
-                browser.test.assertTrue(
-                  error.message.includes(expected),
-                  `Got expected error (got: '${error.message}', expected: '${expected}'`);
-              });
+            await browser.test.assertRejects(
+              browser.windows.update(windowId, {state, [param]: 100}),
+              RegExp(expected),
+              `Got expected error for create(${param}=100`);
           }
         }
-      }
 
-      try {
-        await Promise.all(getCalls());
         browser.test.notifyPass("window-update-params");
       } catch (e) {
         browser.test.fail(`${e} :: ${e.stack}`);
         browser.test.notifyFail("window-update-params");
       }
     },
   });
 
--- a/browser/components/extensions/test/browser/head_pageAction.js
+++ b/browser/components/extensions/test/browser/head_pageAction.js
@@ -7,71 +7,66 @@
 
 function* runTests(options) {
   function background(getTests) {
     let tabs;
     let tests;
 
     // Gets the current details of the page action, and returns a
     // promise that resolves to an object containing them.
-    function getDetails() {
-      return new Promise(resolve => {
-        return browser.tabs.query({active: true, currentWindow: true}, resolve);
-      }).then(([tab]) => {
-        let tabId = tab.id;
-        browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
-        return Promise.all([
-          browser.pageAction.getTitle({tabId}),
-          browser.pageAction.getPopup({tabId})]);
-      }).then(details => {
-        return Promise.resolve({title: details[0],
-                                popup: details[1]});
-      });
+    async function getDetails() {
+      let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+      let tabId = tab.id;
+
+      browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
+
+      return {
+        title: await browser.pageAction.getTitle({tabId}),
+        popup: await browser.pageAction.getPopup({tabId}),
+      };
     }
 
 
     // Runs the next test in the `tests` array, checks the results,
     // and passes control back to the outer test scope.
     function nextTest() {
       let test = tests.shift();
 
-      test(expecting => {
+      test(async expecting => {
         function finish() {
           // Check that the actual icon has the expected values, then
           // run the next test.
           browser.test.sendMessage("nextTest", expecting, tests.length);
         }
 
         if (expecting) {
           // Check that the API returns the expected values, and then
           // run the next test.
-          getDetails().then(details => {
-            browser.test.assertEq(expecting.title, details.title,
-                                  "expected value from getTitle");
+          let details = await getDetails();
+
+          browser.test.assertEq(expecting.title, details.title,
+                                "expected value from getTitle");
 
-            browser.test.assertEq(expecting.popup, details.popup,
-                                  "expected value from getPopup");
+          browser.test.assertEq(expecting.popup, details.popup,
+                                "expected value from getPopup");
+        }
 
-            finish();
-          });
-        } else {
-          finish();
-        }
+        finish();
       });
     }
 
-    function runTests() {
+    async function runTests() {
       tabs = [];
       tests = getTests(tabs);
 
-      browser.tabs.query({active: true, currentWindow: true}, resultTabs => {
-        tabs[0] = resultTabs[0].id;
+      let resultTabs = await browser.tabs.query({active: true, currentWindow: true});
 
-        nextTest();
-      });
+      tabs[0] = resultTabs[0].id;
+
+      nextTest();
     }
 
     browser.test.onMessage.addListener((msg) => {
       if (msg == "runTests") {
         runTests();
       } else if (msg == "runNextTest") {
         nextTest();
       } else {
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -535,44 +535,48 @@ let IconDetails = {
         // actual ImageData objects, so they will come from a global
         // with the right property.
         if (instanceOf(imageData, "ImageData")) {
           imageData = {"19": imageData};
         }
 
         for (let size of Object.keys(imageData)) {
           if (!INTEGER.test(size)) {
-            throw new Error(`Invalid icon size ${size}, must be an integer`);
+            throw new ExtensionError(`Invalid icon size ${size}, must be an integer`);
           }
           result[size] = this.convertImageDataToDataURL(imageData[size], context);
         }
       }
 
       if (details.path) {
         let path = details.path;
         if (typeof path != "object") {
           path = {"19": path};
         }
 
         let baseURI = context ? context.uri : extension.baseURI;
 
         for (let size of Object.keys(path)) {
           if (!INTEGER.test(size)) {
-            throw new Error(`Invalid icon size ${size}, must be an integer`);
+            throw new ExtensionError(`Invalid icon size ${size}, must be an integer`);
           }
 
           let url = baseURI.resolve(path[size]);
 
           // The Chrome documentation specifies these parameters as
           // relative paths. We currently accept absolute URLs as well,
           // which means we need to check that the extension is allowed
           // to load them. This will throw an error if it's not allowed.
-          Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
-            extension.principal, url,
-            Services.scriptSecurityManager.DISALLOW_SCRIPT);
+          try {
+            Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
+              extension.principal, url,
+              Services.scriptSecurityManager.DISALLOW_SCRIPT);
+          } catch (e) {
+            throw new ExtensionError(`Illegal URL ${url}`);
+          }
 
           result[size] = url;
         }
       }
     } catch (e) {
       // Function is called from extension code, delegate error.
       if (context) {
         throw e;
--- a/toolkit/components/extensions/test/mochitest/test_ext_sendmessage_no_receiver.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_sendmessage_no_receiver.html
@@ -24,24 +24,22 @@ function loadContentScriptExtension(cont
     files: {
       "contentscript.js": contentScript,
     },
   };
   return ExtensionTestUtils.loadExtension(extensionData);
 }
 
 add_task(function* test_content_script_sendMessage_without_listener() {
-  function contentScript() {
-    browser.runtime.sendMessage("msg").then(reply => {
-      browser.test.assertEq(undefined, reply);
-      browser.test.notifyFail("Did not expect a reply to sendMessage");
-    }, error => {
-      browser.test.assertEq("Could not establish connection. Receiving end does not exist.", error.message);
-      browser.test.notifyPass("sendMessage callback was invoked");
-    });
+  async function contentScript() {
+    await browser.test.assertRejects(
+      browser.runtime.sendMessage("msg"),
+      "Could not establish connection. Receiving end does not exist.");
+
+    browser.test.notifyPass("sendMessage callback was invoked");
   }
 
   let extension = loadContentScriptExtension(contentScript);
   yield extension.startup();
 
   let win = window.open("file_sample.html");
   yield extension.awaitFinish("sendMessage callback was invoked");
   win.close();
--- a/toolkit/components/extensions/test/xpcshell/test_ext_downloads.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads.js
@@ -45,26 +45,23 @@ add_task(function* test_downloads_open_p
 
   let extension = ExtensionTestUtils.loadExtension(extensionData);
   yield extension.startup();
   yield extension.awaitFinish("downloads tests");
   yield extension.unload();
 });
 
 add_task(function* test_downloads_open() {
-  function backgroundScript() {
-    browser.downloads.open(10).then(() => {
-      browser.test.fail("Expected an error");
-      browser.test.notifyFail("downloads tests");
-    }, error => {
-      browser.test.assertEq(error.message, "Invalid download id 10",
-                            "The error is informative.");
+  async function backgroundScript() {
+    await browser.test.assertRejects(
+      browser.downloads.open(10),
+      "Invalid download id 10",
+      "The error is informative.");
 
-      browser.test.notifyPass("downloads tests");
-    });
+    browser.test.notifyPass("downloads tests");
 
     // TODO: Once downloads.{pause,cancel,resume} lands (bug 1245602) test that this gives a good
     // error when called with an incompleted download.
   }
 
   let extensionData = {
     background: backgroundScript,
     manifest: {
--- a/toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
@@ -102,25 +102,23 @@ add_task(function* test_management_unins
   equal(promptService._confirmExArgs[5], "Keep Installed");
   Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null);
 });
 
 add_task(function* test_management_uninstall_prompt_keep() {
   promptService._response = 1;
 
   function background() {
-    browser.test.onMessage.addListener(msg => {
-      browser.management.uninstallSelf({showConfirmDialog: true}).then(() => {
-        browser.test.fail("uninstallSelf rejects when user declines uninstall");
-      }, error => {
-        browser.test.assertEq("User cancelled uninstall of extension",
-                              error.message,
-                              "Expected rejection when user declines uninstall");
-        browser.test.sendMessage("uninstall-rejected");
-      });
+    browser.test.onMessage.addListener(async msg => {
+      await browser.test.assertRejects(
+        browser.management.uninstallSelf({showConfirmDialog: true}),
+        "User cancelled uninstall of extension",
+        "Expected rejection when user declines uninstall");
+
+      browser.test.sendMessage("uninstall-rejected");
     });
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest,
     background,
     useAddonManager: "temporary",
   });
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
@@ -174,21 +174,20 @@ if (AppConstants.platform == "win") {
 }
 
 // Test sendNativeMessage()
 add_task(function* test_sendNativeMessage() {
   async function background() {
     let MSG = {test: "hello world"};
 
     // Check error handling
-    await browser.runtime.sendNativeMessage("nonexistent", MSG).then(() => {
-      browser.test.fail("sendNativeMessage() to a nonexistent app should have failed");
-    }, err => {
-      browser.test.succeed("sendNativeMessage() to a nonexistent app failed");
-    });
+    await browser.test.assertRejects(
+      browser.runtime.sendNativeMessage("nonexistent", MSG),
+      /Attempt to postMessage on disconnected port/,
+      "sendNativeMessage() to a nonexistent app failed");
 
     // Check regular message exchange
     let reply = await browser.runtime.sendNativeMessage("echo", MSG);
 
     let expected = JSON.stringify(MSG);
     let received = JSON.stringify(reply);
     browser.test.assertEq(expected, received, "Received echoed native message");
 
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js
@@ -33,22 +33,20 @@ add_task(function* test_sendMessage_erro
     for (let [args, expectedError] of testCases.slice()) {
       args = args.map(arg => arg === null ? undefined : arg);
       testCases.push([args, expectedError]);
     }
 
     for (let [args, expectedError] of testCases) {
       let description = `runtime.sendMessage(${args.map(String).join(", ")})`;
 
-      await browser.runtime.sendMessage(...args)
-        .then(() => {
-          browser.test.fail(`Unexpectedly got no error for ${description}`);
-        }, err => {
-          browser.test.assertEq(expectedError, err.message, `expected error message for ${description}`);
-        });
+      await browser.test.assertRejects(
+        browser.runtime.sendMessage(...args),
+        expectedError,
+        `expected error message for ${description}`);
     }
 
     browser.test.notifyPass("sendMessage parameter validation");
   }
   let extensionData = {
     background,
   };
 
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js
@@ -1,21 +1,20 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(function* test_sendMessage_without_listener() {
-  function background() {
-    browser.runtime.sendMessage("msg").then(reply => {
-      browser.test.assertEq(undefined, reply);
-      browser.test.notifyFail("Did not expect a reply to sendMessage");
-    }, error => {
-      browser.test.assertEq("Could not establish connection. Receiving end does not exist.", error.message);
-      browser.test.notifyPass("sendMessage callback was invoked");
-    });
+  async function background() {
+    await browser.test.assertRejects(
+      browser.runtime.sendMessage("msg"),
+      "Could not establish connection. Receiving end does not exist.",
+      "sendMessage callback was invoked");
+
+    browser.test.notifyPass("sendMessage callback was invoked");
   }
   let extensionData = {
     background,
   };
 
   let extension = ExtensionTestUtils.loadExtension(extensionData);
   yield extension.startup();
 
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_self.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_self.js
@@ -1,35 +1,32 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 
 "use strict";
 
 add_task(function* test_sendMessage_to_self_should_not_trigger_onMessage() {
-  function background() {
+  async function background() {
     browser.runtime.onMessage.addListener(msg => {
       browser.test.assertEq("msg from child", msg);
       browser.test.notifyPass("sendMessage did not call same-frame onMessage");
     });
 
     browser.test.onMessage.addListener(msg => {
       browser.test.assertEq("sendMessage with a listener in another frame", msg);
       browser.runtime.sendMessage("should only reach another frame");
     });
 
-    browser.runtime.sendMessage("should not trigger same-frame onMessage")
-      .then(reply => {
-        browser.test.fail(`Unexpected reply to sendMessage: ${reply}`);
-      }, err => {
-        browser.test.assertEq("Could not establish connection. Receiving end does not exist.", err.message);
+    await browser.test.assertRejects(
+      browser.runtime.sendMessage("should not trigger same-frame onMessage"),
+      "Could not establish connection. Receiving end does not exist.");
 
-        let anotherFrame = document.createElement("iframe");
-        anotherFrame.src = browser.extension.getURL("extensionpage.html");
-        document.body.appendChild(anotherFrame);
-      });
+    let anotherFrame = document.createElement("iframe");
+    anotherFrame.src = browser.extension.getURL("extensionpage.html");
+    document.body.appendChild(anotherFrame);
   }
 
   function lastScript() {
     browser.runtime.onMessage.addListener(msg => {
       browser.test.assertEq("should only reach another frame", msg);
       browser.runtime.sendMessage("msg from child");
     });
     browser.test.sendMessage("sendMessage callback called");