Bug 1573254: Part 2 - Update tests to await snapshotWindow when necessary. r=mccr8
authorKris Maglione <maglione.k@gmail.com>
Mon, 12 Aug 2019 12:56:25 -0700
changeset 488077 4b826e607ca87939b656b62836721973c67dac71
parent 488076 c3db0f8fbc5b2ac742da75e8295052d5d9510306
child 488078 f8e99bd2a193f00d159581d9dffeb5cd634ad624
push id36435
push usercbrindusan@mozilla.com
push dateThu, 15 Aug 2019 09:46:49 +0000
treeherdermozilla-central@0db07ff50ab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1573254
milestone70.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 1573254: Part 2 - Update tests to await snapshotWindow when necessary. r=mccr8 This fixes several tests which snapshot remote windows under Fission. It also changes some other arbitrary tests that don't use remote windows, which I changed before I gave up on having an always-async API. Differential Revision: https://phabricator.services.mozilla.com/D41630
docshell/test/chrome/bug113934_window.xul
docshell/test/chrome/bug293235_window.xul
docshell/test/chrome/bug89419_window.xul
docshell/test/mochitest/test_bug598895.html
docshell/test/mochitest/test_bug637644.html
dom/base/test/mochitest.ini
dom/base/test/test_bug1101364.html
dom/base/test/test_bug590812.html
dom/base/test/test_bug682592.html
dom/browser-element/mochitest/browserElement_XFrameOptionsDeny.js
dom/canvas/test/test_bitmaprenderer.html
dom/canvas/test/test_offscreencanvas_dynamic_fallback.html
dom/events/test/test_bug864040.html
dom/html/test/forms/test_input_textarea_set_value_no_scroll.html
dom/html/test/test_bug611189.html
dom/security/test/csp/mochitest.ini
dom/security/test/csp/test_fontloader.html
dom/svg/test/mochitest.ini
dom/svg/test/test_text_dirty.html
dom/svg/test/test_use_with_hsts.html
dom/xul/test/test_bug398289.html
image/test/mochitest/mochitest.ini
image/test/mochitest/test_bug671906.html
layout/svg/tests/mochitest.ini
layout/svg/tests/test_filter_crossorigin.html
widget/tests/window_composition_text_querycontent.xul
--- a/docshell/test/chrome/bug113934_window.xul
+++ b/docshell/test/chrome/bug113934_window.xul
@@ -43,20 +43,20 @@
     "data:text/html,<html><body onbeforeunload='document.documentElement.textContent = \"\"' onunload='document.documentElement.textContent = \"\"' onpagehide='document.documentElement.textContent = \"\"'>This is a test</body></html>";
     var doc2 = "data:text/html,<html><head></head><body>This is a second test</body></html>";
 
 
     $("f1").setAttribute("src", doc1);
     $("f2").setAttribute("src", doc2);
     $("f3").setAttribute("src", doc2);
 
