Bug 1541557: Part 3 - Update callers of sync SpecialPowers functions to await the return value. r=nika
☠☠ backed out by f9bf5e4b0b4f ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Wed, 12 Jun 2019 11:41:32 -0700
changeset 540537 b4ed40bea2698802ef562a0931c0b560737fb89d
parent 540536 158a4000c44b9b17a7935340db79431d544fb556
child 540538 189dc8a359815e059a4a217f788d183260bb2bfe
push id11529
push userarchaeopteryx@coole-files.de
push dateThu, 04 Jul 2019 15:22:33 +0000
treeherdermozilla-beta@ebb510a784b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1541557
milestone69.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 1541557: Part 3 - Update callers of sync SpecialPowers functions to await the return value. r=nika When we migrate SpecialPowers to a JSWindowActor, it will no longer be able to use synchronous IPC messaging, which means that its current synchronous APIs will have to become asynchronous. This patch doesn't change the behavior of those functions, but it does change their callers to `await` their return values rather than using them directly. This pattern will work the same whether the functions return a promise or a plain value, which simplifies the migration. Differential Revision: https://phabricator.services.mozilla.com/D35053
browser/components/originattributes/test/mochitest/test_permissions_api.html
dom/base/test/plugin.js
dom/permission/tests/test_permissions_api.html
dom/plugins/test/mochitest/head.js
dom/plugins/test/mochitest/plugin-utils.js
dom/plugins/test/mochitest/test_bug1165981.html
security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html
testing/mochitest/tests/Harness_sanity/test_importInMainProcess.html
testing/mochitest/tests/SimpleTest/SimpleTest.js
testing/mochitest/tests/SimpleTest/TestRunner.js
testing/specialpowers/content/SpecialPowersAPI.jsm
toolkit/components/url-classifier/tests/mochitest/allowlistAnnotatedFrame.html
toolkit/components/url-classifier/tests/mochitest/test_allowlisted_annotations.html
toolkit/content/tests/browser/head.js
--- a/browser/components/originattributes/test/mochitest/test_permissions_api.html
+++ b/browser/components/originattributes/test/mochitest/test_permissions_api.html
@@ -124,19 +124,19 @@
           () => ok(false, `query should not have rejected for '${name}'`));
       },
       testStatusOnChange() {
         return new Promise((resolve) => {
           SpecialPowers.popPermissions(() => {
             const permission = "geolocation";
             const promiseGranted = this.promiseStateChanged(permission, "granted");
             this.setPermissions(ALLOW_ACTION);
-            promiseGranted.then(() => {
+            promiseGranted.then(async () => {
               const promisePrompt = this.promiseStateChanged(permission, "prompt");
-              SpecialPowers.popPermissions();
+              await SpecialPowers.popPermissions();
               return promisePrompt;
             }).then(resolve);
           });
         });
       },
       testInvalidQuery() {
         return aWindow.navigator.permissions
           .query({ name: "invalid" })
--- a/dom/base/test/plugin.js
+++ b/dom/base/test/plugin.js
@@ -9,24 +9,24 @@ function getTestPlugin(pluginName) {
       return tag;
     }
   }
 
   ok(false, "Could not find plugin tag with plugin name '" + name + "'");
   return null;
 }
 // Copied from /dom/plugins/test/mochitest/utils.js
-function setTestPluginEnabledState(newEnabledState, pluginName) {
-  var oldEnabledState = SpecialPowers.setTestPluginEnabledState(newEnabledState, pluginName);
+async function setTestPluginEnabledState(newEnabledState, pluginName) {
+  var oldEnabledState = await SpecialPowers.setTestPluginEnabledState(newEnabledState, pluginName);
   if (!oldEnabledState) {
     return;
   }
   var plugin = getTestPlugin(pluginName);
   // Run a nested event loop to wait for the preference change to
   // propagate to the child. Yuck!
   SpecialPowers.Services.tm.spinEventLoopUntil(() => {
     return plugin.enabledState == newEnabledState;
   });
   SimpleTest.registerCleanupFunction(function() {
-    SpecialPowers.setTestPluginEnabledState(oldEnabledState, pluginName);
+    return SpecialPowers.setTestPluginEnabledState(oldEnabledState, pluginName);
   });
 }
 setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
--- a/dom/permission/tests/test_permissions_api.html
+++ b/dom/permission/tests/test_permissions_api.html
@@ -125,19 +125,19 @@
           () => ok(false, `query should not have rejected for '${name}'`));
       },
       testStatusOnChange() {
         return new Promise((resolve) => {
           SpecialPowers.popPermissions(() => {
             const permission = 'geolocation';
             const promiseGranted = this.promiseStateChanged(permission, 'granted');
             this.setPermissions(ALLOW_ACTION);
-            promiseGranted.then(() => {
+            promiseGranted.then(async () => {
               const promisePrompt = this.promiseStateChanged(permission, 'prompt');
-              SpecialPowers.popPermissions();
+              await SpecialPowers.popPermissions();
               return promisePrompt;
             }).then(resolve);
           });
         });
       },
       testInvalidQuery() {
         return aWindow.navigator.permissions
           .query({ name: 'invalid' })
--- a/dom/plugins/test/mochitest/head.js
+++ b/dom/plugins/test/mochitest/head.js
@@ -103,17 +103,21 @@ function waitScrollFinish(aTarget) {
 
 /**
  * Set a plugin activation state. See nsIPluginTag for
  * supported states. Affected plugin default to the first
  * test plugin.
  */
 function setTestPluginEnabledState(aState, aPluginName) {
   let name = aPluginName || "Test Plug-in";
-  SpecialPowers.setTestPluginEnabledState(aState, name);
+  let resolved = false;
+  SpecialPowers.setTestPluginEnabledState(aState, name).then(() => {
+    resolved = true;
+  });
+  SpecialPowers.Services.tm.spinEventLoopUntil(() => resolved);
 }
 
 /**
  * Returns the chrome side nsIPluginTag for this plugin, helper for
  * setTestPluginEnabledState.
  */
 function getTestPlugin(aName) {
   let pluginName = aName || "Test Plug-in";
--- a/dom/plugins/test/mochitest/plugin-utils.js
+++ b/dom/plugins/test/mochitest/plugin-utils.js
@@ -28,18 +28,18 @@ function getTestPlugin(pluginName) {
 function setTestPluginEnabledState(newEnabledState, pluginName) {
   var oldEnabledState = SpecialPowers.setTestPluginEnabledState(newEnabledState, pluginName);
   var plugin = getTestPlugin(pluginName);
   // Run a nested event loop to wait for the preference change to
   // propagate to the child. Yuck!
   SpecialPowers.Services.tm.spinEventLoopUntil(() => {
     return plugin.enabledState == newEnabledState;
   });
-  SimpleTest.registerCleanupFunction(function() {
-    SpecialPowers.setTestPluginEnabledState(oldEnabledState, pluginName);
+  SimpleTest.registerCleanupFunction(async function() {
+    return SpecialPowers.setTestPluginEnabledState(await oldEnabledState, pluginName);
   });
 }
 
 function crashAndGetCrashServiceRecord(crashMethodName, callback) {
   var crashMan =
     SpecialPowers.Cu.import("resource://gre/modules/Services.jsm").
     Services.crashmanager;
 
--- a/dom/plugins/test/mochitest/test_bug1165981.html
+++ b/dom/plugins/test/mochitest/test_bug1165981.html
@@ -5,21 +5,16 @@
     <script src="/tests/SimpleTest/SimpleTest.js"></script>
     <script type="text/javascript" src="plugin-utils.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   </head>
     <script class="testbody" type="application/javascript">
       "use strict";
 
       SimpleTest.waitForExplicitFinish();
-      function addPerms() {
-        ok(SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Shockwave Flash"), "Should find allowed test flash plugin");
-        ok(!SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Third Test Plug-in"), "Should not find disallowed plugin");
-        SpecialPowers.pushPermissions([{type: "plugin:flash", allow: true, context: document}], run);
-      }
 
       function findPlugin(pluginName) {
           for (var i = 0; i < navigator.plugins.length; i++) {
             var plugin = navigator.plugins[i];
             if (plugin.name === pluginName) {
               return plugin;
             }
           }
@@ -40,17 +35,23 @@
           let obj = document.createElement("object");
           obj.type = type;
           obj.id = id;
           obj.width = 200;
           obj.height = 200;
           document.body.appendChild(obj);
       }
 
-      function run() {
+      async function run() {
+        ok(await SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Shockwave Flash"), "Should find allowed test flash plugin");
+        ok(!await SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Third Test Plug-in"), "Should not find disallowed plugin");
+        await new Promise(resolve => {
+          SpecialPowers.pushPermissions([{type: "plugin:flash", allow: true, context: document}], resolve);
+        });
+
         createNode("plugin-flash", "application/x-shockwave-flash-test");
         createNode("disallowedPlugin", "application/x-third-test");
         var pluginElement = document.getElementById("plugin-flash");
         is(pluginElement.identifierToStringTest("foo"), "foo", "Should be able to call a function provided by the plugin");
 
         pluginElement = document.getElementById("disallowedPlugin");
         is(typeof pluginElement.identifierToStringTest, "undefined", "Should NOT be able to call a function on a disallowed plugin");
 
@@ -65,11 +66,11 @@
 
         ok(findMimeType("application/x-shockwave-flash-test"), "Should have found a MIME type named 'application/x-shockwave-flash-test'");
         ok(!findMimeType("application/x-third-test"), "Should NOT have found a disallowed MIME type named 'application/x-third-test'");
 
         SimpleTest.finish();
       }
     </script>
 
-  <body onload="addPerms()">
+  <body onload="run()">
   </body>
 </html>
--- a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
@@ -175,21 +175,21 @@
       let browser = win.gBrowser.selectedBrowser;
       ContentTask.spawn(browser, testframes, async function(contentTestFrames) {
         content.document.body.removeChild(
           content.document.getElementById("ifr_bootstrap"));
         for (let test in contentTestFrames) {
           content.document.body.removeChild(
             content.document.getElementById("ifr_" + test));
         }
-      }).then(() => {
+      }).then(async () => {
         currentround = "";
 
         if (!isPrivate) {
-          clean_up_sts_state(isPrivate);
+          await clean_up_sts_state(isPrivate);
         }
         // Close test window.
         win.close();
         // And advance to the next test.
         // Defer this so it doesn't muck with the stack too much.
         SimpleTest.executeSoon(nextTest);
       });
     }
@@ -214,21 +214,21 @@
   function test_sts_after_exiting_private_mode() {
     testOnWindow(false, function(win) {
       SimpleTest.info("In a new public window");
       dump_STSState(false);
       startRound(win, false, "nosts");
     });
   }
 
-  function clean_up_sts_state(isPrivate) {
+  async function clean_up_sts_state(isPrivate) {
     // erase all signs that this test ran.
     SimpleTest.info("Cleaning up STS data");
     let flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
-    SpecialPowers.cleanUpSTSData("http://example.com", flags);
+    await SpecialPowers.cleanUpSTSData("http://example.com", flags);
     dump_STSState(isPrivate);
   }
 
   function dump_STSState(isPrivate) {
     let sss = Cc["@mozilla.org/ssservice;1"]
                 .getService(Ci.nsISiteSecurityService);
     let flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
     SimpleTest.info("State of example.com: " +
--- a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html
+++ b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html
@@ -36,117 +36,117 @@ function starttest(){
   SpecialPowers.addPermission("pREMOVE", ALLOW_ACTION, document);
   SpecialPowers.addPermission("pSESSION", ACCESS_SESSION, document);
 
   setTimeout(test1, 0);
 }
 
 SimpleTest.waitForExplicitFinish();
 
-function test1() {
-  if (!SpecialPowers.testPermission('pALLOW', ALLOW_ACTION, document)) {
+async function test1() {
+  if (!await SpecialPowers.testPermission('pALLOW', ALLOW_ACTION, document)) {
     dump('/**** allow not set ****/\n');
     setTimeout(test1, 0);
-  } else if (!SpecialPowers.testPermission('pDENY', DENY_ACTION, document)) {
+  } else if (!await SpecialPowers.testPermission('pDENY', DENY_ACTION, document)) {
     dump('/**** deny not set ****/\n');
     setTimeout(test1, 0);
-  } else if (!SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document)) {
+  } else if (!await SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document)) {
     dump('/**** prompt not set ****/\n');
     setTimeout(test1, 0);
-  } else if (!SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document)) {
+  } else if (!await SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document)) {
     dump('/**** remove not set ****/\n');
     setTimeout(test1, 0);
-  } else if (!SpecialPowers.testPermission('pSESSION', ACCESS_SESSION, document)) {
+  } else if (!await SpecialPowers.testPermission('pSESSION', ACCESS_SESSION, document)) {
     dump('/**** ACCESS_SESSION not set ****/\n');
     setTimeout(test1, 0);
   } else {
     test2();
   }
 }
 
-function test2() {
-  ok(SpecialPowers.testPermission('pUNKNOWN', UNKNOWN_ACTION, document), 'pUNKNOWN value should have UNKOWN permission');
+async function test2() {
+  ok(await SpecialPowers.testPermission('pUNKNOWN', UNKNOWN_ACTION, document), 'pUNKNOWN value should have UNKOWN permission');
   SpecialPowers.pushPermissions([
     {'type': 'pUNKNOWN', 'allow': true, 'context': document},
     {'type': 'pALLOW', 'allow': false, 'context': document},
     {'type': 'pDENY', 'allow': true, 'context': document},
     {'type': 'pPROMPT', 'allow': true, 'context': document},
     {'type': 'pSESSION', 'allow': true, 'context': document},
     {'type': 'pREMOVE', 'remove': true, 'context': document},
   ], test3);
 }
 
-function test3() {
-  ok(SpecialPowers.testPermission('pUNKNOWN', ALLOW_ACTION, document), 'pUNKNOWN value should have ALLOW permission');
-  ok(SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pPROMPT value should have ALLOW permission');
-  ok(SpecialPowers.testPermission('pALLOW', DENY_ACTION, document), 'pALLOW should have DENY permission');
-  ok(SpecialPowers.testPermission('pDENY', ALLOW_ACTION, document), 'pDENY should have ALLOW permission');
-  ok(SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document), 'pREMOVE should have REMOVE permission');
-  ok(SpecialPowers.testPermission('pSESSION', ALLOW_ACTION, document), 'pSESSION should have ALLOW permission');
+async function test3() {
+  ok(await SpecialPowers.testPermission('pUNKNOWN', ALLOW_ACTION, document), 'pUNKNOWN value should have ALLOW permission');
+  ok(await SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pPROMPT value should have ALLOW permission');
+  ok(await SpecialPowers.testPermission('pALLOW', DENY_ACTION, document), 'pALLOW should have DENY permission');
+  ok(await SpecialPowers.testPermission('pDENY', ALLOW_ACTION, document), 'pDENY should have ALLOW permission');
+  ok(await SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document), 'pREMOVE should have REMOVE permission');
+  ok(await SpecialPowers.testPermission('pSESSION', ALLOW_ACTION, document), 'pSESSION should have ALLOW permission');
 
   // only pPROMPT (last one) is different, the other stuff is just to see if it doesn't cause test failures
   SpecialPowers.pushPermissions([
     {'type': 'pUNKNOWN', 'allow': true, 'context': document},
     {'type': 'pALLOW', 'allow': false, 'context': document},
     {'type': 'pDENY', 'allow': true, 'context': document},
     {'type': 'pPROMPT', 'allow': false, 'context': document},
     {'type': 'pREMOVE', 'remove': true, 'context': document},
   ], test3b);
 }
 
-function test3b() {
-  ok(SpecialPowers.testPermission('pPROMPT', DENY_ACTION, document), 'pPROMPT value should have DENY permission');
+async function test3b() {
+  ok(await SpecialPowers.testPermission('pPROMPT', DENY_ACTION, document), 'pPROMPT value should have DENY permission');
   SpecialPowers.pushPermissions([
     {'type': 'pUNKNOWN', 'allow': DENY_ACTION, 'context': document},
     {'type': 'pALLOW', 'allow': PROMPT_ACTION, 'context': document},
     {'type': 'pDENY', 'allow': PROMPT_ACTION, 'context': document},
     {'type': 'pPROMPT', 'allow': ALLOW_ACTION, 'context': document},
   ], test4);
 }
 
-function test4() {
-  ok(SpecialPowers.testPermission('pUNKNOWN', DENY_ACTION, document), 'pUNKNOWN value should have DENY permission');
-  ok(SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pPROMPT value should have ALLOW permission');
-  ok(SpecialPowers.testPermission('pALLOW', PROMPT_ACTION, document), 'pALLOW should have PROMPT permission');
-  ok(SpecialPowers.testPermission('pDENY', PROMPT_ACTION, document), 'pDENY should have PROMPT permission');
+async function test4() {
+  ok(await SpecialPowers.testPermission('pUNKNOWN', DENY_ACTION, document), 'pUNKNOWN value should have DENY permission');
+  ok(await SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pPROMPT value should have ALLOW permission');
+  ok(await SpecialPowers.testPermission('pALLOW', PROMPT_ACTION, document), 'pALLOW should have PROMPT permission');
+  ok(await SpecialPowers.testPermission('pDENY', PROMPT_ACTION, document), 'pDENY should have PROMPT permission');
   //this should reset all the permissions to before all the pushPermissions calls
   SpecialPowers.flushPermissions(test5);
 }
 
-function test5() {
-  ok(SpecialPowers.testPermission('pUNKNOWN', UNKNOWN_ACTION, document), 'pUNKNOWN should have UNKNOWN permission');
-  ok(SpecialPowers.testPermission('pALLOW', ALLOW_ACTION, document), 'pALLOW should have ALLOW permission');
-  ok(SpecialPowers.testPermission('pDENY', DENY_ACTION, document), 'pDENY should have DENY permission');
-  ok(SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document), 'pPROMPT should have PROMPT permission');
-  ok(SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document), 'pREMOVE should have ALLOW permission');
-  ok(SpecialPowers.testPermission('pSESSION', ACCESS_SESSION, document), 'pSESSION should have ACCESS_SESSION permission');
+async function test5() {
+  ok(await SpecialPowers.testPermission('pUNKNOWN', UNKNOWN_ACTION, document), 'pUNKNOWN should have UNKNOWN permission');
+  ok(await SpecialPowers.testPermission('pALLOW', ALLOW_ACTION, document), 'pALLOW should have ALLOW permission');
+  ok(await SpecialPowers.testPermission('pDENY', DENY_ACTION, document), 'pDENY should have DENY permission');
+  ok(await SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document), 'pPROMPT should have PROMPT permission');
+  ok(await SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document), 'pREMOVE should have ALLOW permission');
+  ok(await SpecialPowers.testPermission('pSESSION', ACCESS_SESSION, document), 'pSESSION should have ACCESS_SESSION permission');
 
   SpecialPowers.removePermission("pPROMPT", document);
   SpecialPowers.removePermission("pALLOW", document);
   SpecialPowers.removePermission("pDENY", document);
   SpecialPowers.removePermission("pREMOVE", document);
   SpecialPowers.removePermission("pSESSION", document);
 
   setTimeout(test6, 0);
 }
 
-function test6() {
-  if (!SpecialPowers.testPermission('pALLOW', UNKNOWN_ACTION, document)) {
+async function test6() {
+  if (!await SpecialPowers.testPermission('pALLOW', UNKNOWN_ACTION, document)) {
     dump('/**** allow still set ****/\n');
     setTimeout(test6, 0);
-  } else if (!SpecialPowers.testPermission('pDENY', UNKNOWN_ACTION, document)) {
+  } else if (!await SpecialPowers.testPermission('pDENY', UNKNOWN_ACTION, document)) {
     dump('/**** deny still set ****/\n');
     setTimeout(test6, 0);
-  } else if (!SpecialPowers.testPermission('pPROMPT', UNKNOWN_ACTION, document)) {
+  } else if (!await SpecialPowers.testPermission('pPROMPT', UNKNOWN_ACTION, document)) {
     dump('/**** prompt still set ****/\n');
     setTimeout(test6, 0);
-  } else if (!SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document)) {
+  } else if (!await SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document)) {
     dump('/**** remove still set ****/\n');
     setTimeout(test6, 0);
-  } else if (!SpecialPowers.testPermission('pSESSION', UNKNOWN_ACTION, document)) {
+  } else if (!await SpecialPowers.testPermission('pSESSION', UNKNOWN_ACTION, document)) {
     dump('/**** pSESSION still set ****/\n');
     setTimeout(test6, 0);
   } else {
     test7();
   }
 }
 
 function test7() {
@@ -181,32 +181,32 @@ function afterPermissionChanged(type, op
   gScript.addMessageListener('perm-changed', function onChange(msg) {
     if (msg.type == type && msg.op == op) {
       gScript.removeMessageListener('perm-changed', onChange);
       callback();
     }
   });
 }
 
-function permissionPollingCheck() {
+async function permissionPollingCheck() {
   var now = Number(Date.now());
   if (now < (start + PERIOD)) {
-    if (SpecialPowers.testPermission('pEXPIRE', ALLOW_ACTION, document)) {
+    if (await SpecialPowers.testPermission('pEXPIRE', ALLOW_ACTION, document)) {
       // To make sure that permission will be expired in next round,
       // the next permissionPollingCheck calling will be fired 100ms later after
       // permission is out-of-period.
       setTimeout(permissionPollingCheck, PERIOD + 100);
       return;
     }
 
     errorHandler('unexpired permission should be allowed!');
   }
 
   // The permission is already expired!
-  if (SpecialPowers.testPermission('pEXPIRE', ALLOW_ACTION, document)) {
+  if (await SpecialPowers.testPermission('pEXPIRE', ALLOW_ACTION, document)) {
     errorHandler('expired permission should be removed!');
   }
 }
 
 function getPlatformInfo() {
   var version = SpecialPowers.Services.sysinfo.getProperty('version');
   version = parseFloat(version);
 
--- a/testing/mochitest/tests/Harness_sanity/test_importInMainProcess.html
+++ b/testing/mochitest/tests/Harness_sanity/test_importInMainProcess.html
@@ -6,49 +6,51 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 
 <div id="content" class="testbody">
   <script type="text/javascript">
     SimpleTest.waitForExplicitFinish();
 
-    var failed = false;
-    try {
-      SpecialPowers.importInMainProcess("invalid file for import");
-    } catch (e) {
-      ok(e.toString().indexOf("NS_ERROR_MALFORMED_URI") > -1, "Exception should be for a malformed URI");
-      failed = true;
-    }
-    ok(failed, "An invalid import should throw");
+    (async () => {
+      var failed = false;
+      try {
+        await SpecialPowers.importInMainProcess("invalid file for import");
+      } catch (e) {
+        ok(e.toString().indexOf("NS_ERROR_MALFORMED_URI") > -1, "Exception should be for a malformed URI");
+        failed = true;
+      }
+      ok(failed, "An invalid import should throw");
+
+      const testingResource = "resource://testing-common/ImportTesting.jsm";
+      var script = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('importtesting_chromescript.js'));
 
-    const testingResource = "resource://testing-common/ImportTesting.jsm";
-    var script = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('importtesting_chromescript.js'));
+      script.addMessageListener("ImportTesting:IsModuleLoadedReply", handleFirstReply);
+      script.sendAsyncMessage("ImportTesting:IsModuleLoaded", testingResource);
 
-    script.addMessageListener("ImportTesting:IsModuleLoadedReply", handleFirstReply);
-    script.sendAsyncMessage("ImportTesting:IsModuleLoaded", testingResource);
+      async function handleFirstReply(aMsg) {
+        ok(!aMsg, "ImportTesting.jsm shouldn't be loaded before we import it");
 
-    function handleFirstReply(aMsg) {
-      ok(!aMsg, "ImportTesting.jsm shouldn't be loaded before we import it");
+        try {
+          await SpecialPowers.importInMainProcess(testingResource);
+        } catch (e) {
+          ok(false, "Unexpected exception when importing a valid resource: " + e.toString());
+        }
 
-      try {
-        SpecialPowers.importInMainProcess(testingResource);
-      } catch (e) {
-        ok(false, "Unexpected exception when importing a valid resource: " + e.toString());
+        script.removeMessageListener("ImportTesting:IsModuleLoadedReply", handleFirstReply);
+        script.addMessageListener("ImportTesting:IsModuleLoadedReply", handleSecondReply);
+        script.sendAsyncMessage("ImportTesting:IsModuleLoaded", testingResource);
       }
 
-      script.removeMessageListener("ImportTesting:IsModuleLoadedReply", handleFirstReply);
-      script.addMessageListener("ImportTesting:IsModuleLoadedReply", handleSecondReply);
-      script.sendAsyncMessage("ImportTesting:IsModuleLoaded", testingResource);
-    }
+      function handleSecondReply(aMsg) {
+        script.removeMessageListener("ImportTesting:IsModuleLoadedReply", handleSecondReply);
 
-    function handleSecondReply(aMsg) {
-      script.removeMessageListener("ImportTesting:IsModuleLoadedReply", handleSecondReply);
+        ok(aMsg, "ImportTesting.jsm should be loaded after we import it");
 
-      ok(aMsg, "ImportTesting.jsm should be loaded after we import it");
-
-      SimpleTest.finish();
-    }
+        SimpleTest.finish();
+      }
+    })();
 
   </script>
 </div>
 </body>
 </html>
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -1148,17 +1148,17 @@ SimpleTest.finish = function() {
 
     SimpleTest._alreadyFinished = true;
 
     if (SimpleTest._inChaosMode) {
         SpecialPowers.DOMWindowUtils.leaveChaosMode();
         SimpleTest._inChaosMode = false;
     }
 
-    var afterCleanup = function() {
+    var afterCleanup = async function() {
         SpecialPowers.removeFiles();
 
         if (SpecialPowers.DOMWindowUtils.isTestControllingRefreshes) {
             SimpleTest.ok(false, "test left refresh driver under test control");
             SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
         }
         if (SimpleTest._expectingUncaughtException) {
             SimpleTest.ok(false, "expectUncaughtException was called but no uncaught exception was detected!");
@@ -1174,17 +1174,17 @@ SimpleTest.finish = function() {
         if (SimpleTest._tests.length == 0) {
             SimpleTest.ok(false, "[SimpleTest.finish()] No checks actually run. "
                                + "(You need to call ok(), is(), or similar "
                                + "functions at least once.  Make sure you use "
                                + "SimpleTest.waitForExplicitFinish() if you need "
                                + "it.)");
         }
 
-        let workers = SpecialPowers.registeredServiceWorkers();
+        let workers = await SpecialPowers.registeredServiceWorkers();
         let promise = null;
         if (SimpleTest._expectingRegisteredServiceWorker) {
             if (workers.length === 0) {
                 SimpleTest.ok(false, "This test is expected to leave a service worker registered");
             }
         } else {
             if (workers.length > 0) {
                 SimpleTest.ok(false, "This test left a service worker registered without cleaning it up");
--- a/testing/mochitest/tests/SimpleTest/TestRunner.js
+++ b/testing/mochitest/tests/SimpleTest/TestRunner.js
@@ -538,30 +538,30 @@ TestRunner.testFinished = function(tests
         // TODO : replace this by a function that returns the mem data as an object
         // that's dumped later with the test_end message
         MemoryStats.dump(TestRunner._currentTest,
                          TestRunner.currentTestURL,
                          TestRunner.dumpOutputDirectory,
                          TestRunner.dumpAboutMemoryAfterTest,
                          TestRunner.dumpDMDAfterTest);
 
-        function cleanUpCrashDumpFiles() {
-            if (!SpecialPowers.removeExpectedCrashDumpFiles(TestRunner._expectingProcessCrash)) {
+        async function cleanUpCrashDumpFiles() {
+            if (!await SpecialPowers.removeExpectedCrashDumpFiles(TestRunner._expectingProcessCrash)) {
                 var subtest = "expected-crash-dump-missing";
                 TestRunner.structuredLogger.testStatus(TestRunner.currentTestURL,
                                                        subtest,
                                                        "ERROR",
                                                        "PASS",
                                                        "This test did not leave any crash dumps behind, but we were expecting some!");
                 extraTests.push({ name: subtest, result: false });
                 result = "ERROR";
             }
 
             var unexpectedCrashDumpFiles =
-                SpecialPowers.findUnexpectedCrashDumpFiles();
+                await SpecialPowers.findUnexpectedCrashDumpFiles();
             TestRunner._expectingProcessCrash = false;
             if (unexpectedCrashDumpFiles.length) {
                 var subtest = "unexpected-crash-dump-found";
                 TestRunner.structuredLogger.testStatus(TestRunner.currentTestURL,
                                                        subtest,
                                                        "ERROR",
                                                        "PASS",
                                                        "This test left crash dumps behind, but we " +
@@ -572,17 +572,17 @@ TestRunner.testFinished = function(tests
                 result = "CRASH";
                 unexpectedCrashDumpFiles.sort().forEach(function(aFilename) {
                     TestRunner.structuredLogger.info("Found unexpected crash dump file " +
                                                      aFilename + ".");
                 });
             }
 
             if (TestRunner.cleanupCrashes) {
-                if (SpecialPowers.removePendingCrashDumpFiles()) {
+                if (await SpecialPowers.removePendingCrashDumpFiles()) {
                     TestRunner.structuredLogger.info("This test left pending crash dumps");
                 }
             }
         }
 
         function runNextTest() {
             if (TestRunner.currentTestURL != TestRunner.getLoadedTestURL()) {
                 TestRunner.structuredLogger.testStatus(TestRunner.currentTestURL,
@@ -635,24 +635,22 @@ TestRunner.testFinished = function(tests
                    TestRunner.structuredLogger.error(TestRunner.currentTestURL + " logged result after SimpleTest.finish(): " + wrongtestname);
                  }
                  TestRunner.updateUI([{ result: false }]);
                }
             });
             TestRunner._makeIframe(interstitialURL, 0);
         }
 
-        SpecialPowers.executeAfterFlushingMessageQueue(function() {
-            SpecialPowers.waitForCrashes(TestRunner._expectingProcessCrash)
-                         .then(() => {
-                cleanUpCrashDumpFiles();
-                SpecialPowers.flushPermissions(function () {
-                    SpecialPowers.flushPrefEnv(runNextTest);
-                });
-            });
+        SpecialPowers.executeAfterFlushingMessageQueue(async function() {
+          await SpecialPowers.waitForCrashes(TestRunner._expectingProcessCrash);
+          await cleanUpCrashDumpFiles();
+          await SpecialPowers.flushPermissions();
+          await SpecialPowers.flushPrefEnv();
+          runNextTest();
         });
     });
 };
 
 TestRunner.testUnloaded = function() {
     // If we're in a debug build, check assertion counts.  This code is
     // similar to the code in Tester_nextTest in browser-test.js used
     // for browser-chrome mochitests.
--- a/testing/specialpowers/content/SpecialPowersAPI.jsm
+++ b/testing/specialpowers/content/SpecialPowersAPI.jsm
@@ -492,33 +492,33 @@ class SpecialPowersAPI {
      we will revert the permission back to the original.
 
      inPermissions is an array of objects where each object has a type, action, context, ex:
      [{'type': 'SystemXHR', 'allow': 1, 'context': document},
       {'type': 'SystemXHR', 'allow': Ci.nsIPermissionManager.PROMPT_ACTION, 'context': document}]
 
      Allow can be a boolean value of true/false or ALLOW_ACTION/DENY_ACTION/PROMPT_ACTION/UNKNOWN_ACTION
   */
-  pushPermissions(inPermissions, callback) {
+  async pushPermissions(inPermissions, callback) {
     inPermissions = Cu.waiveXrays(inPermissions);
     var pendingPermissions = [];
     var cleanupPermissions = [];
 
     for (var p in inPermissions) {
         var permission = inPermissions[p];
         var originalValue = Ci.nsIPermissionManager.UNKNOWN_ACTION;
         var context = Cu.unwaiveXrays(permission.context); // Sometimes |context| is a DOM object on which we expect
                                                            // to be able to access .nodePrincipal, so we need to unwaive.
-        if (this.testPermission(permission.type, Ci.nsIPermissionManager.ALLOW_ACTION, context)) {
+        if (await this.testPermission(permission.type, Ci.nsIPermissionManager.ALLOW_ACTION, context)) {
           originalValue = Ci.nsIPermissionManager.ALLOW_ACTION;
-        } else if (this.testPermission(permission.type, Ci.nsIPermissionManager.DENY_ACTION, context)) {
+        } else if (await this.testPermission(permission.type, Ci.nsIPermissionManager.DENY_ACTION, context)) {
           originalValue = Ci.nsIPermissionManager.DENY_ACTION;
-        } else if (this.testPermission(permission.type, Ci.nsIPermissionManager.PROMPT_ACTION, context)) {
+        } else if (await this.testPermission(permission.type, Ci.nsIPermissionManager.PROMPT_ACTION, context)) {
           originalValue = Ci.nsIPermissionManager.PROMPT_ACTION;
-        } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_SESSION, context)) {
+        } else if (await this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_SESSION, context)) {
           originalValue = Ci.nsICookiePermission.ACCESS_SESSION;
         }
 
         let principal = this._getPrincipalFromArg(context);
         if (principal.isSystemPrincipal) {
           continue;
         }
 
@@ -623,36 +623,42 @@ class SpecialPowersAPI {
 
   permChangedProxy(aMessage) {
     let permission = aMessage.json.permission;
     let aData = aMessage.json.aData;
     this._permissionObserver.observe(permission, aData);
   }
 
   popPermissions(callback) {
-    if (this._permissionsUndoStack.length > 0) {
-      // See pushPermissions comment regarding delay.
-      let cb = callback ? this._delayCallbackTwice(callback) : null;
-      /* Each pop from the stack will yield an object {op/type/permission/value/url/appid/isInIsolatedMozBrowserElement} or null */
-      this._pendingPermissions.push([this._permissionsUndoStack.pop(), cb]);
-      this._applyPermissions();
-    } else {
-      if (this._observingPermissions) {
-        this._observingPermissions = false;
-        this._removeMessageListener("specialpowers-perm-changed", this.permChangedProxy.bind(this));
+    let promise = new Promise(resolve => {
+      if (this._permissionsUndoStack.length > 0) {
+        // See pushPermissions comment regarding delay.
+        let cb = this._delayCallbackTwice(resolve);
+        /* Each pop from the stack will yield an object {op/type/permission/value/url/appid/isInIsolatedMozBrowserElement} or null */
+        this._pendingPermissions.push([this._permissionsUndoStack.pop(), cb]);
+        this._applyPermissions();
+      } else {
+        if (this._observingPermissions) {
+          this._observingPermissions = false;
+          this._removeMessageListener("specialpowers-perm-changed", this.permChangedProxy.bind(this));
+        }
+        this._setTimeout(resolve);
       }
-      this._setTimeout(callback);
+    });
+    if (callback) {
+      promise.then(callback);
     }
+    return promise;
   }
 
   flushPermissions(callback) {
     while (this._permissionsUndoStack.length > 1)
       this.popPermissions(null);
 
-    this.popPermissions(callback);
+    return this.popPermissions(callback);
   }
 
 
   setTestPluginEnabledState(newEnabledState, pluginName) {
     return this._sendSyncMessage("SPSetTestPluginEnabledState",
                                  { newEnabledState, pluginName })[0];
   }
 
--- a/toolkit/components/url-classifier/tests/mochitest/allowlistAnnotatedFrame.html
+++ b/toolkit/components/url-classifier/tests/mochitest/allowlistAnnotatedFrame.html
@@ -12,31 +12,31 @@ var imageItem1 = "untouched";
 var frameItem1 = "untouched";
 var scriptItem2 = "untouched";
 var imageItem2 = "untouched";
 var frameItem2 = "untouched";
 var xhrItem = "untouched";
 var fetchItem = "untouched";
 var mediaItem1 = "untouched";
 
-function checkLoads() {
+async function checkLoads() {
   window.parent.is(scriptItem1, "spoiled", "Should not block tracking js 1");
   window.parent.is(scriptItem2, "spoiled", "Should not block tracking js 2");
   window.parent.is(imageItem1, "spoiled", "Should not block tracking img 1");
   window.parent.is(imageItem2, "spoiled", "Should not block tracking img 2");
   window.parent.is(frameItem1, "spoiled", "Should not block tracking iframe 1");
   window.parent.is(frameItem2, "spoiled", "Should not block tracking iframe 2");
   window.parent.is(mediaItem1, "loaded", "Should not block tracking video");
   window.parent.is(xhrItem, "loaded", "Should not block tracking XHR");
   window.parent.is(fetchItem, "loaded", "Should not block fetches from tracking domains");
   window.parent.is(window.document.blockedNodeByClassifierCount, 0,
     "No elements should be blocked");
 
   // End (parent) test.
-  window.parent.clearPermissions();
+  await window.parent.clearPermissions();
   window.parent.SimpleTest.finish();
 }
 
 var onloadCalled = false;
 var xhrFinished = false;
 var fetchFinished = false;
 var videoLoaded = false;
 function loaded(type) {
--- a/toolkit/components/url-classifier/tests/mochitest/test_allowlisted_annotations.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_allowlisted_annotations.html
@@ -19,22 +19,22 @@ var Ci = SpecialPowers.Ci;
 
 const {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
 
 // Add https://allowlisted.example.com to the permissions manager
 SpecialPowers.addPermission("trackingprotection",
                             Ci.nsIPermissionManager.ALLOW_ACTION,
                             { url: "https://allowlisted.example.com" });
 
-function clearPermissions() {
-  SpecialPowers.removePermission("trackingprotection",
-                                 { url: "https://allowlisted.example.com" });
-  ok(!SpecialPowers.testPermission("trackingprotection",
-                                   Ci.nsIPermissionManager.ALLOW_ACTION,
-                                   { url: "https://allowlisted.example.com" }));
+async function clearPermissions() {
+  await SpecialPowers.removePermission("trackingprotection",
+                                       { url: "https://allowlisted.example.com" });
+  ok(!await SpecialPowers.testPermission("trackingprotection",
+                                         Ci.nsIPermissionManager.ALLOW_ACTION,
+                                         { url: "https://allowlisted.example.com" }));
 }
 
 SpecialPowers.pushPrefEnv(
   {"set": [["urlclassifier.trackingTable", "moztest-track-simple"],
            ["privacy.trackingprotection.enabled", true],
            ["channelclassifier.allowlist_example", true]]},
   test);
 
--- a/toolkit/content/tests/browser/head.js
+++ b/toolkit/content/tests/browser/head.js
@@ -77,29 +77,29 @@ function getTestPlugin(pluginName) {
       return tag;
     }
   }
 
   ok(false, "Could not find plugin tag with plugin name '" + name + "'");
   return null;
 }
 
-function setTestPluginEnabledState(newEnabledState, pluginName) {
-  var oldEnabledState = SpecialPowers.setTestPluginEnabledState(newEnabledState, pluginName);
+async function setTestPluginEnabledState(newEnabledState, pluginName) {
+  var oldEnabledState = await SpecialPowers.setTestPluginEnabledState(newEnabledState, pluginName);
   if (!oldEnabledState) {
     return;
   }
   var plugin = getTestPlugin(pluginName);
   // Run a nested event loop to wait for the preference change to
   // propagate to the child. Yuck!
   SpecialPowers.Services.tm.spinEventLoopUntil(() => {
     return plugin.enabledState == newEnabledState;
   });
   SimpleTest.registerCleanupFunction(function() {
-    SpecialPowers.setTestPluginEnabledState(oldEnabledState, pluginName);
+    return SpecialPowers.setTestPluginEnabledState(oldEnabledState, pluginName);
   });
 }
 
 function disable_non_test_mouse(disable) {
   let utils = window.windowUtils;
   utils.disableNonTestMouseEvents(disable);
 }