-    function doTheTest() {
-      var s1 = snapshotWindow($("f1").contentWindow);
-      var s2 = snapshotWindow($("f2").contentWindow);
-      var s3 = snapshotWindow($("f3").contentWindow);
+    async function doTheTest() {
+      var s1 = await snapshotWindow($("f1").contentWindow);
+      var s2 = await snapshotWindow($("f2").contentWindow);
+      var s3 = await snapshotWindow($("f3").contentWindow);
 
       // This test is broken - see bug 1090274
       //ok(!compareSnapshots(s2, s3, true)[0],
       //   "Should look different due to different sizing");
 
       function getDOM(id) {
         return $(id).contentDocument.documentElement.innerHTML;
       }
@@ -81,17 +81,17 @@
       // first DOMLinkAdded event (which is a result of the actual addition)
       // is dispatched, the docshells are swapped and the pageshow and pagehide
       // events are tested. Only then, we wait for the DOMLink* events,
       // which are a result of swapping the docshells.
       var DOMLinkListener = {
         _afterFirst: false,
         _removedDispatched: false,
         _addedDispatched: false,
-        handleEvent: function(aEvent) {
+        handleEvent: async function(aEvent) {
           if (!this._afterFirst) {
             is(aEvent.type, "DOMLinkAdded");
 
             var strs = { "f1": "", "f3" : "" };
             function attachListener(node, type) {
               var listener = function(e) {
                 if (strs[node.id]) strs[node.id] += " ";
                 strs[node.id] += node.id + ".page" + type;
@@ -115,17 +115,17 @@
             l1.detach();
             l2.detach();
             l3.detach();
             l4.detach();
 
             // swapDocShells reflows asynchronously, ensure layout is
             // clean so that the viewport of f1 is the right size.
             $("f1").getBoundingClientRect();
-            var s1_new = snapshotWindow($("f1").contentWindow);
+            var s1_new = await snapshotWindow($("f1").contentWindow);
             var [same, first, second] = compareSnapshots(s1_new, s2, true);
             ok(same, "Should reflow on swap. Expected " + second + " but got " + first);
 
             is(strs["f1"], "f1.pagehide f1.pageshow");
             is(strs["f3"], "f3.pagehide f3.pageshow");
             this._afterFirst = true;
             return;
           }
--- a/docshell/test/chrome/bug293235_window.xul
+++ b/docshell/test/chrome/bug293235_window.xul
@@ -1,47 +1,36 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 
 <window id="293235Test"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         width="600"
         height="600"
-        onload="setTimeout(nextTest, 0);"
+        onload="setTimeout(runTests, 0);"
         title="bug 293235 test">
 
   <script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
   <script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
   <script type="application/javascript" src="docshell_helpers.js" />
   <script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
 
   <script type="application/javascript"><![CDATA[
     var {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
 
-    // Define the generator-iterator for the tests.
-    var tests = testIterator();
-
-    ////
-    // Execute the next test in the generator function.
-    //
-    function nextTest() {
-      tests.next();
-    }
-
     // Return the Element object for the specified element id
     function $(id) { return TestWindow.getDocument().getElementById(id); }
 
     ////
     // Generator function for test steps for bug 293235:
     // A visited link should have the :visited style applied
     // to it when displayed on a page which was fetched from
     // the bfcache.
     //
-    function* testIterator()
-    {
+    async function runTests() {
       // Register our observer to know when the link lookup is complete.
       let testURI = NetUtil.newURI(getHttpUrl("bug293235_p2.html"));
       let os = Cc["@mozilla.org/observer-service;1"].
                getService(Ci.nsIObserverService);
       const URI_VISITED_RESOLUTION_TOPIC = "visited-status-resolution";
       let observer = {
         notified: false,
         observe: function(aSubject, aTopic, aData)
@@ -58,94 +47,97 @@
       };
       os.addObserver(observer, URI_VISITED_RESOLUTION_TOPIC);
       function notified() {
         return observer.notified;
       }
 
       // Load a test page containing a link that should be initially
       // blue, per the :link style.
-      doPageNavigation({
-        uri: getHttpUrl("bug293235.html"),
-        onNavComplete: nextTest
+      await new Promise(resolve => {
+        doPageNavigation({
+          uri: getHttpUrl("bug293235.html"),
+          onNavComplete: resolve,
+        });
       });
-      yield undefined;
 
       // Before we go any further, make sure our link has been notified.
-      waitForTrue(notified, nextTest);
-      yield undefined;
+      await new Promise(resolve => {
+        waitForTrue(notified, resolve);
+      });
 
       // Now that we've been notified, we can check our link color.
       // Since we can't use getComputedStyle() for this because
       // getComputedStyle lies about styles that result from :visited,
       // we have to take snapshots.
       // First, take two reference snapshots.
       var link1 = $("link1");
       link1.className = "forcelink";
-      var refLink = snapshotWindow(TestWindow.getWindow());
+      var refLink = await snapshotWindow(TestWindow.getWindow());
       link1.className = "forcevisited";
-      var refVisited = snapshotWindow(TestWindow.getWindow());
+      var refVisited = await snapshotWindow(TestWindow.getWindow());
       link1.className = "";
       function snapshotsEqual(snap1, snap2) {
         return compareSnapshots(snap1, snap2, true)[0];
       }
       ok(!snapshotsEqual(refLink, refVisited), "references should not match");
-      ok(snapshotsEqual(refLink, snapshotWindow(TestWindow.getWindow())),
+      ok(snapshotsEqual(refLink, await snapshotWindow(TestWindow.getWindow())),
          "link should initially be blue");
 
       let observedVisit = false, observedPageShow = false;
-      function maybeRunNextTest() {
-        ok(true, "maybe run next test? visited: " + observedVisit + " pageShow: " + observedPageShow);
-        if (observedVisit && observedPageShow)
-          nextTest();
-      }
+      await new Promise(resolve => {
+        function maybeResolve() {
+          ok(true, "maybe run next test? visited: " + observedVisit + " pageShow: " + observedPageShow);
+          if (observedVisit && observedPageShow)
+            resolve();
+        }
 
-      // Because adding visits is async, we will not be notified imemdiately.
-      let visitObserver = {
-        observe: function(aSubject, aTopic, aData)
-        {
-          if (!testURI.equals(aSubject.QueryInterface(Ci.nsIURI))) {
-            return;
+        // Because adding visits is async, we will not be notified imemdiately.
+        let visitObserver = {
+          observe: function(aSubject, aTopic, aData)
+          {
+            if (!testURI.equals(aSubject.QueryInterface(Ci.nsIURI))) {
+              return;
+            }
+            os.removeObserver(this, aTopic);
+            observedVisit = true;
+            maybeResolve();
+          },
+        };
+        os.addObserver(visitObserver, "uri-visit-saved");
+        // Load the page that the link on the previous page points to.
+        doPageNavigation({
+          uri: getHttpUrl("bug293235_p2.html"),
+          onNavComplete: function() {
+            observedPageShow = true;
+            maybeResolve();
           }
-          os.removeObserver(this, aTopic);
-          observedVisit = true;
-          maybeRunNextTest();
-        },
-      };
-      os.addObserver(visitObserver, "uri-visit-saved");
-      // Load the page that the link on the previous page points to.
-      doPageNavigation({
-        uri: getHttpUrl("bug293235_p2.html"),
-        onNavComplete: function() {
-          observedPageShow = true;
-          maybeRunNextTest();
-        }
-      });
-      yield undefined;
+        });
+      })
 
       // And the nodes get notified after the "uri-visit-saved" topic, so
       // we need to execute soon...
-      SimpleTest.executeSoon(nextTest);
-      yield undefined;
+      await new Promise(SimpleTest.executeSoon);
 
       // Go back, verify the original page was loaded from the bfcache,
       // and verify that the link is now purple, per the
       // :visited style.
-      doPageNavigation({
-        back: true,
-        eventsToListenFor: ["pageshow"],
-        expectedEvents: [ { type: "pageshow",
-                            persisted: true,
-                            title: "Bug 293235 page1" } ],
-        onNavComplete: nextTest
-      });
-      yield undefined;
+      await new Promise(resolve => {
+        doPageNavigation({
+          back: true,
+          eventsToListenFor: ["pageshow"],
+          expectedEvents: [ { type: "pageshow",
+                              persisted: true,
+                              title: "Bug 293235 page1" } ],
+          onNavComplete: resolve,
+        });
+      })
 
       // Now we can test the link color.
-      ok(snapshotsEqual(refVisited, snapshotWindow(TestWindow.getWindow())),
+      ok(snapshotsEqual(refVisited, await snapshotWindow(TestWindow.getWindow())),
          "visited link should be purple");
 
       // Tell the framework the test is finished.
       finish();
     }
 
   ]]></script>
 
--- a/docshell/test/chrome/bug89419_window.xul
+++ b/docshell/test/chrome/bug89419_window.xul
@@ -9,69 +9,59 @@
         title="bug 89419 test">
 
   <script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
   <script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
   <script type="application/javascript" src="docshell_helpers.js" />
   <script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
 
   <script type="application/javascript"><![CDATA[
-    // Define the generator-iterator for the tests.
-    var tests = testIterator();
-
     ////
-    // Execute the next test in the generator function.
-    //
-    function nextTest() {
-      tests.next();
-    }
-
-    ////
-    // Generator function for test steps for bug 89419:
     // A visited link should have the :visited style applied
     // to it when displayed on a page which was fetched from
     // the bfcache.
     //
-    function* testIterator()
-    {
+    async function runTests() {
       // Disable rcwn to make cache behavior deterministic.
-      var SpecialPowers = window.opener.wrappedJSObject.SpecialPowers;
-      SpecialPowers.pushPrefEnv({"set":[["network.http.rcwn.enabled", false]]}, nextTest);
-      yield undefined;
+      var {SpecialPowers} = opener;
+      await SpecialPowers.pushPrefEnv({"set":[["network.http.rcwn.enabled", false]]});
 
       // Load a test page containing an image referring to the sjs that returns
       // a different redirect every time it's loaded.
-      doPageNavigation({
-        uri: getHttpUrl("89419.html"),
-        onNavComplete: nextTest,
-        preventBFCache: true
-      });
-      yield undefined;
+      await new Promise(resolve => {
+        doPageNavigation({
+          uri: getHttpUrl("89419.html"),
+          onNavComplete: resolve,
+          preventBFCache: true,
+        });
+      })
 
-      var first = snapshotWindow(TestWindow.getWindow());
+      var first = await snapshotWindow(TestWindow.getWindow());
 
-      doPageNavigation({
-        uri: "about:blank",
-        onNavComplete: nextTest
+      await new Promise(resolve => {
+        doPageNavigation({
+          uri: "about:blank",
+          onNavComplete: resolve,
+        });
       });
-      yield undefined;
 
-      var second = snapshotWindow(TestWindow.getWindow());
+      var second = await snapshotWindow(TestWindow.getWindow());
       function snapshotsEqual(snap1, snap2) {
         return compareSnapshots(snap1, snap2, true)[0];
       }
       ok(!snapshotsEqual(first, second), "about:blank should not be the same as the image web page");
 
-      doPageNavigation({
-        back: true,
-        onNavComplete: nextTest
+      await new Promise(resolve => {
+        doPageNavigation({
+          back: true,
+          onNavComplete: resolve,
+        });
       });
-      yield undefined;
 
-      var third = snapshotWindow(TestWindow.getWindow());
+      var third = await snapshotWindow(TestWindow.getWindow());
       ok(!snapshotsEqual(third, second), "going back should not be the same as about:blank");
       ok(snapshotsEqual(first, third), "going back should be the same as the initial load");
 
       // Tell the framework the test is finished.
       finish();
     }
 
   ]]></script>
--- a/docshell/test/mochitest/test_bug598895.html
+++ b/docshell/test/mochitest/test_bug598895.html
@@ -22,22 +22,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(function() {
 var win1 = window.open();
 win1.document.body.textContent = "Should show";
 
 var windowsLoaded = 0;
 
-window.onmessage = function(ev) {
+window.onmessage = async function(ev) {
   is(ev.data, "loaded", "Message should be 'loaded'");
   if (++windowsLoaded == 2) {
-    var one = snapshotWindow(win1);
-    var two = snapshotWindow(win2);
-    var three = snapshotWindow(win3);
+    var one = await snapshotWindow(win1);
+    var two = await snapshotWindow(win2);
+    var three = await snapshotWindow(win3);
     win1.close();
     win2.close();
     win3.close();
     ok(compareSnapshots(one, two, true)[0], "Popups should look identical");
     ok(compareSnapshots(one, three, false)[0], "Popups should not look identical");
 
     SimpleTest.finish();
   }
--- a/docshell/test/mochitest/test_bug637644.html
+++ b/docshell/test/mochitest/test_bug637644.html
@@ -22,22 +22,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(function() {
 var win1 = window.open("", "", "height=500,width=500");
 win1.document.body.textContent = "Should show";
 
 var windowsLoaded = 0;
 
-window.onmessage = function(ev) {
+window.onmessage = async function(ev) {
   is(ev.data, "loaded", "Message should be 'loaded'");
   if (++windowsLoaded == 2) {
-    var one = snapshotWindow(win1);
-    var two = snapshotWindow(win2);
-    var three = snapshotWindow(win3);
+    var one = await snapshotWindow(win1);
+    var two = await snapshotWindow(win2);
+    var three = await snapshotWindow(win3);
     win1.close();
     win2.close();
     win3.close();
     ok(compareSnapshots(one, two, true)[0], "Popups should look identical");
     ok(compareSnapshots(one, three, false)[0], "Popups should not look identical");
 
     SimpleTest.finish();
   }
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -484,17 +484,16 @@ skip-if = (os == "android") # Failure wi
 [test_bug574596.html]
 skip-if = toolkit == 'android'
 [test_bug578096.html]
 skip-if = (verify && (os == 'win'))
 [test_bug585978.html]
 [test_bug587931.html]
 [test_bug588990.html]
 [test_bug590812.html]
-fail-if = fission
 skip-if = toolkit == 'android' || (verify && !debug && (os == 'linux')) #bug 687032
 [test_bug590870.html]
 skip-if = fission # Crashes: @ mozilla::dom::ContentParent::RecvDetachBrowsingContext(unsigned long, std::function<void (bool const&)>&&)
 [test_bug592366.html]
 [test_bug592829.html]
 [test_bug597345.html]
 [test_bug599295.html]
 [test_bug599588.html]
--- a/dom/base/test/test_bug1101364.html
+++ b/dom/base/test/test_bug1101364.html
@@ -21,46 +21,46 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body id='body'>
 
 <iframe id="test1" srcdoc="<h1 id='test1' style='-moz-user-select:none'>Header</h1><div id='testDiv'>test1</div>"></iframe>
 <iframe id="test2" srcdoc="<div contenteditable id='test2'>AAA<span id='test2Inner'>BBB</span></div>"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-function test()
+async function test()
 {
   var iframe1 = document.getElementById('test1');
   iframe1.focus();
   var docShell = SpecialPowers.wrap(iframe1.contentWindow).docShell;
 
   // test1
   docShell.doCommand("cmd_selectAll");
-  var withoutContenteditable = snapshotWindow(iframe1.contentWindow);
+  var withoutContenteditable = await snapshotWindow(iframe1.contentWindow);
 
   iframe1.contentDocument.getElementById('testDiv').setAttribute('contentEditable', true);
   docShell.doCommand("cmd_selectAll");
-  var withContenteditable = snapshotWindow(iframe1.contentWindow);
+  var withContenteditable = await snapshotWindow(iframe1.contentWindow);
   dump(withoutContenteditable.toDataURL());
   dump(withContenteditable.toDataURL());
 
   ok(compareSnapshots(withoutContenteditable, withContenteditable, true)[0], 'Select all should look identical');
 
   // test2
   var iframe2 = document.getElementById('test2');
   iframe2.focus();
   var docShell = SpecialPowers.wrap(iframe2.contentWindow).docShell;
   var test2Inner = iframe2.contentDocument.getElementById('test2Inner');
   test2Inner.style.MozUserSelect = 'text';
   docShell.doCommand("cmd_selectAll");
-  var withoutUserSelect = snapshotWindow(iframe2.contentWindow);
+  var withoutUserSelect = await snapshotWindow(iframe2.contentWindow);
 
   test2Inner.style.MozUserSelect = 'none';
   docShell.doCommand("cmd_selectAll");
-  var withUserSelect = snapshotWindow(iframe2.contentWindow);
+  var withUserSelect = await snapshotWindow(iframe2.contentWindow);
   ok(compareSnapshots(withoutUserSelect, withUserSelect, true)[0], 'Editable fields should ignore user select style');
 
   SimpleTest.finish();
 }
 window.onload = function() { setTimeout(test, 0); };
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
--- a/dom/base/test/test_bug590812.html
+++ b/dom/base/test/test_bug590812.html
@@ -21,19 +21,19 @@ async function runTest() {
   // FIXME(Fission): The load event fires before cross-origin iframes have
   // loaded (bug 1559841).
   if (SpecialPowers.useRemoteSubframes) {
     for (let i = 0; i < 100; i++) {
       await new Promise(resolve => setTimeout(resolve, 0));
     }
   }
 
-  sNoXUL = snapshotWindow(window.frames[0], false);
-  sWithXUL = snapshotWindow(window.frames[1], false);
-  sRef = snapshotWindow(window.frames[2], false);
+  let sNoXUL = await snapshotWindow(window.frames[0], false);
+  let sWithXUL = await snapshotWindow(window.frames[1], false);
+  let sRef = await snapshotWindow(window.frames[2], false);
   let res;
   ok(compareSnapshots(sNoXUL, sRef, true)[0],
      "noxul domain same as ref");
   ok(compareSnapshots(sWithXUL, sRef, true)[0],
      "xul supporting domain same as ref");
 
   SimpleTest.finish();
 }
--- a/dom/base/test/test_bug682592.html
+++ b/dom/base/test/test_bug682592.html
@@ -45,21 +45,21 @@ if (navigator.platform.startsWith("Linux
 }
 
 var page = `<!DOCTYPE html>
 <html><meta charset='UTF-8'><body><p id="content"></p></body></html>`;
 var refFrame = document.getElementById("iframe-ref")
 var testFrame = document.getElementById("iframe-test");
 
 refFrame.addEventListener("load", function() {
-  testFrame.addEventListener("load", function() {
+  testFrame.addEventListener("load", async function() {
     let {done} = tests.next();
     if (!done) {
-      ok(compareSnapshots(snapshotWindow(testFrame.contentWindow), 
-                          snapshotWindow(refFrame.contentWindow), true)[0], 
+      ok(compareSnapshots(await snapshotWindow(testFrame.contentWindow), 
+                          await snapshotWindow(refFrame.contentWindow), true)[0], 
          "bidi is not detected correctly");
 
       testFrame.contentWindow.location.reload();
     } else {
       SimpleTest.finish();
     }
   });
   testFrame.srcdoc = page;
--- a/dom/browser-element/mochitest/browserElement_XFrameOptionsDeny.js
+++ b/dom/browser-element/mochitest/browserElement_XFrameOptionsDeny.js
@@ -34,25 +34,25 @@ function runTest() {
   iframe.setAttribute("mozbrowser", "true");
 
   // Our child will create two iframes, so make sure this iframe is big enough
   // to show both of them without scrolling, so taking a screenshot gets both
   // frames.
   iframe.height = "1000px";
 
   var step1, stepfinish;
-  iframe.addEventListener("mozbrowsershowmodalprompt", function(e) {
+  iframe.addEventListener("mozbrowsershowmodalprompt", async function(e) {
     switch (e.detail.message) {
       case "step 1":
-        step1 = SpecialPowers.snapshotWindow(iframe.contentWindow);
+        step1 = await SpecialPowers.snapshotWindow(iframe.contentWindow);
         break;
       case "step 2":
         // The page has now attempted to load the X-Frame-Options page; take
         // another screenshot.
-        stepfinish = SpecialPowers.snapshotWindow(iframe.contentWindow);
+        stepfinish = await SpecialPowers.snapshotWindow(iframe.contentWindow);
         ok(
           step1.toDataURL() == stepfinish.toDataURL(),
           "Screenshots should be identical"
         );
         SimpleTest.finish();
         break;
     }
   });
--- a/dom/canvas/test/test_bitmaprenderer.html
+++ b/dom/canvas/test/test_bitmaprenderer.html
@@ -47,33 +47,33 @@ function runTest(canvasWidth, canvasHeig
   var ctx = canvasRef.getContext("2d");
   // Clear with black transparent first
   ctx.fillStyle = "rgba(0, 0, 0, 0)";
   ctx.fillRect(0, 0, 90, 90);
 
   ctx.fillStyle = "#00FF00";
   ctx.fillRect(0, 0, canvasWidth, canvasHeight);
 
-  createImageBitmap(canvas1).then(function(bmp) {
+  createImageBitmap(canvas1).then(async function(bmp) {
     document.body.removeChild(canvas1);
 
     var canvas2 = createCanvas(90, 90);
     var ctx2 = canvas2.getContext("bitmaprenderer");
     ctx2.transferFromImageBitmap(bmp);
 
     ok(canvasRef.toDataURL() == canvas2.toDataURL(), "toDataURL should return same result.");
 
     // Exam render result
     canvasRef.style.display = "none";
     canvas2.style.display = "block";
-    var snapshot = snapshotWindow(window);
+    var snapshot = await snapshotWindow(window);
 
     canvasRef.style.display = "block";
     canvas2.style.display = "none";
-    var snapshotRef = snapshotWindow(window);
+    var snapshotRef = await snapshotWindow(window);
 
     // bitmaprenderers use an ImageLayer whereas a normal 2d canvas uses a canvas layer. This
     // can result in some anti-aliasing differences on the edge. We consider slight AA differences
     // to be reasonable when using different codepaths so fuzz a little bit.
     var fuzz = { numDifferentPixels:  0,
                  maxDifference: 0 };
     if (SpecialPowers.Services.appinfo.widgetToolkit == "android") {
       fuzz.maxDifference = 2;
@@ -97,40 +97,40 @@ function scaleTest() {
 
   var canvas2 = createCanvas(64, 64);
   var ctx2 = canvas2.getContext("2d");
   ctx2.fillStyle = "#00FF00";
   ctx2.fillRect(0, 0, 64, 64);
 
   var p1 = createImageBitmap(canvas1);
   var p2 = createImageBitmap(canvas2);
-  Promise.all([p1, p2]).then(function(bitmaps) {
+  Promise.all([p1, p2]).then(async function(bitmaps) {
     document.body.removeChild(canvas1);
     document.body.removeChild(canvas2);
 
     // Create a large canvas then shrink.
     var canvas3 = createCanvas(128, 128);
     var ctx3 = canvas3.getContext("bitmaprenderer");
     ctx3.transferFromImageBitmap(bitmaps[0]);
-    var snapshotLargeRef = snapshotWindow(window);
+    var snapshotLargeRef = await snapshotWindow(window);
 
     canvas3.width = 32;
     canvas3.height = 32;
-    var snapshotSmall = snapshotWindow(window);
+    var snapshotSmall = await snapshotWindow(window);
     document.body.removeChild(canvas3);
 
     // Create a small canvas then grow.
     var canvas4 = createCanvas(32, 32);
     var ctx4 = canvas4.getContext("bitmaprenderer");
     ctx4.transferFromImageBitmap(bitmaps[1]);
-    var snapshotSmallRef = snapshotWindow(window);
+    var snapshotSmallRef = await snapshotWindow(window);
 
     canvas4.width = 128;
     canvas4.height = 128;
-    var snapshotLarge = snapshotWindow(window);
+    var snapshotLarge = await snapshotWindow(window);
     document.body.removeChild(canvas4);
 
     var resultsLarge = compareSnapshots(snapshotLarge, snapshotLargeRef, true);
     ok(resultsLarge[0], "Screenshots should be the same");
 
     var resultsSmall = compareSnapshots(snapshotSmall, snapshotSmallRef, true);
     ok(resultsSmall[0], "Screenshots should be the same");
     runTestOnWorker();
--- a/dom/canvas/test/test_offscreencanvas_dynamic_fallback.html
+++ b/dom/canvas/test/test_offscreencanvas_dynamic_fallback.html
@@ -18,47 +18,47 @@ function createCanvas(initWithMask) {
   document.body.appendChild(canvas);
   if (initWithMask) {
     canvas.style.mask = "url('offscreencanvas_mask.svg#fade_mask_both')";
   }
 
   return canvas;
 }
 
-function getRefSnapshot(initWithMask) {
+async function getRefSnapshot(initWithMask) {
   var refCanvas = createCanvas(!initWithMask);
   var ctx = refCanvas.getContext("2d");
   ctx.rect(0, 0, 64, 64);
   ctx.fillStyle = "#00FF00";
   ctx.fill();
-  var result = snapshotWindow(window);
+  var result = await snapshotWindow(window);
   document.body.removeChild(refCanvas);
   return result;
 }
 
 function runTest(initWithMask) {
   var htmlCanvas = createCanvas(initWithMask);
   var worker = new Worker("offscreencanvas.js");
 
-  worker.onmessage = function(evt) {
+  worker.onmessage = async function(evt) {
     var msg = evt.data || {};
     if (msg.type == "draw") {
       if (msg.count === 10) {
         // Change the fallback state dynamically when drawing count reaches 10.
         if (initWithMask) {
           htmlCanvas.style.mask = "";
         } else {
           htmlCanvas.style.mask = "url('offscreencanvas_mask.svg#fade_mask_both')";
         }
       } else if (msg.count === 20) {
-        var snapshotFallback = snapshotWindow(window);
         worker.terminate();
+        var snapshotFallback = await snapshotWindow(window);
         document.body.removeChild(htmlCanvas);
 
-        var results = compareSnapshots(snapshotFallback, getRefSnapshot(initWithMask), true);
+        var results = compareSnapshots(snapshotFallback, await getRefSnapshot(initWithMask), true);
         ok(results[0], "after dynamic fallback, screenshots should be the same");
 
         if (initWithMask) {
           SimpleTest.finish();
         } else {
           runTest(true);
         }
       }
--- a/dom/events/test/test_bug864040.html
+++ b/dom/events/test/test_bug864040.html
@@ -24,62 +24,62 @@ https://bugzilla.mozilla.org/show_bug.cg
     /**
     * Test for Bug 864040
     *
     * We use a selection event to set the selection to the end of an editor
     * containing an ending newline. Then we test to see that the caret is
     * actually drawn on the newline.
     */
 
-    function testSelectEndOfText(elem) {
+    async function testSelectEndOfText(elem) {
       var tn = elem.tagName;
       elem.focus();
 
       // Enter test string into editor
       var test_string = 'test\n';
       sendString(test_string);
 
       // Get the caret position after what we entered
       var result = synthesizeQuerySelectedText();
       ok(result, tn + ': failed to query selection (1)');
       var refoffset = result.offset;
 
       // Take a snapshot of where the caret is (on the new line)
-      referenceSnapshot = snapshotWindow(window, true /* withCaret */);
+      referenceSnapshot = await snapshotWindow(window, true /* withCaret */);
       ok(referenceSnapshot, tn + ': failed to take snapshot (1)');
 
       // Set selection to the same spot through a selection event
       ok(synthesizeSelectionSet(refoffset, 0, false), tn + ': failed to set selection');
 
       // Make sure new selection is the same
       result = synthesizeQuerySelectedText();
       ok(result, tn + ': failed to query selection (2)');
       is(result.offset, refoffset, tn + ': caret is not at the right position');
 
       // Take a snapshot of where the new caret is (shoud still be on the new line)
-      testSnapshot = snapshotWindow(window, true /* withCaret */);
+      testSnapshot = await snapshotWindow(window, true /* withCaret */);
       ok(testSnapshot, tn + ': failed to take snapshot (2)');
 
       // Compare snapshot (should be the same)
       result = compareSnapshots(referenceSnapshot, testSnapshot, true /* expected */)
       ok(result, tn + ': failed to compare snapshots');
       // result = [correct, s1data, s2data]
       ok(result[0], tn + ': caret is not on new line');
       if (!result[0]) {
         dump('Ref: ' + result[1] + '\n');
         dump('Res: ' + result[2] + '\n');
       }
     }
 
-    function runTests() {
+    async function runTests() {
       // we don't test regular <input> because this test is about multiline support
       // test textarea
-      testSelectEndOfText(document.getElementById('ta'));
+      await testSelectEndOfText(document.getElementById('ta'));
       // test contentEditable
-      testSelectEndOfText(document.getElementById('ce'));
+      await testSelectEndOfText(document.getElementById('ce'));
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
 
     SimpleTest.waitForFocus(runTests);
   </script>
 </pre>
--- a/dom/html/test/forms/test_input_textarea_set_value_no_scroll.html
+++ b/dom/html/test/forms/test_input_textarea_set_value_no_scroll.html
@@ -17,40 +17,40 @@ https://bugzilla.mozilla.org/show_bug.cg
    * This test checks that setting .value on an text field (input or textarea)
    * doesn't scroll the field to its beginning.
    */
 
   SimpleTest.waitForExplicitFinish();
 
   var gTestRunner = null;
 
-  function test(aElementName)
+  async function test(aElementName)
   {
     var element = document.getElementsByTagName(aElementName)[0];
     element.focus();
 
-    var baseSnapshot = snapshotWindow(window);
+    var baseSnapshot = await snapshotWindow(window);
 
     // This is a sanity check.
-    var s2 = snapshotWindow(window);
-    var results = compareSnapshots(baseSnapshot, snapshotWindow(window), true);
+    var s2 = await snapshotWindow(window);
+    var results = compareSnapshots(baseSnapshot, await snapshotWindow(window), true);
     ok(results[0], "sanity check: screenshots should be the same");
 
     element.selectionStart = element.selectionEnd = element.value.length;
 
     setTimeout(function() {
       sendString('f');
 
-      requestAnimationFrame(function() {
-        var selectionAtTheEndSnapshot = snapshotWindow(window);
+      requestAnimationFrame(async function() {
+        var selectionAtTheEndSnapshot = await snapshotWindow(window);
         results = compareSnapshots(baseSnapshot, selectionAtTheEndSnapshot, false);
         ok(results[0], "after appending a character, string should have changed");
 
         element.value = element.value;
-        var tmpSnapshot = snapshotWindow(window);
+        var tmpSnapshot = await snapshotWindow(window);
 
         results = compareSnapshots(baseSnapshot, tmpSnapshot, false);
         ok(results[0], "re-settig the value should change nothing");
 
         results = compareSnapshots(selectionAtTheEndSnapshot, tmpSnapshot, true);
         ok(results[0], "re-settig the value should change nothing");
 
         element.selectionStart = element.selectionEnd = 0;
@@ -58,36 +58,36 @@ https://bugzilla.mozilla.org/show_bug.cg
 
         gTestRunner.next();
       });
     }, 0);
   }
 
   // This test checks that when a textarea has a long list of values and the
   // textarea's value is then changed, the values are shown correctly.
-  function testCorrectUpdateOnScroll()
+  async function testCorrectUpdateOnScroll()
   {
     var textarea = document.createElement('textarea');
     textarea.rows = 5;
     textarea.cols = 10;
     textarea.value = 'a\nb\nc\nd';
     document.getElementById('content').appendChild(textarea);
 
-    var baseSnapshot = snapshotWindow(window);
+    var baseSnapshot = await snapshotWindow(window);
 
     textarea.value = '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n';
     textarea.selectionStart = textarea.selectionEnd = textarea.value.length;
 
-    var fullSnapshot = snapshotWindow(window);
+    var fullSnapshot = await snapshotWindow(window);
     var results = compareSnapshots(baseSnapshot, fullSnapshot, false);
     ok(results[0], "sanity check: screenshots should not be the same");
 
     textarea.value = 'a\nb\nc\nd';
 
-    var tmpSnapshot = snapshotWindow(window);
+    var tmpSnapshot = await snapshotWindow(window);
     results = compareSnapshots(baseSnapshot, tmpSnapshot, true);
     ok(results[0], "textarea view should look like the beginning");
 
     setTimeout(function() {
       gTestRunner.next();
     }, 0);
   }
 
--- a/dom/html/test/test_bug611189.html
+++ b/dom/html/test/test_bug611189.html
@@ -15,31 +15,31 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 611189 **/
 SimpleTest.waitForExplicitFinish();
-addLoadEvent(function() {
+addLoadEvent(async function() {
   var i = document.createElement("input");
   var b = document.getElementById("content");
   b.appendChild(i);
   b.clientWidth; // bind to frame
   i.focus(); // initialize editor
-  var before = snapshotWindow(window, true);
+  var before = await snapshotWindow(window, true);
   i.value = "L"; // set the value
   i.style.display = "none";
   b.clientWidth; // unbind from frame
   i.value = ""; // set the value without a frame
   i.style.display = "";
   b.clientWidth; // rebind to frame
   is(i.value, "", "Input's value should be correctly updated");
-  var after = snapshotWindow(window, true);
+  var after = await snapshotWindow(window, true);
   ok(compareSnapshots(before, after, true), "The correct value should be rendered inside the control");
   SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -304,17 +304,16 @@ skip-if = toolkit == 'android'
 [test_child-src_worker_data.html]
 [test_child-src_worker-redirect.html]
 [test_child-src_iframe.html]
 [test_meta_element.html]
 [test_meta_header_dual.html]
 [test_docwrite_meta.html]
 [test_multipartchannel.html]
 [test_fontloader.html]
-fail-if = fission
 [test_block_all_mixed_content.html]
 tags = mcb
 [test_block_all_mixed_content_frame_navigation.html]
 tags = mcb
 [test_form_action_blocks_url.html]
 [test_meta_whitespace_skipping.html]
 [test_iframe_sandbox.html]
 [test_iframe_sandbox_top_1.html]
--- a/dom/security/test/csp/test_fontloader.html
+++ b/dom/security/test/csp/test_fontloader.html
@@ -52,21 +52,21 @@ const tests = [
   }
 ];
 
 var curTest;
 var counter = -1;
 var baselineframe = document.getElementById("baselineframe");
 var testframe = document.getElementById("testframe");
 
-function checkResult() {
+async function checkResult() {
   testframe.removeEventListener('load', checkResult);
   try {
-    ok(compareSnapshots(snapshotWindow(baselineframe.contentWindow),
-                        snapshotWindow(testframe.contentWindow),
+    ok(compareSnapshots(await snapshotWindow(baselineframe.contentWindow),
+                        await snapshotWindow(testframe.contentWindow),
                         curTest.expected)[0],
                         curTest.description);
   } catch(err) {
     ok(false, "error: " + err.message);
   }
   loadNextTest();
 }
 
--- a/dom/svg/test/mochitest.ini
+++ b/dom/svg/test/mochitest.ini
@@ -96,15 +96,14 @@ support-files = tearoff_with_cc_helper.h
 [test_text.html]
 [test_text_lengthAdjust.html]
 [test_text_scaled.html]
 [test_text_selection.html]
 [test_text_update.html]
 [test_transform.xhtml]
 [test_transformParsing.html]
 [test_use_with_hsts.html]
-skip-if = fission
 support-files = use-with-hsts-helper.html use-with-hsts-helper.html^headers^
 [test_valueAsString.xhtml]
 [test_valueLeaks.xhtml]
 [test_viewBox.html]
 [test_viewport.html]
 
--- a/dom/svg/test/test_text_dirty.html
+++ b/dom/svg/test/test_text_dirty.html
@@ -18,26 +18,26 @@ https://bugzilla.mozilla.org/show_bug.cg
     <mask id="m"><text id="t">x</text></mask>
     <rect width="600" height="400" mask="url(#m)"/>
   </svg>
 </p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-function runTest() {
+async function runTest() {
   var svgText = document.getElementById("t");
 
   // Dirty the frames.
   document.getElementById("display").style.width = "700px";
   svgText.firstChild.remove();
 
   // Paint without flushing layout.  If the test fails, we'll trigger
   // an assertion.
-  SpecialPowers.snapshotWindowWithOptions(window, undefined, undefined, { DRAWWINDOW_DO_NOT_FLUSH: true });
+  await SpecialPowers.snapshotWindowWithOptions(window, undefined, undefined, { DRAWWINDOW_DO_NOT_FLUSH: true });
 
   ok(true);
   SimpleTest.finish();
 }
 
 window.addEventListener("load", runTest);
 
 SimpleTest.waitForExplicitFinish();
--- a/dom/svg/test/test_use_with_hsts.html
+++ b/dom/svg/test/test_use_with_hsts.html
@@ -68,52 +68,52 @@ https://bugzilla.mozilla.org/show_bug.cg
     });
   }
 
   // MAIN TEST CODE BEGINS HERE.
   async function runTest() {
     // Capture a snapshot with nothing in the iframe, so we can do a
     // sanity-check not-equal comparison against our reference case, to be
     // sure we're rendering anything at all:
-    let blankSnapshot = snapshotWindow(iframeWin);
+    let blankSnapshot = await snapshotWindow(iframeWin);
 
     // Load & snapshot a reference case (fully lime):
     await LoadIframeAsync("data:text/html,<body style='background:lime'>");
-    let refSnapshot = snapshotWindow(iframeWin);
+    let refSnapshot = await snapshotWindow(iframeWin);
 
     // Ensure reference snapshot looks different from blank snapshot:
     assertSnapshots(refSnapshot, blankSnapshot,
                     false /* not equal*/, null /* no fuzz*/,
                     "refSnapshot", "blankSnapshot");
 
     // OK, assuming we've got a valid refSnapshot, we can now proceed to
     // capture test screenshots.
 
     // Register a postMessage handler, so that iframe can report its location:
     window.addEventListener("message", receiveMessage);
 
     // Load & snapshot secure (HTTPS) version of testcase, & check against ref:
     await LoadIframeAsync(secureURI);
-    let secureSnapshot = snapshotWindow(iframeWin);
+    let secureSnapshot = await snapshotWindow(iframeWin);
     assertSnapshots(secureSnapshot, refSnapshot,
                     true /* equal*/, null /* no fuzz*/,
                     "secureSnapshot", "refSnapshot");
 
     // Load insecure (HTTP) version of testcase (which should get
     // automatically upgraded to secure (HTTPS) under the hood):
     await LoadIframeAsync(insecureURI);
 
     // Double-check that iframe is really pointed at insecure URI, to be sure
     // we're actually exercising HSTS. (Note that receiveMessage() will make
     // sure it's been upgraded to a secure HTTPS URI under the hood.)
     is(iframe.src, insecureURI,
        "test should've attempted to load insecure HTTP URI, to exercise HSTS");
 
     // Capture snapshot of iframe showing upgraded-to-HTTPS version of testcase:
-    let upgradedSnapshot = snapshotWindow(iframeWin);
+    let upgradedSnapshot = await snapshotWindow(iframeWin);
     assertSnapshots(upgradedSnapshot, refSnapshot,
                     true /* equal*/, null /* no fuzz*/,
                     "upgradedSnapshot", "refSnapshot");
 
     // Check that the iframe did actually invoke our postMessage handler (which
     // is where we verify that the HSTS upgrade actually happened):
     is(numPostMessageCalls, expectedNumPostMessageCalls,
       "didn't receive as many messages from child iframe as expected");
--- a/dom/xul/test/test_bug398289.html
+++ b/dom/xul/test/test_bug398289.html
@@ -10,28 +10,28 @@
   <iframe id="test" src="398289-resource.xul" width="100%" height="100%">
   </iframe>
 
   <script class="testbody" type="text/javascript">
     var snap1, snap2;
   
     SimpleTest.waitForExplicitFinish();
   
-    function onBodyLoad() {
+    async function onBodyLoad() {
       window.frames[0].document.getElementById("test").selectedIndex = 0;
       window.frames[0].document.getElementById("test").selectedIndex = 1;
       
-      snap1 = snapshotWindow(window);
+      snap1 = await snapshotWindow(window);
       
       document.getElementById("test").onload = onFrameLoad;
       window.frames[0].location.reload();
     }
     
-    function onFrameLoad() {
-      snap2 = snapshotWindow(window);
+    async function onFrameLoad() {
+      snap2 = await snapshotWindow(window);
 
       var equal, str1, str2;
       [equal, str1, str2] = compareSnapshots(snap1, snap2, true);
 
       ok(equal, "persistent attribute in tab box broken, expected: "+str1+" got: "+str2);
           
       SimpleTest.finish();
     }
--- a/image/test/mochitest/mochitest.ini
+++ b/image/test/mochitest/mochitest.ini
@@ -118,17 +118,16 @@ skip-if = verify
 [test_bug497665.html]
 [test_bug552605-1.html]
 [test_bug552605-2.html]
 [test_bug553982.html]
 [test_bug601470.html]
 [test_bug614392.html]
 [test_bug657191.html]
 [test_bug671906.html]
-fail-if = fission
 [test_bug733553.html]
 skip-if = verify
 [test_bug767779.html]
 [test_bug865919.html]
 [test_bug89419-1.html]
 [test_bug89419-2.html]
 [test_bug1132427.html]
 skip-if = os == 'android'
--- a/image/test/mochitest/test_bug671906.html
+++ b/image/test/mochitest/test_bug671906.html
@@ -16,43 +16,43 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script type="application/javascript">
 
 var first, second, third;
 var correct, val1, val2;
 
 SimpleTest.waitForExplicitFinish();
 
-function snapshotFirst()
+async function snapshotFirst()
 {
   var iframeelem = document.getElementById('test-iframe');
-  first = snapshotWindow(iframeelem.contentWindow, false);
+  first = await snapshotWindow(iframeelem, false);
 
   iframeelem.onload = snapshotSecond;
   iframeelem.src = "http://example.com/tests/image/test/mochitest/bug671906-iframe.html";
 }
 
-function snapshotSecond()
+async function snapshotSecond()
 {
   var iframeelem = document.getElementById('test-iframe');
-  second = snapshotWindow(iframeelem.contentWindow, false);
+  second = await snapshotWindow(iframeelem, false);
 
   // We must have loaded the image again, because the principals for the
   // loading document are different.
   [correct, val1, val2] = compareSnapshots(first, second, false);
   ok(correct, "Image should have changed after changing the iframe's src.");
 
   iframeelem.onload = snapshotThird;
   iframeelem.src = "http://mochi.test:8888/tests/image/test/mochitest/bug671906-iframe.html";
 }
 
-function snapshotThird()
+async function snapshotThird()
 {
   var iframeelem = document.getElementById('test-iframe');
-  third = snapshotWindow(iframeelem.contentWindow, false);
+  third = await snapshotWindow(iframeelem, false);
 
   // We must have loaded the image again, because the principals for the
   // loading document are different.
   [correct, val1, val2] = compareSnapshots(second, third, false);
   ok(correct, "Image should have changed after changing the iframe's src.");
 
   // We must have looped back to the first image, because the sjs only sends
   // one of two images.
--- a/layout/svg/tests/mochitest.ini
+++ b/layout/svg/tests/mochitest.ini
@@ -1,15 +1,14 @@
 [DEFAULT]
 support-files =
   file_disabled_iframe.html
 
 [test_disabled.html]
 [test_filter_crossorigin.html]
-fail-if = fission
 support-files =
   filters.svg
   file_filter_crossorigin.svg
   file_black_yellow.svg
   file_yellow_black.svg
 
 [test_hover_near_text.html]
 [test_multiple_font_size.html]
--- a/layout/svg/tests/test_filter_crossorigin.html
+++ b/layout/svg/tests/test_filter_crossorigin.html
@@ -19,21 +19,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 <br>
 <!-- These iframes' renderings are expected to match: -->
 <iframe src="http://example.org/tests/layout/svg/tests/file_filter_crossorigin.svg"></iframe>
 <iframe src="file_yellow_black.svg"></iframe>
 
 <pre id="test">
 <script type="application/javascript">
 // Main Function
-function run() {
+async function run() {
   SimpleTest.waitForExplicitFinish();
+
+  // FIXME(Fission): The load event fires before cross-origin iframes have
+  // loaded (bug 1559841).
+  if (SpecialPowers.useRemoteSubframes) {
+    for (let i = 0; i < 100; i++) {
+      await new Promise(resolve => setTimeout(resolve, 0));
+    }
+  }
+
   let snapshots = new Array(4);
   for (let i = 0; i < snapshots.length; i++) {
-    snapshots[i] = snapshotWindow(frames[i].window, false);
+    snapshots[i] = await snapshotWindow(frames[i], false);
   }
 
   // Compare mochi.test iframe against its reference:
   assertSnapshots(snapshots[0], snapshots[1], true, null,
                   "Testcase loaded from mochi.test", "Reference: black/yellow");
 
   // Compare example.org iframe against its reference:
   assertSnapshots(snapshots[2], snapshots[3], true, null,
--- a/widget/tests/window_composition_text_querycontent.xul
+++ b/widget/tests/window_composition_text_querycontent.xul
@@ -8802,94 +8802,94 @@ async function runPasswordMaskDelayTest(
     is(correct, aMatch, `${aDescription}\nREFTEST   IMAGE 1 (TEST): ${data1}\nREFTEST   IMAGE 2 (REFERENCE): ${data2}`);
   }
 
   // First character input
   passwordElement.value = "";
   passwordElement.focus();
   let waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeKey("a");
-  let unmaskedResult = snapshotWindow(passwordWindow, true);
+  let unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  let maskedResult = snapshotWindow(passwordWindow, true);
+  let maskedResult = await snapshotWindow(passwordWindow, true);
 
   inputElement.value = "a";
   inputElement.focus();
   inputElement.setSelectionRange(1, 1);
-  let unmaskedReference = snapshotWindow(inputWindow, true);
+  let unmaskedReference = await snapshotWindow(inputWindow, true);
   inputElement.value = kMask;
   inputElement.setSelectionRange(1, 1);
-  let maskedReference = snapshotWindow(inputWindow, true);
+  let maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): first inputted character should be unmasked for a while");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): first inputted character should be masked after a while");
 
   // Second character input
   passwordElement.value = "a";
   passwordElement.focus();
   passwordElement.setSelectionRange(1, 1);
   waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeKey("b");
-  unmaskedResult = snapshotWindow(passwordWindow, true);
+  unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  maskedResult = snapshotWindow(passwordWindow, true);
+  maskedResult = await snapshotWindow(passwordWindow, true);
 
   inputElement.value = `${kMask}b`;
   inputElement.focus();
   inputElement.setSelectionRange(2, 2);
-  unmaskedReference = snapshotWindow(inputWindow, true);
+  unmaskedReference = await snapshotWindow(inputWindow, true);
   inputElement.value = `${kMask}${kMask}`;
   inputElement.setSelectionRange(2, 2);
-  maskedReference = snapshotWindow(inputWindow, true);
+  maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): second inputted character should be unmasked for a while");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): second inputted character should be masked after a while");
 
   // Typing new character should mask the previous unmasked characters
   passwordElement.value = "ab";
   passwordElement.focus();
   passwordElement.setSelectionRange(2, 2);
   waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeKey("c");
   synthesizeKey("d");
-  unmaskedResult = snapshotWindow(passwordWindow, true);
+  unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  maskedResult = snapshotWindow(passwordWindow, true);
+  maskedResult = await snapshotWindow(passwordWindow, true);
 
   inputElement.value = `${kMask}${kMask}${kMask}d`;
   inputElement.focus();
   inputElement.setSelectionRange(4, 4);
-  unmaskedReference = snapshotWindow(inputWindow, true);
+  unmaskedReference = await snapshotWindow(inputWindow, true);
   inputElement.value = `${kMask}${kMask}${kMask}${kMask}`;
   inputElement.setSelectionRange(4, 4);
-  maskedReference = snapshotWindow(inputWindow, true);
+  maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): forth character input should mask the third character");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): forth inputted character should be masked after a while");
 
   // Typing middle of password should unmask the last input character
   passwordElement.value = "abcd";
   passwordElement.focus();
   passwordElement.setSelectionRange(2, 2);
   waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeKey("e");
-  unmaskedResult = snapshotWindow(passwordWindow, true);
+  unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  maskedResult = snapshotWindow(passwordWindow, true);
+  maskedResult = await snapshotWindow(passwordWindow, true);
 
   inputElement.value = `${kMask}${kMask}e${kMask}${kMask}`;
   inputElement.focus();
   inputElement.setSelectionRange(3, 3);
-  unmaskedReference = snapshotWindow(inputWindow, true);
+  unmaskedReference = await snapshotWindow(inputWindow, true);
   inputElement.value = `${kMask}${kMask}${kMask}${kMask}${kMask}`;
   inputElement.setSelectionRange(3, 3);
-  maskedReference = snapshotWindow(inputWindow, true);
+  maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): inserted character should be unmasked for a while");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): inserted character should be masked after a while");
 
   // Composition string should be unmasked for a while, and shouldn't be committed at masking
   passwordElement.value = "ab";
   passwordElement.focus();
@@ -8897,42 +8897,42 @@ async function runPasswordMaskDelayTest(
   waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeCompositionChange(
     { composition:
       { string: "c",
         clauses: [{ length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 1, length: 0 },
     });
-  unmaskedResult = snapshotWindow(passwordWindow, true);
+  unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  maskedResult = snapshotWindow(passwordWindow, true);
+  maskedResult = await snapshotWindow(passwordWindow, true);
   is(getEditor(passwordElement).composing, true,
      "runPasswordMaskDelayTest(): composition shouldn't be commited at masking the composing string #1");
   synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
 
   inputElement.value = `${kMask}${kMask}`;
   inputElement.focus();
   inputElement.setSelectionRange(1, 1);
   synthesizeCompositionChange(
     { composition:
       { string: "c",
         clauses: [{ length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 1, length: 0 },
     });
-  unmaskedReference = snapshotWindow(inputWindow, true);
+  unmaskedReference = await snapshotWindow(inputWindow, true);
   synthesizeCompositionChange(
     { composition:
       { string: kMask,
         clauses: [{ length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 1, length: 0 },
     });
-  maskedReference = snapshotWindow(inputWindow, true);
+  maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): composing character should be unmasked for a while");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): composing character should be masked after a while");
   synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
 
   // Updating composition string should unmask the composition string for a while
   passwordElement.value = "ab";
@@ -8950,42 +8950,42 @@ async function runPasswordMaskDelayTest(
   waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeCompositionChange(
     { composition:
       { string: "d",
         clauses: [{ length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 1, length: 0 },
     });
-  unmaskedResult = snapshotWindow(passwordWindow, true);
+  unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  maskedResult = snapshotWindow(passwordWindow, true);
+  maskedResult = await snapshotWindow(passwordWindow, true);
   is(getEditor(passwordElement).composing, true,
      "runPasswordMaskDelayTest(): composition shouldn't be commited at masking the composing string #2");
   synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
 
   inputElement.value = `${kMask}${kMask}`;
   inputElement.focus();
   inputElement.setSelectionRange(1, 1);
   synthesizeCompositionChange(
     { composition:
       { string: "d",
         clauses: [{ length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 1, length: 0 },
     });
-  unmaskedReference = snapshotWindow(inputWindow, true);
+  unmaskedReference = await snapshotWindow(inputWindow, true);
   synthesizeCompositionChange(
     { composition:
       { string: kMask,
         clauses: [{ length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 1, length: 0 },
     });
-  maskedReference = snapshotWindow(inputWindow, true);
+  maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): updated composing character should be unmasked for a while");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): updated composing character should be masked after a while");
   synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
 
   // Composing multi-characters should be unmasked for a while.
   passwordElement.value = "ab";
@@ -9003,42 +9003,42 @@ async function runPasswordMaskDelayTest(
   waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeCompositionChange(
     { composition:
       { string: "cd",
         clauses: [{ length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 2, length: 0 },
     });
-  unmaskedResult = snapshotWindow(passwordWindow, true);
+  unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  maskedResult = snapshotWindow(passwordWindow, true);
+  maskedResult = await snapshotWindow(passwordWindow, true);
   is(getEditor(passwordElement).composing, true,
      "runPasswordMaskDelayTest(): composition shouldn't be commited at masking the composing string #3");
   synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
 
   inputElement.value = `${kMask}${kMask}`;
   inputElement.focus();
   inputElement.setSelectionRange(1, 1);
   synthesizeCompositionChange(
     { composition:
       { string: "cd",
         clauses: [{ length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 2, length: 0 },
     });
-  unmaskedReference = snapshotWindow(inputWindow, true);
+  unmaskedReference = await snapshotWindow(inputWindow, true);
   synthesizeCompositionChange(
     { composition:
       { string: `${kMask}${kMask}`,
         clauses: [{ length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 2, length: 0 },
     });
-  maskedReference = snapshotWindow(inputWindow, true);
+  maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): all of composing string should be unmasked for a while");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): all of composing string should be masked after a while");
   synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
 
   // Committing composition should make the commit string unmasked.
   passwordElement.value = "ab";
@@ -9050,27 +9050,27 @@ async function runPasswordMaskDelayTest(
       { string: "cd",
         clauses: [{ length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }],
       },
       caret: { start: 2, length: 0 },
     });
   await waitForMaskingLastInput;
   waitForMaskingLastInput = promiseAllPasswordMasked();
   synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
-  unmaskedResult = snapshotWindow(passwordWindow, true);
+  unmaskedResult = await snapshotWindow(passwordWindow, true);
   await waitForMaskingLastInput;
-  maskedResult = snapshotWindow(passwordWindow, true);
+  maskedResult = await snapshotWindow(passwordWindow, true);
 
   inputElement.value = `${kMask}cd${kMask}`;
   inputElement.focus();
   inputElement.setSelectionRange(3, 3);
-  unmaskedReference = snapshotWindow(inputWindow, true);
+  unmaskedReference = await snapshotWindow(inputWindow, true);
   inputElement.value = `${kMask}${kMask}${kMask}${kMask}`;
   inputElement.setSelectionRange(3, 3);
-  maskedReference = snapshotWindow(inputWindow, true);
+  maskedReference = await snapshotWindow(inputWindow, true);
   checkSnapshots(unmaskedResult, unmaskedReference, true,
                  "runPasswordMaskDelayTest(): committed string should be unmasked for a while");
   checkSnapshots(maskedResult, maskedReference, true,
                  "runPasswordMaskDelayTest(): committed string should be masked after a while");
 }
 
 async function runTest()
 {