Merge inbound to mozilla-central. a=merge
authorarthur.iakab <aiakab@mozilla.com>
Sat, 21 Sep 2019 13:00:40 +0300
changeset 494415 5ac55079c87e4cd25eafafa8662594b4a2917dcc
parent 494414 de5a09d263ff557012c5872a9edfb276ca1e353f (current diff)
parent 494413 56e11fddf939f61bcfac9e179e13ff62a8ad5d82 (diff)
child 494416 69aa8e7e33d5d417e4d40f83accd36a275fccd08
child 494430 2a7cddefc1bbeee6bc41105b76814e4760a878df
push id95992
push useraiakab@mozilla.com
push dateSat, 21 Sep 2019 10:07:20 +0000
treeherderautoland@69aa8e7e33d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone71.0a1
first release with
nightly linux32
5ac55079c87e / 71.0a1 / 20190921100259 / files
nightly linux64
5ac55079c87e / 71.0a1 / 20190921100259 / files
nightly mac
5ac55079c87e / 71.0a1 / 20190921100259 / files
nightly win32
5ac55079c87e / 71.0a1 / 20190921100259 / files
nightly win64
5ac55079c87e / 71.0a1 / 20190921100259 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
docshell/base/BrowsingContext.cpp
docshell/base/BrowsingContext.h
testing/web-platform/tests/accelerometer/Accelerometer_onerror-manual.https.html
testing/web-platform/tests/ambient-light/AmbientLightSensor_onerror-manual.https.html
testing/web-platform/tests/geolocation-sensor/GeolocationSensor_onerror-manual.https.html
testing/web-platform/tests/gyroscope/Gyroscope_onerror-manual.https.html
testing/web-platform/tests/magnetometer/Magnetometer_onerror-manual.https.html
testing/web-platform/tests/orientation-sensor/OrientationSensor_onerror-manual.https.html
--- a/accessible/tests/mochitest/browser.js
+++ b/accessible/tests/mochitest/browser.js
@@ -114,17 +114,17 @@ function openBrowserWindowIntl() {
     if ("width" in rect) {
       params += ",width=" + rect.width;
     }
     if ("height" in rect) {
       params += ",height=" + rect.height;
     }
   }
 
-  gBrowserContext.browserWnd = window.openDialog(
+  gBrowserContext.browserWnd = window.docShell.rootTreeItem.domWindow.openDialog(
     AppConstants.BROWSER_CHROME_URL,
     "_blank",
     params,
     gBrowserContext.startURL || "data:text/html,<html></html>"
   );
 
   whenDelayedStartupFinished(browserWindow(), function() {
     addA11yLoadEvent(startBrowserTests, browserWindow());
--- a/accessible/tests/mochitest/events/docload/test_docload_root.html
+++ b/accessible/tests/mochitest/events/docload/test_docload_root.html
@@ -33,17 +33,17 @@
         } catch (e) {
           ok(false, `Can't get parent for ${prettyName(docAcc)}`);
           throw e;
         }
       }
 
       this.eventSeq = [ new invokerChecker(EVENT_REORDER, gRootAcc) ];
 
-      this.invoke = () => (gDialog = window.openDialog(aURL));
+      this.invoke = () => (gDialog = docShell.rootTreeItem.domWindow.openDialog(aURL));
 
       this.finalCheck = () => {
         const accTree = {
           role: ROLE_APP_ROOT,
           children: [
             {
               role: ROLE_CHROME_WINDOW,
             },
--- a/accessible/tests/mochitest/events/docload/test_docload_shutdown.html
+++ b/accessible/tests/mochitest/events/docload/test_docload_shutdown.html
@@ -49,17 +49,17 @@
           },
           get targetDescr() {
             return "inner iframe of docload_wnd.html document";
           },
         },
       ];
 
 
-      this.invoke = () => gDialog = window.openDialog(aURL);
+      this.invoke = () => gDialog = window.docShell.rootTreeItem.domWindow.openDialog(aURL);
 
       this.finalCheck = () => {
         const accTree = {
           role: ROLE_APP_ROOT,
           children: [
             {
               role: ROLE_CHROME_WINDOW,
             },
--- a/accessible/tests/mochitest/focus/test_focusedChild.html
+++ b/accessible/tests/mochitest/focus/test_focusedChild.html
@@ -19,17 +19,18 @@
 
   <script type="application/javascript">
     function openWnd() {
       this.eventSeq = [ new invokerChecker(EVENT_FOCUS,
                                            getDialogAccessible,
                                            this) ];
 
       this.invoke = function openWnd_invoke() {
-        this.dialog = window.openDialog("about:mozilla",
+        this.dialog = window.docShell.rootTreeItem.domWindow
+                            .openDialog("about:mozilla",
                                         "AboutMozilla",
                                         "chrome,width=600,height=600");
       };
 
       this.finalCheck = function openWnd_finalCheck() {
         var app = getApplicationAccessible();
         is(app.focusedChild, getDialogAccessible(this),
            "Wrong focused child");
--- a/browser/base/content/test/general/browser_bug484315.js
+++ b/browser/base/content/test/general/browser_bug484315.js
@@ -1,24 +1,14 @@
-function test() {
-  var contentWin = window.open("about:blank", "", "width=100,height=100");
-  for (let win of Services.wm.getEnumerator("navigator:browser")) {
-    if (win.content == contentWin) {
-      Services.prefs.setBoolPref("browser.tabs.closeWindowWithLastTab", false);
-      win.gBrowser.removeCurrentTab();
-      ok(win.closed, "popup is closed");
+add_task(async function test() {
+  window.open("about:blank", "", "width=100,height=100,noopener");
 
-      // clean up
-      if (!win.closed) {
-        win.close();
-      }
-      if (
-        Services.prefs.prefHasUserValue("browser.tabs.closeWindowWithLastTab")
-      ) {
-        Services.prefs.clearUserPref("browser.tabs.closeWindowWithLastTab");
-      }
+  let win = Services.wm.getMostRecentWindow("navigator:browser");
+  Services.prefs.setBoolPref("browser.tabs.closeWindowWithLastTab", false);
+  win.gBrowser.removeCurrentTab();
+  ok(win.closed, "popup is closed");
 
-      return;
-    }
+  // clean up
+  if (!win.closed) {
+    win.close();
   }
-
-  throw new Error("couldn't find the content window");
-}
+  Services.prefs.clearUserPref("browser.tabs.closeWindowWithLastTab");
+});
--- a/browser/base/content/test/general/browser_fullscreen-window-open.js
+++ b/browser/base/content/test/general/browser_fullscreen-window-open.js
@@ -176,16 +176,17 @@ function test_open_with_pref_to_disable_
 }
 
 // Test for window.open() called from chrome context.
 function test_open_from_chrome() {
   waitForWindowOpenFromChrome({
     message: {
       title: "test_open_from_chrome",
       param: "",
+      option: "noopener",
     },
     finalizeFn() {},
   });
 }
 
 function waitForTabOpen(aOptions) {
   let message = aOptions.message;
 
--- a/browser/components/extensions/test/browser/browser_ext_sidebarAction.js
+++ b/browser/components/extensions/test/browser/browser_ext_sidebarAction.js
@@ -175,17 +175,18 @@ add_task(async function sidebar_isOpen()
     result: true,
   });
   await sendMessage(extension2, "isOpen", {
     arg: { windowId: WINDOW_ID_CURRENT },
     result: false,
   });
 
   info("Open a new window");
-  let newWin = open();
+  open("", "", "noopener");
+  let newWin = Services.wm.getMostRecentWindow("navigator:browser");
 
   info("The new window has no sidebar");
   await sendMessage(extension1, "isOpen", { result: false });
   await sendMessage(extension2, "isOpen", { result: false });
 
   info("But the original window still does");
   await sendMessage(extension1, "isOpen", { arg: { windowId }, result: true });
   await sendMessage(extension2, "isOpen", { arg: { windowId }, result: false });
--- a/browser/components/preferences/in-content/subdialogs.js
+++ b/browser/components/preferences/in-content/subdialogs.js
@@ -95,17 +95,18 @@ SubDialog.prototype = {
       this._closingPromise.then(() => {
         this.open.apply(this, args);
       });
       return;
     }
     this._addDialogEventListeners();
 
     let features =
-      (aFeatures ? aFeatures + "," : "") + "resizable,dialog=no,centerscreen";
+      (aFeatures ? aFeatures + "," : "") +
+      "resizable,dialog=no,centerscreen,chrome=no";
     let dialog = window.openDialog(
       aURL,
       `dialogFrame-${this._id}`,
       features,
       aParams
     );
     if (aClosingCallback) {
       this._closingCallback = aClosingCallback.bind(dialog);
--- a/browser/modules/SiteDataManager.jsm
+++ b/browser/modules/SiteDataManager.jsm
@@ -503,17 +503,17 @@ var SiteDataManager = {
    */
   promptSiteDataRemoval(win, removals) {
     if (removals) {
       let args = {
         hosts: removals,
         allowed: false,
       };
       let features = "centerscreen,chrome,modal,resizable=no";
-      win.openDialog(
+      win.docShell.rootTreeItem.domWindow.openDialog(
         "chrome://browser/content/preferences/siteDataRemoveSelected.xul",
         "",
         features,
         args
       );
       return args.allowed;
     }
 
--- a/devtools/client/responsive/test/browser/browser_window_close.js
+++ b/devtools/client/responsive/test/browser/browser_window_close.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 add_task(async function() {
   const newWindowPromise = BrowserTestUtils.waitForNewWindow();
-  window.open("data:text/html;charset=utf-8,", "_blank");
+  window.open("data:text/html;charset=utf-8,", "_blank", "noopener,all");
   const newWindow = await newWindowPromise;
 
   newWindow.focus();
   await BrowserTestUtils.browserLoaded(newWindow.gBrowser.selectedBrowser);
 
   const tab = newWindow.gBrowser.selectedTab;
   await openRDM(tab);
 
--- a/devtools/client/shared/test/browser_dbg_multiple-windows.js
+++ b/devtools/client/shared/test/browser_dbg_multiple-windows.js
@@ -107,11 +107,11 @@ async function continue_remove_tab(clien
   ok(!foundTab2, "Tab2 should be gone.");
 
   ok(tabs[0].selected, "The previously opened tab is selected.");
 }
 
 async function addWindow(url) {
   info("Adding window: " + url);
   const onNewWindow = BrowserTestUtils.waitForNewWindow({ url });
-  window.open(url);
+  window.open(url, "_blank", "noopener");
   return onNewWindow;
 }
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -97,16 +97,18 @@ CanonicalBrowsingContext* BrowsingContex
 }
 
 /* static */
 already_AddRefed<BrowsingContext> BrowsingContext::Create(
     BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
     Type aType) {
   MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->mType == aType);
 
+  MOZ_DIAGNOSTIC_ASSERT(aType != Type::Chrome || XRE_IsParentProcess());
+
   uint64_t id = nsContentUtils::GenerateBrowsingContextId();
 
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("Creating 0x%08" PRIx64 " in %s", id,
            XRE_IsParentProcess() ? "Parent" : "Child"));
 
   // Determine which BrowsingContextGroup this context should be created in.
   RefPtr<BrowsingContextGroup> group =
@@ -119,16 +121,18 @@ already_AddRefed<BrowsingContext> Browsi
   } else {
     context = new BrowsingContext(aParent, group, id, aType);
   }
 
   // The name and opener fields need to be explicitly initialized. Don't bother
   // using transactions to set them, as we haven't been attached yet.
   context->mName = aName;
   if (aOpener) {
+    MOZ_DIAGNOSTIC_ASSERT(aOpener->Group() == context->Group());
+    MOZ_DIAGNOSTIC_ASSERT(aOpener->mType == context->mType);
     context->mOpenerId = aOpener->Id();
     context->mHadOriginalOpener = true;
   }
   context->mEmbedderPolicy = nsILoadInfo::EMBEDDER_POLICY_NULL;
 
   BrowsingContext* inherit = aParent ? aParent : aOpener;
   if (inherit) {
     context->mOpenerPolicy = inherit->Top()->mOpenerPolicy;
@@ -1047,17 +1051,17 @@ void BrowsingContext::Transaction::Apply
     aBrowsingContext->m##name = std::move(*m##name); \
     aBrowsingContext->DidSet##name();                \
     m##name.reset();                                 \
   }
 #include "mozilla/dom/BrowsingContextFieldList.h"
 }
 
 BrowsingContext::IPCInitializer BrowsingContext::GetIPCInitializer() {
-  // FIXME: We should assert that we're loaded in-content here. (bug 1553804)
+  MOZ_DIAGNOSTIC_ASSERT(mType == Type::Content);
 
   IPCInitializer init;
   init.mId = Id();
   init.mParentId = mParent ? mParent->Id() : 0;
   init.mCached = IsCached();
 
 #define MOZ_BC_FIELD(name, type) init.m##name = m##name;
 #include "mozilla/dom/BrowsingContextFieldList.h"
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -208,22 +208,24 @@ class BrowsingContext : public nsWrapper
 
   BrowsingContext* GetParent() const { return mParent; }
 
   BrowsingContext* Top();
 
   already_AddRefed<BrowsingContext> GetOpener() const {
     RefPtr<BrowsingContext> opener(Get(mOpenerId));
     if (!mIsDiscarded && opener && !opener->mIsDiscarded) {
+      MOZ_DIAGNOSTIC_ASSERT(opener->mType == mType);
       return opener.forget();
     }
     return nullptr;
   }
   void SetOpener(BrowsingContext* aOpener) {
     MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->Group() == Group());
+    MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->mType == mType);
     SetOpenerId(aOpener ? aOpener->Id() : 0);
   }
 
   bool HasOpener() const;
 
   bool HadOriginalOpener() const { return mHadOriginalOpener; }
 
   /**
--- a/docshell/test/browser/browser_bug388121-2.js
+++ b/docshell/test/browser/browser_bug388121-2.js
@@ -33,17 +33,18 @@ function test() {
     } else {
       ++iteration;
       doTest();
     }
   }
 
   function doTest() {
     uri = uris[iteration - 1];
-    w = window.open(uri, "_blank", "width=10,height=10");
+    window.open(uri, "_blank", "width=10,height=10,noopener");
+    w = Services.wm.getMostRecentWindow("navigator:browser").content;
     var prin = w.document.nodePrincipal;
     if (!uri) {
       uri = undefined;
     }
     isnot(prin, null, "Forced principal must not be null when loading " + uri);
     isnot(
       prin,
       undefined,
--- a/docshell/test/chrome/bug112564_window.xul
+++ b/docshell/test/chrome/bug112564_window.xul
@@ -17,34 +17,34 @@
     const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
     const LISTEN_EVENTS = ["load", "unload", "pageshow", "pagehide"];
 
     var gBrowser;
     var gTestsIterator;
     var gExpected = [];
 
     function ok(condition, message) {
-      window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+      window.arguments[0].SimpleTest.ok(condition, message);
     }
 
     function is(a, b, message) {
-      window.opener.wrappedJSObject.SimpleTest.is(a, b, message);
+      window.arguments[0].SimpleTest.is(a, b, message);
     }
 
     function finish() {
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.removeEventListener(eventType, eventListener, true);
       }
 
       // Work around bug 467960
       var history = gBrowser.webNavigation.sessionHistory;
       history.legacySHistory.PurgeHistory(history.count);
 
       window.close();
-      window.opener.wrappedJSObject.SimpleTest.finish();
+      window.arguments[0].SimpleTest.finish();
     }
 
     function onLoad() {
       gBrowser = document.getElementById("content");
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.addEventListener(eventType, eventListener, true);
       }
              
--- a/docshell/test/chrome/bug113934_window.xul
+++ b/docshell/test/chrome/bug113934_window.xul
@@ -11,17 +11,17 @@
     <spacer flex="1"/>
   </hbox>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     var imports = [ "SimpleTest", "is", "isnot", "ok", "snapshotWindow",
                     "compareSnapshots", "onerror" ];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
 
     function $(id) {
       return document.getElementById(id);
     }
 
     function addBrowser(parent, id, width, height) {
       var b =
--- a/docshell/test/chrome/bug215405_window.xul
+++ b/docshell/test/chrome/bug215405_window.xul
@@ -12,17 +12,17 @@
         height="600"
         onload="onLoad();"
         title="215405 test">
 
   <script type="application/javascript"><![CDATA[
     const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
     var imports = [ "SimpleTest", "is", "isnot", "ok"];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
 
     const text="MOZILLA";
     const nostoreURI = "http://mochi.test:8888/tests/docshell/test/chrome/" +
                        "215405_nostore.html";
     const nocacheURI = "https://example.com:443/tests/docshell/test/chrome/" +
                        "215405_nocache.html";
 
@@ -33,17 +33,17 @@
 
     function finish() {
       gBrowser.removeEventListener("pageshow", eventListener, true);
       // Work around bug 467960
       var history = gBrowser.webNavigation.sessionHistory;
       history.legacySHistory.PurgeHistory(history.count);
 
       window.close();
-      window.opener.wrappedJSObject.SimpleTest.finish();
+      window.arguments[0].SimpleTest.finish();
     }
 
     function onLoad(e) {
       gBrowser = document.getElementById("content");
       gBrowser.addEventListener("pageshow", eventListener, true);
        
       gTestsIterator = testsIterator();
       nextTest();
--- a/docshell/test/chrome/bug364461_window.xul
+++ b/docshell/test/chrome/bug364461_window.xul
@@ -17,28 +17,28 @@
     const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
     const LISTEN_EVENTS = ["load", "unload", "pageshow", "pagehide"];
 
     var gBrowser;
     var gTestsIterator;
     var gExpected = [];
 
     function ok(condition, message) {
-      window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+      window.arguments[0].SimpleTest.ok(condition, message);
     }
     function is(a, b, message) {
-      window.opener.wrappedJSObject.SimpleTest.is(a, b, message);
+      window.arguments[0].SimpleTest.is(a, b, message);
     }
     function finish() {
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.removeEventListener(eventType, eventListener, true);
       }
     
       window.close();
-      window.opener.wrappedJSObject.SimpleTest.finish();
+      window.arguments[0].SimpleTest.finish();
     }
 
     function onLoad() {
       gBrowser = document.getElementById("content");
 
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.addEventListener(eventType, eventListener, true);
       }
--- a/docshell/test/chrome/bug396519_window.xul
+++ b/docshell/test/chrome/bug396519_window.xul
@@ -18,28 +18,28 @@
     const LISTEN_EVENTS = ["pageshow"];
 
     var gBrowser;
     var gTestCount = 0;
     var gTestsIterator;
     var gExpected = [];
 
     function ok(condition, message) {
-      window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+      window.arguments[0].SimpleTest.ok(condition, message);
     }
     function is(a, b, message) {
-      window.opener.wrappedJSObject.SimpleTest.is(a, b, message);
+      window.arguments[0].SimpleTest.is(a, b, message);
     }
     function finish() {
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.removeEventListener(eventType, eventListener, true);
       }
     
       window.close();
-      window.opener.wrappedJSObject.SimpleTest.finish();
+      window.arguments[0].SimpleTest.finish();
     }
 
     function onLoad() {
       gBrowser = document.getElementById("content");
 
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.addEventListener(eventType, eventListener, true);
       }
--- a/docshell/test/chrome/bug449778_window.xul
+++ b/docshell/test/chrome/bug449778_window.xul
@@ -5,17 +5,17 @@
 
   <hbox id="parent">
   </hbox>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     var imports = [ "SimpleTest", "is", "isnot", "ok", "onerror" ];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
 
     function $(id) {
       return document.getElementById(id);
     }
 
     function addBrowser(parent, id, width, height) {
       var b =
--- a/docshell/test/chrome/bug449780_window.xul
+++ b/docshell/test/chrome/bug449780_window.xul
@@ -5,17 +5,17 @@
 
   <hbox id="parent">
   </hbox>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     var imports = [ "SimpleTest", "is", "isnot", "ok", "onerror" ];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
 
     function $(id) {
       return document.getElementById(id);
     }
 
     function addBrowser(parent, id, width, height) {
       var b =
--- a/docshell/test/chrome/bug89419_window.xul
+++ b/docshell/test/chrome/bug89419_window.xul
@@ -15,17 +15,17 @@
   <script type="application/javascript"><![CDATA[
     ////
     // A visited link should have the :visited style applied
     // to it when displayed on a page which was fetched from
     // the bfcache.
     //
     async function runTests() {
       // Disable rcwn to make cache behavior deterministic.
-      var {SpecialPowers} = opener;
+      var {SpecialPowers} = window.arguments[0];
       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.
       await new Promise(resolve => {
         doPageNavigation({
           uri: getHttpUrl("89419.html"),
           onNavComplete: resolve,
--- a/docshell/test/chrome/bug92598_window.xul
+++ b/docshell/test/chrome/bug92598_window.xul
@@ -17,34 +17,34 @@
     const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
     const LISTEN_EVENTS = ["load", "unload", "pageshow", "pagehide"];
 
     var gBrowser;
     var gTestsIterator;
     var gExpected = [];
 
     function ok(condition, message) {
-      window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+      window.arguments[0].SimpleTest.ok(condition, message);
     }
 
     function is(a, b, message) {
-      window.opener.wrappedJSObject.SimpleTest.is(a, b, message);
+      window.arguments[0].SimpleTest.is(a, b, message);
     }
 
     function finish() {
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.removeEventListener(eventType, eventListener, true);
       }
      
       // Work around bug 467960
       var history = gBrowser.webNavigation.sessionHistory;
       history.legacySHistory.PurgeHistory(history.count);
 
       window.close();
-      window.opener.wrappedJSObject.SimpleTest.finish();
+      window.arguments[0].SimpleTest.finish();
     }
 
     function onLoad() {
       gBrowser = document.getElementById("content");
       for (let eventType of LISTEN_EVENTS) {
         gBrowser.addEventListener(eventType, eventListener, true);
       }
              
--- a/docshell/test/chrome/docshell_helpers.js
+++ b/docshell/test/chrome/docshell_helpers.js
@@ -1,8 +1,11 @@
+if (!window.opener && window.arguments) {
+  window.opener = window.arguments[0];
+}
 /**
  * Import common SimpleTest methods so that they're usable in this window.
  */
 var imports = [
   "SimpleTest",
   "is",
   "isnot",
   "ok",
--- a/docshell/test/chrome/mozFrameType_window.xul
+++ b/docshell/test/chrome/mozFrameType_window.xul
@@ -7,18 +7,18 @@
   onload="runTests();">
 
   <html:iframe id="normalFrame"/>
   <html:iframe id="typeContentFrame" mozframetype="content"/>
 
   <script type="application/javascript" src="docshell_helpers.js" />
   <script type="application/javascript"><![CDATA[
     function runTests() {
-      let opener = window.opener;
-      let SimpleTest = opener.wrappedJSObject.SimpleTest;
+      let opener = window.arguments[0];
+      let SimpleTest = opener.SimpleTest;
 
       function getDocShellType(frame) {
         return frame.contentWindow.docShell.itemType;
       }
 
       var normalFrame = document.getElementById("normalFrame");
       var typeContentFrame = document.getElementById("typeContentFrame");
 
--- a/docshell/test/chrome/test_bug112564.xul
+++ b/docshell/test/chrome/test_bug112564.xul
@@ -23,15 +23,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 112564 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug112564_window.xul", "bug112564",
-            "chrome,width=600,height=600");
+window.openDialog("bug112564_window.xul", "bug112564",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug113934.xul
+++ b/docshell/test/chrome/test_bug113934.xul
@@ -16,14 +16,14 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 396519</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     SimpleTest.waitForExplicitFinish();
 
     addLoadEvent(function() {
-      window.open("bug113934_window.xul?content", "bug113934",
-                  "chrome,width=800,height=800");
+      window.openDialog("bug113934_window.xul?content", "bug113934",
+                        "chrome,width=800,height=800,noopener", window);
     });
 
   ]]></script>
 </window>
--- a/docshell/test/chrome/test_bug215405.xul
+++ b/docshell/test/chrome/test_bug215405.xul
@@ -23,15 +23,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 215405 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug215405_window.xul", "bug215405",
-            "chrome,width=600,height=600");
+window.openDialog("bug215405_window.xul", "bug215405",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug293235.xul
+++ b/docshell/test/chrome/test_bug293235.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 293235 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug293235_window.xul", "bug293235",
-            "chrome,width=600,height=600");
+window.openDialog("bug293235_window.xul", "bug293235",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug294258.xul
+++ b/docshell/test/chrome/test_bug294258.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 294258 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug294258_window.xul", "bug294258",
-            "chrome,width=600,height=600");
+window.openDialog("bug294258_window.xul", "bug294258",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug298622.xul
+++ b/docshell/test/chrome/test_bug298622.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 298622 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug298622_window.xul", "bug298622",
-            "chrome,width=600,height=600");
+window.openDialog("bug298622_window.xul", "bug298622",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug301397.xul
+++ b/docshell/test/chrome/test_bug301397.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 301397 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug301397_window.xul", "bug301397",
-            "chrome,width=600,height=600");
+window.openDialog("bug301397_window.xul", "bug301397",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug303267.xul
+++ b/docshell/test/chrome/test_bug303267.xul
@@ -25,15 +25,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 SimpleTest.expectAssertions(0, 1);
 
 /** Test for Bug 303267 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug303267_window.xul", "bug303267",
-            "chrome,width=600,height=600");
+window.openDialog("bug303267_window.xul", "bug303267",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug311007.xul
+++ b/docshell/test/chrome/test_bug311007.xul
@@ -28,15 +28,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 if (navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 1);
 }
 
 /** Test for Bug 311007 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug311007_window.xul", "bug311007",
-            "chrome,width=600,height=600");
+window.openDialog("bug311007_window.xul", "bug311007",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug321671.xul
+++ b/docshell/test/chrome/test_bug321671.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 321671 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug321671_window.xul", "bug321671",
-            "chrome,width=600,height=600,scrollbars");
+window.openDialog("bug321671_window.xul", "bug321671",
+                  "chrome,width=600,height=600,scrollbars,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug360511.xul
+++ b/docshell/test/chrome/test_bug360511.xul
@@ -25,15 +25,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 360511 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug360511_window.xul", "bug360511",
-            "chrome,scrollbars,width=600,height=600");
+window.openDialog("bug360511_window.xul", "bug360511",
+                  "chrome,scrollbars,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug364461.xul
+++ b/docshell/test/chrome/test_bug364461.xul
@@ -29,15 +29,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 SimpleTest.waitForExplicitFinish();
 
 SpecialPowers.pushPrefEnv({
   "set":[["security.data_uri.block_toplevel_data_uri_navigations", false]]
 }, runTests);
 
 function runTests() {
-  window.open("bug364461_window.xul", "bug364461",
-              "chrome,width=600,height=600");
+  window.openDialog("bug364461_window.xul", "bug364461",
+                    "chrome,width=600,height=600,noopener", window);
 }
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug396519.xul
+++ b/docshell/test/chrome/test_bug396519.xul
@@ -16,13 +16,13 @@ https://bugzilla.mozilla.org/show_bug.cg
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
     /** Test for Bug 396519 **/
 
     SimpleTest.waitForExplicitFinish();
-    window.open("bug396519_window.xul", "bug396519",
-                "chrome,width=600,height=600");
+    window.openDialog("bug396519_window.xul", "bug396519",
+                      "chrome,width=600,height=600,noopener", window);
 
   ]]></script>
 </window>
--- a/docshell/test/chrome/test_bug396649.xul
+++ b/docshell/test/chrome/test_bug396649.xul
@@ -27,15 +27,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 396649 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug396649_window.xul", "bug396649",
-            "chrome,width=600,height=600,scrollbars");
+window.openDialog("bug396649_window.xul", "bug396649",
+                  "chrome,width=600,height=600,scrollbars,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug449778.xul
+++ b/docshell/test/chrome/test_bug449778.xul
@@ -16,14 +16,14 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 396519</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     SimpleTest.waitForExplicitFinish();
 
     addLoadEvent(function() {
-      window.open("bug449778_window.xul", "bug449778",
-                  "chrome,width=800,height=800");
+      window.openDialog("bug449778_window.xul", "bug449778",
+                        "chrome,width=800,height=800,noopener", window);
     });
 
   ]]></script>
 </window>
--- a/docshell/test/chrome/test_bug449780.xul
+++ b/docshell/test/chrome/test_bug449780.xul
@@ -16,14 +16,14 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 396519</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     SimpleTest.waitForExplicitFinish();
 
     addLoadEvent(function() {
-      window.open("bug449780_window.xul", "bug449780",
-                  "chrome,width=800,height=800");
+      window.openDialog("bug449780_window.xul", "bug449780",
+                        "chrome,width=800,height=800,noopener", window);
     });
 
   ]]></script>
 </window>
--- a/docshell/test/chrome/test_bug456980.xul
+++ b/docshell/test/chrome/test_bug456980.xul
@@ -16,14 +16,14 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 396519</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     SimpleTest.waitForExplicitFinish();
 
     addLoadEvent(function() {
-      window.open("bug113934_window.xul?chrome", "bug456980",
-                  "chrome,width=800,height=800");
+      window.openDialog("bug113934_window.xul?chrome", "bug456980",
+                        "chrome,width=800,height=800,noopener", window);
     });
 
   ]]></script>
 </window>
--- a/docshell/test/chrome/test_bug582176.xul
+++ b/docshell/test/chrome/test_bug582176.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 582176 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug582176_window.xul", "bug582176",
-            "chrome,width=600,height=600");
+window.openDialog("bug582176_window.xul", "bug582176",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug608669.xul
+++ b/docshell/test/chrome/test_bug608669.xul
@@ -23,16 +23,18 @@ SimpleTest.waitForExplicitFinish();
 addLoadEvent(nextTest);
 
 gen = doTest();
 
 function nextTest() {
   gen.next();
 }
 
+let chromeWindow = docShell.rootTreeItem.domWindow;
+
 function* doTest() {
   var notificationCount = 0;
   var observer = {
     observe: function(aSubject, aTopic, aData) {
       is(aTopic, "chrome-document-global-created",
          "correct topic");
       is(aData, "null",
          "correct data");
@@ -43,34 +45,36 @@ function* doTest() {
   var os = Cc["@mozilla.org/observer-service;1"].
     getService(Ci.nsIObserverService);
   os.addObserver(observer, "chrome-document-global-created");
   os.addObserver(observer, "content-document-global-created");
 
   is(notificationCount, 0, "initial count");
 
   // create a new window
-  var testWin = window.open("", "bug 608669", "chrome,width=600,height=600");
+  var testWin = chromeWindow.open("", "bug 608669", "chrome,width=600,height=600");
   testWin.x = "y";
   is(notificationCount, 1, "after created window");
 
   // Try loading in the window
   testWin.location = "bug608669.xul";
-  window.onmessage = nextTest;
+  chromeWindow.onmessage = nextTest;
   yield undefined;
   is(notificationCount, 1, "after first load");
   is(testWin.x, "y", "reused window");
 
   // Try loading again in the window
   testWin.location = "bug608669.xul?x";
-  window.onmessage = nextTest;
+  chromeWindow.onmessage = nextTest;
   yield undefined;
   is(notificationCount, 2, "after second load");
   is("x" in testWin, false, "didn't reuse window");
 
+  chromeWindow.onmessage = null;
+
   testWin.close();
 
   os.removeObserver(observer, "chrome-document-global-created");
   os.removeObserver(observer, "content-document-global-created");
   SimpleTest.finish();
 }
 
   ]]></script>
--- a/docshell/test/chrome/test_bug662200.xul
+++ b/docshell/test/chrome/test_bug662200.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 662200 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug662200_window.xul", "bug662200",
-            "chrome,width=600,height=600");
+window.openDialog("bug662200_window.xul", "bug662200",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug690056.xul
+++ b/docshell/test/chrome/test_bug690056.xul
@@ -14,13 +14,13 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 690056</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
   /** Test for Bug 690056 **/
 SimpleTest.waitForExplicitFinish();
-window.open("bug690056_window.xul", "bug690056",
-            "chrome,width=600,height=600");
+window.openDialog("bug690056_window.xul", "bug690056",
+                  "chrome,width=600,height=600,noopener", window);
   ]]>
   </script>
 </window>
--- a/docshell/test/chrome/test_bug89419.xul
+++ b/docshell/test/chrome/test_bug89419.xul
@@ -24,15 +24,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 89419 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug89419_window.xul", "bug89419",
-            "chrome,width=600,height=600");
+window.openDialog("bug89419_window.xul", "bug89419",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_bug92598.xul
+++ b/docshell/test/chrome/test_bug92598.xul
@@ -23,15 +23,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 92598 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("bug92598_window.xul", "bug92598",
-            "chrome,width=600,height=600");
+window.openDialog("bug92598_window.xul", "bug92598",
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_mozFrameType.xul
+++ b/docshell/test/chrome/test_mozFrameType.xul
@@ -27,16 +27,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 if (navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 1);
 }
 
 /** Test for Bug 769771 **/
 SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(function () {
-  window.open("mozFrameType_window.xul", "mozFrameType",
-              "chrome,width=600,height=600");
+  window.openDialog("mozFrameType_window.xul", "mozFrameType",
+                    "chrome,width=600,height=600,noopener", window);
 });
 
 ]]>
 </script>
 
 </window>
--- a/docshell/test/chrome/test_principalInherit.xul
+++ b/docshell/test/chrome/test_principalInherit.xul
@@ -56,17 +56,17 @@ var tests = [
   },
   function testInheritFromCreated(cb) {
     // Open a new chrome window with a type="content" iframe, so that it has no
     // same-type parent.
     // Load a javascript: URI in it to ensure that GetInheritedPrincipal will
     // force creation of a content viewer.
     let xulWinURL = 'data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?>' +
                     '<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>';
-    let newWin = window.openDialog(xulWinURL, "chrome_window", "chrome");
+    let newWin = docShell.rootTreeItem.domWindow.openDialog(xulWinURL, "chrome_window", "chrome");
     loadListener(newWin, function () {
       let frame = newWin.document.createXULElement("iframe");
       frame.setAttribute("type", "content");
       frame.setAttribute("src", "javascript:'1';");
       loadListener(frame, function () {
         is(frame.contentWindow.document.body.textContent, "1", "content viewer was created");
         SimpleTest.executeSoon(function () {
           newWin.close();
--- a/dom/base/test/chrome/cpows_parent.xul
+++ b/dom/base/test/chrome/cpows_parent.xul
@@ -13,29 +13,29 @@
     const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
     var test_state = "remote";
     var test_node = null;
     var reentered = false;
     var savedMM = null;
 
     function info(message) {
-      return opener.wrappedJSObject.info(message);
+      return window.arguments[0].info(message);
     }
 
     function ok(condition, message) {
-      return opener.wrappedJSObject.ok(condition, message);
+      return window.arguments[0].ok(condition, message);
     }
 
     function is(v1, v2, message) {
-      return opener.wrappedJSObject.is(v1, v2, message);
+      return window.arguments[0].is(v1, v2, message);
     }
 
     function todo_is(v1, v2, message) {
-      return opener.wrappedJSObject.todo_is(v1, v2, message);
+      return window.arguments[0].todo_is(v1, v2, message);
     }
 
     // Make sure that an error in this file actually causes the test to fail.
     var gReceivedErrorProbe = false;
     window.onerror = function (msg, url, line) {
       if (/Test Error Probe/.test(msg)) {
         gReceivedErrorProbe = true;
         return;
@@ -406,33 +406,33 @@
       try {
         msg.objects.f();
       } catch (e) {
         if (!/unsafe CPOW usage forbidden/.test(String(e))) {
           throw e;
         }
         failed = true;
       }
-      opener.wrappedJSObject.SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN);
+      window.arguments[0].SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN);
       ok(failed, "CPOW should fail when unsafe");
       msg.target.messageManager.sendAsyncMessage("cpows:unsafe_done");
     }
 
     function recvSafe(msg) {
       const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser";
       Services.prefs.setBoolPref(PREF_UNSAFE_FORBIDDEN, true);
       try {
         msg.objects.f();
       } catch (e) {
         if (!/unsafe CPOW usage forbidden/.test(String(e))) {
           throw e;
         }
         ok(false, "cpow failed");
       }
-      opener.wrappedJSObject.SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN);
+      window.arguments[0].SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN);
       msg.target.messageManager.sendAsyncMessage("cpows:safe_done");
     }
 
     function recvDead(msg) {
       // Need to do this in a separate turn of the event loop.
       setTimeout(() => {
         msg.objects.gcTrigger();
         try {
@@ -507,16 +507,16 @@
       BrowserTestUtils.loadURI(browser, "http://mochi.test:8888/tests/dom/base/test/chrome/cpows_child.html");
       await BrowserTestUtils.browserLoaded(browser);
 
       run_tests('remote');
     }
 
     function finish() {
       ok(gReceivedErrorProbe, "Should have reported error probe");
-      opener.setTimeout(function() { this.done(); }, 0);
+      window.arguments[0].setTimeout(function() { this.done(); }, 0);
       window.close();
     }
   ]]></script>
 
   <browser type="content" src="about:blank" id="cpowbrowser_remote" remote="true"/>
   <browser type="content" src="about:blank" id="cpowbrowser_inprocess"/>
 </window>
--- a/dom/base/test/chrome/file_bug1139964.xul
+++ b/dom/base/test/chrome/file_bug1139964.xul
@@ -9,17 +9,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   onload="run()">
   <label value="Mozilla Bug 1139964"/>
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
   var ppm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService();
 
   function ok(cond, msg) {
-    opener.wrappedJSObject.ok(cond, msg);
+    window.arguments[0].ok(cond, msg);
   }
 
   var msgName = "TEST:Global_has_Promise";
 
   function mmScriptForPromiseTest() {
     sendAsyncMessage("TEST:Global_has_Promise",
                      {
                        hasPromise: ("Promise" in this),
@@ -39,17 +39,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   }
 
   function tabListener(m) {
     messageManager.removeMessageListener(msgName, tabListener);
     ok(m.data.hasPromise, "BrowserChildGlobal should have Promise object in the global scope!");
     ok(m.data.hasTextEncoder, "BrowserChildGlobal should have TextEncoder object in the global scope!");
     ok(m.data.hasWindow, "BrowserChildGlobal should have Window object in the global scope!");
 
-    opener.setTimeout(function() { this.done(); }, 0);
+    window.arguments[0].setTimeout(function() { this.done(); }, 0);
     window.close();
   }
 
   function run() {
     ppm.addMessageListener(msgName, processListener)
     ppm.loadProcessScript("data:,(" + mmScriptForPromiseTest.toString() + ")()", true);
   }
 
--- a/dom/base/test/chrome/file_bug1209621.xul
+++ b/dom/base/test/chrome/file_bug1209621.xul
@@ -7,21 +7,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <window title="Mozilla Bug 1209621"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   onload="run()">
   <label value="Mozilla Bug 1209621"/>
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
   function ok(cond, msg) {
-    opener.wrappedJSObject.ok(cond, msg);
+    window.arguments[0].ok(cond, msg);
   }
 
   function is(actual, expected, msg) {
-    opener.wrappedJSObject.is(actual, expected, msg);
+    window.arguments[0].is(actual, expected, msg);
   }
 
   function run() {
     var docshell = window.docShell;
     ok(docshell, "Active window should have a DocShell");
     var treeOwner = docshell.treeOwner;
     ok(treeOwner, "Active docshell should have a TreeOwner!");
 
@@ -59,17 +59,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     remote2.setAttribute("primary", "true");
     var tp2 = remote2.frameLoader.remoteTab;
     ok(tp2, "Remote browsers should have a remoteTab.");
     is(treeOwner.primaryRemoteTab, tp2,
        "primary remote browser should be the primaryRemoteTab.");
     is(treeOwner.primaryContentShell, null,
        "There shouldn't be primaryContentShell because no browser has primary=true.");
 
-    opener.setTimeout(function() { this.done(); }, 0);
+    window.arguments[0].setTimeout(function() { this.done(); }, 0);
     window.close();
   }
 
   ]]></script>
   <browser type="content" src="about:blank" id="inprocess"/>
   <browser type="content" remote="true" src="about:blank" id="remote"/>
   <browser type="content" remote="true" src="about:blank" id="remote2"/>
 </window>
--- a/dom/base/test/chrome/file_bug549682.xul
+++ b/dom/base/test/chrome/file_bug549682.xul
@@ -14,21 +14,21 @@ https://bugzilla.mozilla.org/show_bug.cg
   var didRunAsync = false;
   var didRunLocal = false;
 
   var global = Cc["@mozilla.org/globalmessagemanager;1"].getService();
   var ppm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService();
   var cpm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService();
 
   function ok(cond, msg) {
-    opener.wrappedJSObject.ok(cond, msg);
+    window.arguments[0].ok(cond, msg);
   }
 
   function is(actual, expected, msg) {
-    opener.wrappedJSObject.is(actual, expected, msg);
+    window.arguments[0].is(actual, expected, msg);
   }
 
   var asyncPPML = false;
   function ppmASL(m) {
     asyncPPML = true;
   }
   var syncPPML = false;
   function ppmSL(m) {
@@ -114,17 +114,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   };
 
   function weakDoneListener() {
     ok(weakMessageReceived, 'Got "weak" message.');
     finish();
   }
 
   function finish() {
-    opener.setTimeout(function() { this.done(); }, 0);
+    window.arguments[0].setTimeout(function() { this.done(); }, 0);
     var i = document.getElementById("ifr");
     i.remove(); // This is a crash test!
     window.close();
   }
 
   function loadScript() {
     // Async should be processed first!
     messageManager.loadFrameScript("data:,\
--- a/dom/base/test/chrome/file_bug616841.xul
+++ b/dom/base/test/chrome/file_bug616841.xul
@@ -33,31 +33,31 @@ https://bugzilla.mozilla.org/show_bug.cg
         messageManager.broadcastAsyncMessage("cmp",
                                              { i: i, a: pair[0], b: pair[1] });
       }
     }
 
     function recvCmp(m) {
       var i = m.json.i, cmp = m.json.cmp;
       var pair = toCompare[i];
-      opener.wrappedJSObject.is(pair[0].localeCompare(pair[1]), cmp, "localeCompare returned same result in frame script");
+      window.arguments[0].is(pair[0].localeCompare(pair[1]), cmp, "localeCompare returned same result in frame script");
 
       if (toCompare.length == ++nCmps) {
          messageManager.removeMessageListener("cmp", recvCmp);
         finish();
       }
     }
 
     function start() {
       messageManager.addMessageListener("contentReady", recvContentReady);
       messageManager.addMessageListener("cmp", recvCmp);
       messageManager.loadFrameScript(FRAME_SCRIPT, true);
     }
 
     function finish() {
-      opener.setTimeout(function() { this.done(); }, 0);
+      window.arguments[0].setTimeout(function() { this.done(); }, 0);
       window.close();
     }
 
   ]]></script>
 
   <browser id="browser" type="content" src="about:blank"/>
 </window>
--- a/dom/base/test/chrome/file_bug816340.xul
+++ b/dom/base/test/chrome/file_bug816340.xul
@@ -8,17 +8,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <window title="Mozilla Bug 816340"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   onload="start();">
   <label value="Mozilla Bug 816340"/>
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
     function ok(val, msg) {
-      opener.wrappedJSObject.ok(val, msg);
+      window.arguments[0].ok(val, msg);
     }
 
     var elems = 
       [
         "input",
         "textarea",
         "select",
         "fieldset",
@@ -55,16 +55,16 @@ https://bugzilla.mozilla.org/show_bug.cg
       testElement("div", false, true);
       testElement("div", true, true);
 
       for (var i = 0; i < elems.length; ++i) {
         testElement(elems[i], false, true);
         testElement(elems[i], true, false);
       }
       ok(true, "done");
-      opener.setTimeout(function() { this.done(); }, 0);
+      window.arguments[0].setTimeout(function() { this.done(); }, 0);
       window.close();
     }
 
   ]]></script>
 
   <browser id="browser" type="content" src="about:blank"/>
 </window>
--- a/dom/base/test/chrome/file_bug990812-1.xul
+++ b/dom/base/test/chrome/file_bug990812-1.xul
@@ -14,17 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     var FRAME_SCRIPT_GLOBAL = "data:,sendSyncMessage('test', 'global')";
     var FRAME_SCRIPT_WINDOW = "data:,sendSyncMessage('test', 'window')";
     var FRAME_SCRIPT_GROUP  = "data:,sendSyncMessage('test', 'group')";
 
     var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
 
     function is(val, exp, msg) {
-      opener.wrappedJSObject.is(val, exp, msg);
+      window.arguments[0].is(val, exp, msg);
     }
 
     /**
      * Ensures that delayed frame scripts are loaded in the expected order.
      * Global frame scripts will be loaded before delayed frame scripts from
      * window message managers. The latter will be loaded before group message
      * manager frame scripts.
      */
@@ -32,20 +32,20 @@ https://bugzilla.mozilla.org/show_bug.cg
       globalMM.loadFrameScript(FRAME_SCRIPT_GLOBAL, true);
       messageManager.loadFrameScript(FRAME_SCRIPT_WINDOW, true);
       getGroupMessageManager("test").loadFrameScript(FRAME_SCRIPT_GROUP, true);
 
       var order = ["global", "window", "group"];
 
       messageManager.addMessageListener("test", function onMessage(msg) {
         var next = order.shift();
-        opener.wrappedJSObject.is(msg.data, next, "received test:" + next);
+        window.arguments[0].is(msg.data, next, "received test:" + next);
 
         if (order.length == 0) {
-          opener.setTimeout(function() { this.next(); });
+          window.arguments[0].setTimeout(function() { this.next(); });
           window.close();
         }
       });
 
       var browser = document.createXULElement("browser");
       browser.setAttribute("messagemanagergroup", "test");
       browser.setAttribute("src", "about:mozilla");
       browser.setAttribute("type", "content");
--- a/dom/base/test/chrome/file_bug990812-2.xul
+++ b/dom/base/test/chrome/file_bug990812-2.xul
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"><![CDATA[
 
     var FRAME_SCRIPT = "data:,sendAsyncMessage('test')";
     var order = ["group", "window", "global"];
 
     var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
 
     function is(val, exp, msg) {
-      opener.wrappedJSObject.is(val, exp, msg);
+      window.arguments[0].is(val, exp, msg);
     }
 
     function promiseMessage(type, mm) {
       return new Promise(function (resolve) {
         mm.addMessageListener("test", function onMessage() {
           mm.removeMessageListener("test", onMessage);
           is(type, order.shift(), "correct type " + type);
           resolve();
@@ -39,17 +39,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       var global = promiseMessage("global", globalMM);
       var window = promiseMessage("window", messageManager);
       var group = promiseMessage("group", getGroupMessageManager("test"));
 
       var browser = document.querySelector("browser");
       browser.messageManager.loadFrameScript(FRAME_SCRIPT, true);
 
       Promise.all([global, window, group]).then(function () {
-        opener.setTimeout(function() { this.next(); });
+        self.arguments[0].setTimeout(function() { this.next(); });
         self.close();
       });
     }
 
   ]]></script>
 
   <browser messagemanagergroup="test" type="content" src="about:mozilla" />
 
--- a/dom/base/test/chrome/file_bug990812-3.xul
+++ b/dom/base/test/chrome/file_bug990812-3.xul
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"><![CDATA[
 
     var FRAME_SCRIPT = "data:,addMessageListener('test', function (msg) {" +
                        "sendSyncMessage('test', msg.data)})";
 
     var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
 
     function is(val, exp, msg) {
-      opener.wrappedJSObject.is(val, exp, msg);
+      window.arguments[0].is(val, exp, msg);
     }
 
     function promiseMessage(type, mm) {
       var order = [type, "window", "global"];
 
       return new Promise(function (resolve) {
         mm.addMessageListener("test", function onMessage(msg) {
           is(msg.data, order.shift(), "correct message " + msg.data);
@@ -50,17 +50,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       mm2.loadFrameScript(FRAME_SCRIPT, true);
 
       getGroupMessageManager("test1").broadcastAsyncMessage("test", "group1");
       getGroupMessageManager("test2").broadcastAsyncMessage("test", "group2");
       messageManager.broadcastAsyncMessage("test", "window");
       globalMM.broadcastAsyncMessage("test", "global");
 
       Promise.all([promise1, promise2]).then(function () {
-        opener.setTimeout(function() { this.next(); });
+        window.arguments[0].setTimeout(function() { this.next(); });
         window.close();
       });
     }
 
   ]]></script>
 
   <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
   <browser messagemanagergroup="test2" type="content" src="about:mozilla" />
--- a/dom/base/test/chrome/file_bug990812-4.xul
+++ b/dom/base/test/chrome/file_bug990812-4.xul
@@ -15,17 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     var FRAME_SCRIPT1 = "data:,addMessageListener('test', function () {" +
                         "sendSyncMessage('test', 'frame1')})";
     var FRAME_SCRIPT2 = "data:,addMessageListener('test', function () {" +
                         "sendSyncMessage('test', 'frame2')})";
 
     var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
 
     function is(val, exp, msg) {
-      opener.wrappedJSObject.is(val, exp, msg);
+      window.arguments[0].is(val, exp, msg);
     }
 
     function promiseMessage(type, mm) {
       return new Promise(function (resolve) {
         mm.addMessageListener("test", function onMessage(msg) {
           mm.removeMessageListener("test", onMessage);
           is(msg.data, type, "correct message " + type);
           resolve();
@@ -45,17 +45,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       var promise1 = promiseMessage("frame2", getGroupMessageManager("test1"));
       var promise2 = promiseMessage("frame1", getGroupMessageManager("test2"));
 
       browser1.swapFrameLoaders(browser2);
       messageManager.broadcastAsyncMessage("test");
 
       Promise.all([promise1, promise2]).then(function () {
-        opener.setTimeout(function() { this.next(); });
+        window.arguments[0].setTimeout(function() { this.next(); });
         window.close();
       });
     }
 
   ]]></script>
 
   <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
   <browser messagemanagergroup="test2" type="content" src="about:mozilla" />
--- a/dom/base/test/chrome/file_bug990812-5.xul
+++ b/dom/base/test/chrome/file_bug990812-5.xul
@@ -15,17 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     var FRAME_SCRIPT1 = "data:,addMessageListener('test', function () {" +
                         "sendSyncMessage('test', 'group1')})";
     var FRAME_SCRIPT2 = "data:,addMessageListener('test', function () {" +
                         "sendSyncMessage('test', 'group2')})";
 
     var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
 
     function is(val, exp, msg) {
-      opener.wrappedJSObject.is(val, exp, msg);
+      window.arguments[0].is(val, exp, msg);
     }
 
     function promiseTwoMessages(type, mm) {
       var numLeft = 2;
 
       return new Promise(function (resolve) {
         mm.addMessageListener("test", function onMessage(msg) {
           is(msg.data, type, "correct message " + type);
@@ -53,17 +53,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       gmm2.loadFrameScript(FRAME_SCRIPT2, true);
 
       var promise1 = promiseTwoMessages("group1", gmm1);
       var promise2 = promiseTwoMessages("group2", gmm2);
 
       messageManager.broadcastAsyncMessage("test");
 
       Promise.all([promise1, promise2]).then(function () {
-        opener.setTimeout(function() { this.next(); });
+        window.arguments[0].setTimeout(function() { this.next(); });
         window.close();
       });
     }
 
   ]]></script>
 
   <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
   <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
--- a/dom/base/test/chrome/test_bug1139964.xul
+++ b/dom/base/test/chrome/test_bug1139964.xul
@@ -21,12 +21,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   /** Test for Bug 1139964 **/
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("file_bug1139964.xul", "", "chrome");
+    window.openDialog("file_bug1139964.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/dom/base/test/chrome/test_bug1209621.xul
+++ b/dom/base/test/chrome/test_bug1209621.xul
@@ -21,14 +21,14 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("file_bug1209621.xul", "", "chrome");
+    window.openDialog("file_bug1209621.xul", "", "chrome,noopener", window);
   });
 
   ]]>
   </script>
 </window>
--- a/dom/base/test/chrome/test_bug549682.xul
+++ b/dom/base/test/chrome/test_bug549682.xul
@@ -21,12 +21,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   /** Test for Bug 549682 **/
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("file_bug549682.xul", "", "chrome");
+    window.openDialog("file_bug549682.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/dom/base/test/chrome/test_bug616841.xul
+++ b/dom/base/test/chrome/test_bug616841.xul
@@ -19,12 +19,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"><![CDATA[
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("file_bug616841.xul", "", "chrome");
+    window.openDialog("file_bug616841.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/dom/base/test/chrome/test_bug814638.xul
+++ b/dom/base/test/chrome/test_bug814638.xul
@@ -18,18 +18,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript">
   <![CDATA[
   /** Test for Bug 814638 **/
 
   SimpleTest.waitForExplicitFinish();
 
   function startTest() {
     let hostURL = "chrome://mochitests/content/chrome/dom/base/test/chrome/host_bug814638.xul";
-    let host1 = window.open(hostURL, "_blank", "chrome");
-    let host2 = window.open(hostURL, "_blank", "chrome");
+    let host1 = docShell.rootTreeItem.domWindow.open(hostURL, "_blank", "chrome");
+    let host2 = docShell.rootTreeItem.domWindow.open(hostURL, "_blank", "chrome");
 
     let isHost1Loaded = isHost2Loaded = false
     host1.onload = function() {
       isHost1Loaded = true;
       if (isHost2Loaded) swapFrames();
     }
     host2.onload = function() {
       isHost2Loaded = true;
--- a/dom/base/test/chrome/test_bug816340.xul
+++ b/dom/base/test/chrome/test_bug816340.xul
@@ -19,12 +19,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"><![CDATA[
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("file_bug816340.xul", "", "chrome");
+    window.openDialog("file_bug816340.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/dom/base/test/chrome/test_bug990812.xul
+++ b/dom/base/test/chrome/test_bug990812.xul
@@ -26,17 +26,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     "file_bug990812-4.xul",
     "file_bug990812-5.xul",
   ];
 
   function next() {
     if (tests.length > 0) {
       var file = tests.shift();
       info("-- running " + file);
-      window.open(file, "", "chrome");
+      window.openDialog(file, "_blank", "chrome,noopener", window);
     } else {
       SimpleTest.finish();
     }
   }
 
   addLoadEvent(next);
   ]]></script>
 </window>
--- a/dom/base/test/chrome/test_chromeOuterWindowID.xul
+++ b/dom/base/test/chrome/test_chromeOuterWindowID.xul
@@ -67,17 +67,17 @@ windows.
    * @returns Promise
    *        The Promise resolves with an object with the following properties:
    *
    *        win<num>: a reference to the opened window
    *        remote<num>: a reference to the remote browser in the window
    *        nonRemote<num>: a reference to the non-remote browser in the window
    */
   async function prepareWindow(num, page) {
-    let win = window.open(BROWSER_DOC, "bug1474662-" + num, "chrome,width=200,height=200");
+    let win = docShell.rootTreeItem.domWindow.open(BROWSER_DOC, "bug1474662-" + num, "chrome,width=200,height=200");
     await BrowserTestUtils.waitForEvent(win, "load");
     let remote = win.document.getElementById("remote");
     let nonRemote = win.document.getElementById("non-remote");
 
     ok(remote && remote.isRemoteBrowser,
        "Should have found a remote browser in test window " + num);
     ok(nonRemote && !nonRemote.isRemoteBrowser,
        "Should have found a non-remote browser in test window " + num);
--- a/dom/base/test/chrome/test_cpows.xul
+++ b/dom/base/test/chrome/test_cpows.xul
@@ -23,12 +23,12 @@
     Services.prefs.clearUserPref(PREF_UNSAFE_FORBIDDEN);
   });
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("cpows_parent.xul", "", "chrome");
+    window.openDialog("cpows_parent.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/dom/base/test/chrome/test_document-element-inserted.xul
+++ b/dom/base/test/chrome/test_document-element-inserted.xul
@@ -32,17 +32,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         }, "document-element-inserted");
       })
     }
 
     // Load a XUL document that also has an iframe to a subdocument, and
     // expect both events to fire with the docs in the correct state.
     async function testEvents() {
       info(`Waiting for events after loading ${OUTER_URL}`);
-      let win = window.openDialog(OUTER_URL, null, "chrome,dialog=no,all");
+      let win = docShell.rootTreeItem.domWindow.openDialog(OUTER_URL, "_blank", "chrome,dialog=no,all");
       await waitForEvent(OUTER_URL);
       await waitForEvent(INNER_URL);
       win.close();
     }
 
     (async function() {
       // Test the same document twice to make to make sure we are
       // firing properly when loading the protype document.
--- a/dom/base/test/chrome/test_nsITextInputProcessor.xul
+++ b/dom/base/test/chrome/test_nsITextInputProcessor.xul
@@ -16,14 +16,14 @@
 <pre id="test">
 </pre>
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 SimpleTest.waitForExplicitFinish();
-window.open("window_nsITextInputProcessor.xul", "_blank", 
-            "chrome,width=600,height=600");
+window.openDialog("window_nsITextInputProcessor.xul", "_blank", 
+                  "chrome,width=600,height=600,noopener", window);
 
 ]]>
 </script>
 </window>
--- a/dom/base/test/chrome/test_swapFrameLoaders.xul
+++ b/dom/base/test/chrome/test_swapFrameLoaders.xul
@@ -14,12 +14,12 @@ Test swapFrameLoaders with different fra
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1242644"
      target="_blank">Mozilla Bug 1242644</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
   SimpleTest.waitForExplicitFinish();
 
-  window.open("window_swapFrameLoaders.xul", "bug1242644",
-              "chrome,width=600,height=600");
+  window.openDialog("window_swapFrameLoaders.xul", "bug1242644",
+                    "chrome,width=600,height=600,noopener", window);
   ]]></script>
 </window>
--- a/dom/base/test/chrome/test_title.xul
+++ b/dom/base/test/chrome/test_title.xul
@@ -17,13 +17,13 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
 
   /** Test for Bug 481777 **/
 
     SimpleTest.waitForExplicitFinish();
-    window.open("title_window.xul", "bug481777",
-                "chrome,width=100,height=100");
+    window.openDialog("title_window.xul", "bug481777",
+                      "chrome,width=100,height=100,noopener", window);
   ]]>
   </script>
 </window>
--- a/dom/base/test/chrome/title_window.xul
+++ b/dom/base/test/chrome/title_window.xul
@@ -17,17 +17,17 @@
   <iframe id="xul2" src="file_title.xul"/>
   <iframe type="content" id="svg1" src="data:text/xml,&lt;svg xmlns='http://www.w3.org/2000/svg'&gt;&lt;title id='t'&gt;Test&lt;/title&gt;&lt;/svg&gt;"/>
   <iframe type="content" id="svg2" src="data:text/xml,&lt;svg xmlns='http://www.w3.org/2000/svg'&gt;&lt;title id='t'&gt;Test&lt;/title&gt;&lt;/svg&gt;"/>
 
   <script type="application/javascript">
     <![CDATA[
     var imports = [ "SimpleTest", "is", "isnot", "ok" ];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
 
     function testStatics() {
       function testStatic(id, expect, description) {
         is(document.getElementById(id).contentDocument.title, expect, description);
       }
 
       testStatic("html1", "Test", "HTML <title>");
--- a/dom/base/test/chrome/window_nsITextInputProcessor.xul
+++ b/dom/base/test/chrome/window_nsITextInputProcessor.xul
@@ -20,17 +20,17 @@
 </pre>
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+var SimpleTest = window.arguments[0].SimpleTest;
 
 SimpleTest.waitForFocus(runTests, window);
 
 function ok(aCondition, aMessage)
 {
   SimpleTest.ok(aCondition, aMessage);
 }
 
@@ -73,17 +73,17 @@ function checkInputEvent(aEvent, aIsComp
 }
 
 const kIsMac = (navigator.platform.indexOf("Mac") == 0);
 
 var iframe = document.getElementById("iframe");
 var childWindow = iframe.contentWindow;
 var textareaInFrame;
 var input = document.getElementById("input");
-var otherWindow = window.opener;
+var otherWindow = window.arguments[0];
 var otherDocument = otherWindow.document;
 var inputInChildWindow = otherDocument.getElementById("input");
 
 function createTIP()
 {
   return Cc["@mozilla.org/text-input-processor;1"].
            createInstance(Ci.nsITextInputProcessor);
 }
--- a/dom/base/test/chrome/window_swapFrameLoaders.xul
+++ b/dom/base/test/chrome/window_swapFrameLoaders.xul
@@ -5,17 +5,17 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=1242644
 Test swapFrameLoaders with different frame types and remoteness
 -->
 <window title="Mozilla Bug 1242644"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/javascript"><![CDATA[
   ["SimpleTest", "SpecialPowers", "info", "is", "ok", "add_task"].forEach(key => {
-    window[key] = window.opener[key];
+    window[key] = window.arguments[0][key];
   })
 
   const NS = {
     xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
     html: "http://www.w3.org/1999/xhtml",
   }
 
   const TAG = {
--- a/dom/base/test/test_bug1016960.html
+++ b/dom/base/test/test_bug1016960.html
@@ -7,18 +7,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <meta charset="utf-8">
   <title>Test for Bug 1016960</title>
   <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
 
   /** Test for Bug 1016960 **/
 
-  var chromeWindow = window.open("chrome://mochitests/content/chrome/dom/base/test/file_empty.html", "1016960", "chrome");
-  ok(chromeWindow.isChromeWindow, "A chrome window should return true for |instanceof ChromeWindow|.");
+  var chromeWindow = docShell.rootTreeItem.domWindow.open("chrome://mochitests/content/chrome/dom/base/test/file_empty.html", "1016960", "chrome");
+  ok(chromeWindow.isChromeWindow, "A chrome window should return true for .isChromeWindow.");
   chromeWindow.close();
 
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1016960">Mozilla Bug 1016960</a>
 <p id="display"></p>
 <div id="content" style="display: none">
--- a/dom/canvas/test/chrome/test_drawWindow_widget_layers.html
+++ b/dom/canvas/test/chrome/test_drawWindow_widget_layers.html
@@ -24,18 +24,18 @@
     // for regular windows.
     // (The reftest framework doesn't have this problem because it doesn't use
     // a regular window with a titlebar, so there are no rounded corners.)
     const WINDOW_INNER_WIDTH = CANVAS_WIDTH;
     const WINDOW_INNER_HEIGHT = CANVAS_HEIGHT + 10;
 
     // Need to open as a toplevel chrome window so that
     // DRAWWINDOW_USE_WIDGET_LAYERS is honored.
-    sourceWindow = window.open("file_drawWindow_source.html", "",
-                               `chrome,width=${WINDOW_INNER_WIDTH},height=${WINDOW_INNER_HEIGHT}`);
+    sourceWindow = docShell.rootTreeItem.domWindow.open("file_drawWindow_source.html", "",
+                                                        `chrome,width=${WINDOW_INNER_WIDTH},height=${WINDOW_INNER_HEIGHT}`);
     SimpleTest.waitForFocus(runTests, sourceWindow);
   }
 
   async function runTests() {
     var cxInterfaceWrap = SpecialPowers.wrap(CanvasRenderingContext2D);
     
     let snapshot = function(context, x, y, width, height, bg) {
       var flags = cxInterfaceWrap.DRAWWINDOW_USE_WIDGET_LAYERS |
--- a/dom/events/test/test_bug1412775.xul
+++ b/dom/events/test/test_bug1412775.xul
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
 
   /** Test for Bug 1412775 **/
   var win;
   function init() {
     SimpleTest.waitForExplicitFinish();
-    win = window.open("window_bug1412775.xul", "_new", "chrome");
+    win = docShell.rootTreeItem.domWindow.open("window_bug1412775.xul", "_new", "chrome");
     win.onload = function() {
       var b = win.document.getElementById("browser");
       var d = b.contentWindow.document;
       var e = new d.defaultView.Event("foo");
       var didCallChromeSide = false;
       var didCallContentSide = false;
       b.addEventListener("foo", function(e) {
         didCallChromeSide = true;
--- a/dom/events/test/test_bug617528.xul
+++ b/dom/events/test/test_bug617528.xul
@@ -16,17 +16,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   </body>
 
   <script type="application/javascript"><![CDATA[
     const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
     var _window;
     var browser;
 
     function start() {
-      _window = window.open("window_bug617528.xul", "_new", "chrome");
+      _window = docShell.rootTreeItem.domWindow.open("window_bug617528.xul", "_new", "chrome");
       _window.addEventListener("load", onLoad, false);
     }
 
     function onLoad() {
       _window.removeEventListener("load", onLoad, false);
 
       browser = _window.document.getElementById("browser");
       browser.addEventListener("pageshow", onPageShow, false);
--- a/dom/ipc/tests/process_error.xul
+++ b/dom/ipc/tests/process_error.xul
@@ -4,20 +4,20 @@
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
 	orient="vertical">
 
   <browser id="thebrowser" type="content" remote="true" />
   <script type="application/javascript"><![CDATA[
     const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
     const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
 
-    const ok = window.opener.wrappedJSObject.ok;
-    const is = window.opener.wrappedJSObject.is;
-    const done = window.opener.wrappedJSObject.done;
-    const SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+    const ok = window.arguments[0].ok;
+    const is = window.arguments[0].is;
+    const done = window.arguments[0].done;
+    const SimpleTest = window.arguments[0].SimpleTest;
 
     // Allow the browser to get connected before using the messageManager to cause
     // a crash:
     addEventListener("DOMContentLoaded", () => {
       let browser = document.getElementById('thebrowser');
 
       let observerPromise = new Promise(resolve => {
         let crashObserver = (subject, topic, data) => {
--- a/dom/ipc/tests/test_process_error.xul
+++ b/dom/ipc/tests/test_process_error.xul
@@ -4,17 +4,17 @@
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 
   <script>
   SimpleTest.waitForExplicitFinish();
   SimpleTest.expectChildProcessCrash();
 
-  var w = window.open('process_error.xul', '_blank', 'chrome,resizable=yes,width=400,height=600');
+  var w = docShell.rootTreeItem.domWindow.openDialog('process_error.xul', '_blank', 'chrome,resizable=yes,width=400,height=600', window);
 
   function done()
   {
     w.close();
     SimpleTest.finish();
   }
   </script>
 
--- a/dom/messagechannel/tests/mm_messageChannelParent.js
+++ b/dom/messagechannel/tests/mm_messageChannelParent.js
@@ -1,29 +1,29 @@
 let port;
 let mm;
 
 function info(message) {
-  return opener.wrappedJSObject.info(message);
+  return window.arguments[0].info(message);
 }
 
 function ok(condition, message) {
-  return opener.wrappedJSObject.ok(condition, message);
+  return window.arguments[0].ok(condition, message);
 }
 
 function is(v1, v2, message) {
-  return opener.wrappedJSObject.is(v1, v2, message);
+  return window.arguments[0].is(v1, v2, message);
 }
 
 function todo_is(v1, v2, message) {
-  return opener.wrappedJSObject.todo_is(v1, v2, message);
+  return window.arguments[0].todo_is(v1, v2, message);
 }
 
 function cleanUp() {
-  opener.setTimeout(function() {
+  window.arguments[0].setTimeout(function() {
     this.done();
   }, 0);
   window.close();
 }
 
 function debug(msg) {
   dump("[mmMessageChannelParent]" + msg + "\n");
 }
--- a/dom/messagechannel/tests/test_messageChannelWithMessageManager.xul
+++ b/dom/messagechannel/tests/test_messageChannelWithMessageManager.xul
@@ -16,12 +16,12 @@
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     info("done called");
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("mm_messageChannelParent.xul", "", "chrome");
+    window.openDialog("mm_messageChannelParent.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/dom/messagechannel/tests/test_messageChannelWithMessageManagerNotRemote.xul
+++ b/dom/messagechannel/tests/test_messageChannelWithMessageManagerNotRemote.xul
@@ -16,12 +16,12 @@
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     info("done called");
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("mm_messageChannelParentNotRemote.xul", "", "chrome");
+    window.openDialog("mm_messageChannelParentNotRemote.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xul
+++ b/dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xul
@@ -5,17 +5,17 @@
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
   <script type="application/javascript" src="plugin-utils.js"></script>
 
   <script>
   SimpleTest.waitForExplicitFinish();
   setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
 
-  var w = window.open('xulbrowser_plugin_visibility.xul', '_blank', 'chrome,resizable=yes,width=400,height=600');
+  var w = docShell.rootTreeItem.domWindow.openDialog('xulbrowser_plugin_visibility.xul', '_blank', 'chrome,resizable=yes,width=400,height=600', window);
 
   function done()
   {
     w.close();
     SimpleTest.finish();
   }
   </script>
 
--- a/dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xul
+++ b/dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xul
@@ -12,20 +12,20 @@
     <tabpanels flex="1">
       <browser id="browser1" type="content" primary="true" flex="1" src="about:blank"/>
       <browser id="browser2" type="content" primary="true" flex="1" src="about:blank"/>
     </tabpanels>
   </tabbox>
   <script type="application/javascript" src="plugin-utils.js"/>
   <script type="application/javascript"><![CDATA[
     const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
-    const ok = window.opener.wrappedJSObject.ok;
-    const is = window.opener.wrappedJSObject.is;
-    const done = window.opener.wrappedJSObject.done;
-    const SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+    const ok = window.arguments[0].ok;
+    const is = window.arguments[0].is;
+    const done = window.arguments[0].done;
+    const SimpleTest = window.arguments[0].SimpleTest;
 
     const nsIWebProgress = Ci.nsIWebProgress;
     const nsIWebProgressListener = Ci.nsIWebProgressListener;
 
     const kURI = 'http://mochi.test:8888/chrome/dom/plugins/test/mochitest/plugin_visibility_loader.html';
 
     function ProgressListener() {
     }
--- a/dom/tests/browser/browser_test_toolbars_visibility.js
+++ b/dom/tests/browser/browser_test_toolbars_visibility.js
@@ -223,26 +223,26 @@ add_task(async function() {
  * A window opened with "location=no, personalbar=no, toolbar=no, scrollbars=no,
  * menubar=no, status=no", should not have any toolbar visible.
  */
 add_task(async function() {
   // First open a default window from this chrome context
   let defaultWindowPromise = BrowserTestUtils.waitForNewWindow({
     url: TARGET_PAGE,
   });
-  window.open(TARGET_PAGE, "_blank");
+  window.open(TARGET_PAGE, "_blank", "noopener");
   let defaultWindow = await defaultWindowPromise;
 
   // Check that all toolbars are visible
   let toolbars = getToolbarsFromWindowChrome(defaultWindow);
   testDefaultToolbars(toolbars);
 
   // Now lets open a window with toolbars hidden from this chrome context
   let features =
-    "location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no";
+    "location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no, noopener";
   let popupWindowPromise = BrowserTestUtils.waitForNewWindow({
     url: TARGET_PAGE,
   });
   window.open(TARGET_PAGE, "_blank", features);
   let popupWindow = await popupWindowPromise;
 
   // Test none of the tooolbars are visible
   let hiddenToolbars = getToolbarsFromWindowChrome(popupWindow);
--- a/dom/tests/mochitest/chrome/DOMWindowCreated_chrome.xul
+++ b/dom/tests/mochitest/chrome/DOMWindowCreated_chrome.xul
@@ -7,17 +7,17 @@
 <window id="sample-window" width="400" height="400"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" 
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" 
           src="chrome://mochikit/content/chrome-harness.js"></script>
 
 <script type="application/javascript">
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+var SimpleTest = window.arguments[0].SimpleTest;
 
 document.addEventListener("DOMWindowCreated", function(e) {
   var otherWindow = e.target.defaultView.wrappedJSObject;
   SimpleTest.is(e.type, "DOMWindowCreated", "DOMWindowCreated: " + otherWindow);
   otherWindow.doneFunction = function() {
     SimpleTest.ok(true, "doneFunction was called");
     SimpleTest.finish();
     window.close();
--- a/dom/tests/mochitest/chrome/MozDomFullscreen_chrome.xul
+++ b/dom/tests/mochitest/chrome/MozDomFullscreen_chrome.xul
@@ -21,21 +21,21 @@
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="start();">
 
 <script src="chrome://mochikit/content/chrome-harness.js"></script>
 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
 <script type="application/javascript"><![CDATA[
 
 function ok(condition, msg) {
-  window.opener.wrappedJSObject.ok(condition, msg);
+  window.arguments[0].ok(condition, msg);
 }
 
 function is(a, b, msg) {
-  window.opener.wrappedJSObject.is(a, b, msg);
+  window.arguments[0].is(a, b, msg);
 }
 
 var gBrowser = null;
 var gOuterDoc = null;
 var gInnerDoc = null;
 
 var gReceivedFullscreenEnteredEvent = false;
 var gReceivedNewOriginEvent = false;
@@ -83,17 +83,17 @@ function thirdEntry(event) {
 
 function earlyExit(event) {
   ok(false, "MozDOMFullscreen:Exited should only be triggered after cancel all fullscreen");
 }
 
 function lastExit(event) {
   is(event.target, gOuterDoc, "MozDOMFullscreen:Exited should be targeted at the last exited doc");
   ok(gOuterDoc.fullscreenElement == null, "Fullscreen should have been fully exited");
-  window.opener.wrappedJSObject.done();
+  window.arguments[0].done();
 }
 
 function start() {
   SimpleTest.waitForFocus(
     function() {
       gBrowser = document.getElementById("browser");
       gOuterDoc = gBrowser.contentDocument;
       gBrowser.contentWindow.focus();
--- a/dom/tests/mochitest/chrome/file_DOM_element_instanceof.xul
+++ b/dom/tests/mochitest/chrome/file_DOM_element_instanceof.xul
@@ -3,30 +3,30 @@
 <window title="Mozilla Bug 824917"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <iframe type="content"></iframe>
 
   <script type="application/javascript">
   <![CDATA[
   /** Test for Bug 799299 **/
-  var SimpleTest = opener.wrappedJSObject.SimpleTest;
-  var ok = opener.wrappedJSObject.ok;
+  var SimpleTest = window.arguments[0].SimpleTest;
+  var ok = window.arguments[0].ok;
 
   // Note: We can't use frames[0] here because the type="content" attribute
   // isolates it into a separate browsing context hierarchy.
   var doc = document.querySelector("iframe").contentDocument;
   ok(doc.createElement("body") instanceof HTMLBodyElement,
      "Should be instance of HTMLBodyElement");
   ok(doc.createElement("div") instanceof HTMLDivElement,
      "Should be instance of HTMLDivElement");
   ok(doc.createElement("frameset") instanceof HTMLFrameSetElement,
      "Should be instance of HTMLFrameSetElement");
   ok(doc.createElement("h1") instanceof HTMLHeadingElement,
      "Should be instance of HTMLHeadingElement");
   ok(doc.createElement("label") instanceof HTMLLabelElement,
      "Should be instance of HTMLLabelElement");
 
   window.close();
-  opener.wrappedJSObject.SimpleTest.finish();
+  window.arguments[0].SimpleTest.finish();
   ]]>
   </script>
 </window>
--- a/dom/tests/mochitest/chrome/file_bug1224790-1_modal.xul
+++ b/dom/tests/mochitest/chrome/file_bug1224790-1_modal.xul
@@ -19,15 +19,15 @@ https://bugzilla.mozilla.org/show_bug.cg
   /** Test for Bug 1224790 **/
 
   function runTests() {
     window.openDialog('file_bug1224790-1_nonmodal.xul', '', 'dialog=no');
   }
 
   function nonModalClosed() {
     window.close();
-    opener.wrappedJSObject.modalClosed();
+    window.arguments[0].modalClosed();
   }
 
   SimpleTest.waitForFocus(runTests);
   ]]>
   </script>
 </dialog>
--- a/dom/tests/mochitest/chrome/file_bug1224790-2_modal.xul
+++ b/dom/tests/mochitest/chrome/file_bug1224790-2_modal.xul
@@ -21,15 +21,15 @@ https://bugzilla.mozilla.org/show_bug.cg
   var nonModal = null;
 
   function runTests() {
     nonModal = window.openDialog('file_bug1224790-2_nonmodal.xul', '', 'dialog=no');
   }
 
   function nonModalOpened() {
     window.close();
-    nonModal.wrappedJSObject.modalClosed(opener);
+    nonModal.modalClosed(window.arguments[0]);
   }
 
   SimpleTest.waitForFocus(runTests);
   ]]>
   </script>
 </dialog>
--- a/dom/tests/mochitest/chrome/file_bug799299.xul
+++ b/dom/tests/mochitest/chrome/file_bug799299.xul
@@ -25,39 +25,39 @@ https://bugzilla.mozilla.org/show_bug.cg
     wu.sendMouseEventToWindow("mousedown", 10, 10, 0, 0, 0);
     wu.sendMouseEventToWindow("mouseup", 10, 10, 0, 0, 0);
   }
 
   function runTests() {
     var b1 = document.getElementById("b1");
     var b2 = document.getElementById("b2");
     b1.contentWindow.focus();
-    opener.wrappedJSObject.is(document.activeElement, b1,
-                              "Focused first iframe");
+    window.arguments[0].is(document.activeElement, b1,
+                           "Focused first iframe");
 
     var didCallDummy = false;
     b2.contentWindow.addEventListener("mousedown", function(e) { didCallDummy = true; });
     sendClick(b2.contentWindow);
-    opener.wrappedJSObject.ok(didCallDummy, "dummy mousedown handler should fire");
-    opener.wrappedJSObject.is(document.activeElement, b2,
-                              "Focus shifted to second iframe");
+    window.arguments[0].ok(didCallDummy, "dummy mousedown handler should fire");
+    window.arguments[0].is(document.activeElement, b2,
+                           "Focus shifted to second iframe");
 
     b1.contentWindow.focus();
-    opener.wrappedJSObject.is(document.activeElement, b1,
-                              "Re-focused first iframe for the first time");
+    window.arguments[0].is(document.activeElement, b1,
+                           "Re-focused first iframe for the first time");
 
     var didCallListener = false;
     b2.contentWindow.addEventListener("mousedown", function(e) { didCallListener = true; e.preventDefault(); });
     sendClick(b2.contentWindow);
-    opener.wrappedJSObject.ok(didCallListener, "mousedown handler should fire");
-    opener.wrappedJSObject.is(document.activeElement, b2,
-                              "focus should move to the second iframe");
+    window.arguments[0].ok(didCallListener, "mousedown handler should fire");
+    window.arguments[0].is(document.activeElement, b2,
+                           "focus should move to the second iframe");
 
     window.close();
-    opener.wrappedJSObject.SimpleTest.finish();
+    window.arguments[0].SimpleTest.finish();
   }
 
   SimpleTest.waitForFocus(runTests);
   ]]>
   </script>
   <hbox flex="1">
     <browser id="b1" type="content" src="about:blank" flex="1" style="border: 1px solid black;"/>
     <browser id="b2" type="content" src="about:blank" flex="1" style="border: 1px solid black;"/>
--- a/dom/tests/mochitest/chrome/file_bug800817.xul
+++ b/dom/tests/mochitest/chrome/file_bug800817.xul
@@ -25,51 +25,51 @@ https://bugzilla.mozilla.org/show_bug.cg
     wu.sendMouseEventToWindow("mousedown", 10, 10, 0, 0, 0);
     wu.sendMouseEventToWindow("mouseup", 10, 10, 0, 0, 0);
   }
 
   function runTests() {
     var b1 = document.getElementById("b1");
     var b2 = document.getElementById("b2");
 
-    var testMozBrowser = opener.wrappedJSObject.testMozBrowser;
+    var testMozBrowser = window.arguments[0].testMozBrowser;
     if (testMozBrowser) {
       b1.setAttribute("mozbrowser", "true");
       b2.setAttribute("mozbrowser", "true");
     }
 
     if (testMozBrowser)
-      opener.wrappedJSObject.info("Testing with mozbrowser=true");
+      window.arguments[0].info("Testing with mozbrowser=true");
     else
-      opener.wrappedJSObject.info("Testing without mozbrowser");
+      window.arguments[0].info("Testing without mozbrowser");
 
     b1.contentWindow.focus();
-    opener.wrappedJSObject.is(document.activeElement, b1,
-                              "Focused first iframe");
+    window.arguments[0].is(document.activeElement, b1,
+                           "Focused first iframe");
 
     var didCallDummy = false;
     b2.contentWindow.addEventListener("mousedown", function(e) { didCallDummy = true; });
     sendClick(b2.contentWindow);
-    opener.wrappedJSObject.ok(didCallDummy, "dummy mousedown handler should fire");
-    opener.wrappedJSObject.is(document.activeElement, b2,
-                              "Focus shifted to second iframe");
+    window.arguments[0].ok(didCallDummy, "dummy mousedown handler should fire");
+    window.arguments[0].is(document.activeElement, b2,
+                           "Focus shifted to second iframe");
 
     b1.contentWindow.focus();
-    opener.wrappedJSObject.is(document.activeElement, b1,
-                              "Re-focused first iframe for the first time");
+    window.arguments[0].is(document.activeElement, b1,
+                           "Re-focused first iframe for the first time");
 
     var didCallListener = false;
     b2.contentWindow.addEventListener("mousedown", function(e) { didCallListener = true; e.preventDefault(); });
     sendClick(b2.contentWindow);
-    opener.wrappedJSObject.ok(didCallListener, "mousedown handler should fire");
-    opener.wrappedJSObject.is(document.activeElement, b1,
-                              "Did not move focus to the second iframe");
+    window.arguments[0].ok(didCallListener, "mousedown handler should fire");
+    window.arguments[0].is(document.activeElement, b1,
+                           "Did not move focus to the second iframe");
 
     window.close();
-    opener.wrappedJSObject.finishedTests();
+    window.arguments[0].finishedTests();
   }
 
   SimpleTest.waitForFocus(runTests);
   ]]>
   </script>
   <iframe xmlns="http://www.w3.org/1999/xhtml"
           id="b1" type="content" src="about:blank"
           style="width: 300px; height: 550px; border: 1px solid black;"/>
--- a/dom/tests/mochitest/chrome/file_bug830858.xul
+++ b/dom/tests/mochitest/chrome/file_bug830858.xul
@@ -29,37 +29,37 @@ https://bugzilla.mozilla.org/show_bug.cg
     var docListenerCalled = 0;
     doc.addEventListener("foo", function() { ++docListenerCalled; }, true);
     var winListenerCalled = 0;
     win.addEventListener("foo", function() { ++winListenerCalled; }, true);
     var iframeListenerCalled = 0;
     b.addEventListener("foo", function() { ++iframeListenerCalled; }, true);
 
     doc.dispatchEvent(new Event("foo"));
-    opener.wrappedJSObject.is(docListenerCalled, 1, "Normal dispatch to Document");
-    opener.wrappedJSObject.is(winListenerCalled, 1, "Normal dispatch to Document");
-    opener.wrappedJSObject.is(iframeListenerCalled, 1, "Normal dispatch to Document");
+    window.arguments[0].is(docListenerCalled, 1, "Normal dispatch to Document");
+    window.arguments[0].is(winListenerCalled, 1, "Normal dispatch to Document");
+    window.arguments[0].is(iframeListenerCalled, 1, "Normal dispatch to Document");
 
     win.dispatchEvent(new Event("foo"));
-    opener.wrappedJSObject.is(docListenerCalled, 1, "Normal dispatch to Window");
-    opener.wrappedJSObject.is(winListenerCalled, 2, "Normal dispatch to Window");
-    opener.wrappedJSObject.is(iframeListenerCalled, 2, "Normal dispatch to Window");
+    window.arguments[0].is(docListenerCalled, 1, "Normal dispatch to Window");
+    window.arguments[0].is(winListenerCalled, 2, "Normal dispatch to Window");
+    window.arguments[0].is(iframeListenerCalled, 2, "Normal dispatch to Window");
 
     wu.dispatchEventToChromeOnly(doc, new Event("foo"));
-    opener.wrappedJSObject.is(docListenerCalled, 1, "Chrome-only dispatch to Document");
-    opener.wrappedJSObject.is(winListenerCalled, 2, "Chrome-only dispatch to Document");
-    opener.wrappedJSObject.is(iframeListenerCalled, 3, "Chrome-only dispatch to Document");
+    window.arguments[0].is(docListenerCalled, 1, "Chrome-only dispatch to Document");
+    window.arguments[0].is(winListenerCalled, 2, "Chrome-only dispatch to Document");
+    window.arguments[0].is(iframeListenerCalled, 3, "Chrome-only dispatch to Document");
 
     wu.dispatchEventToChromeOnly(win, new Event("foo"));
-    opener.wrappedJSObject.is(docListenerCalled, 1, "Chrome-only dispatch to Window");
-    opener.wrappedJSObject.is(winListenerCalled, 2, "Chrome-only dispatch to Window");
-    opener.wrappedJSObject.is(iframeListenerCalled, 4, "Chrome-only dispatch to Window");
+    window.arguments[0].is(docListenerCalled, 1, "Chrome-only dispatch to Window");
+    window.arguments[0].is(winListenerCalled, 2, "Chrome-only dispatch to Window");
+    window.arguments[0].is(iframeListenerCalled, 4, "Chrome-only dispatch to Window");
 
     window.close();
-    opener.wrappedJSObject.finishedTests();
+    window.arguments[0].finishedTests();
   }
 
   SimpleTest.waitForFocus(runTests);
   ]]>
   </script>
   <iframe xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           id="b" type="content" src="about:blank"
           style="width: 300px; height: 550px; border: 1px solid black;"/>
--- a/dom/tests/mochitest/chrome/file_clipboard_events_chrome.html
+++ b/dom/tests/mochitest/chrome/file_clipboard_events_chrome.html
@@ -1,1 +1,1 @@
-<body onload='window.opener.doChecks(this)'><input id='i' value='Sample Text'></body>
+<body onload='window.arguments[0].doChecks(this)'><input id='i' value='Sample Text'></body>
--- a/dom/tests/mochitest/chrome/fullscreen.xul
+++ b/dom/tests/mochitest/chrome/fullscreen.xul
@@ -8,17 +8,17 @@
         sizemode="fullscreen">
 
 <script>
 
 window.addEventListener("fullscreen", onFullScreen, true);
 
 function onFullScreen(event)
 {
-  window.opener.wrappedJSObject.done(window.fullScreen);
+  window.arguments[0].done(window.fullScreen);
 }
 
 </script>
 
 <body xmlns="http://www.w3.org/1999/xhtml">
 
 <button id="find-button" label="Find"/>
 <button id="cancel-button" label="Cancel"/>
--- a/dom/tests/mochitest/chrome/sizemode_attribute.xul
+++ b/dom/tests/mochitest/chrome/sizemode_attribute.xul
@@ -41,17 +41,17 @@ let tests = [
   },
 
   function test7() {
     listen("resize", () => checkAndContinue("normal"));
     window.restore();
   },
 
   function test8() {
-    window.opener.wrappedJSObject.done();
+    window.arguments[0].done();
   }
 ];
 
 function nextStep() {
   tests.shift()();
 }
 
 function listen(event, fn) {
@@ -72,16 +72,16 @@ function checkAndContinue(sizemode) {
   setTimeout(function() {
     is(window.document.documentElement.getAttribute("sizemode"), sizemode, "sizemode attribute should match actual window state");
     is(window.fullScreen, sizemode == "fullscreen", "window.fullScreen should match actual window state");
     is(window.windowState, windowStates[sizemode], "window.sizeMode should match actual window state");
     nextStep();
   }, 0);
 }
 
-let is = window.opener.wrappedJSObject.is;
+let is = window.arguments[0].is;
 
 </script>
 
 <body xmlns="http://www.w3.org/1999/xhtml">
 
 </body>
 </window>
--- a/dom/tests/mochitest/chrome/test_DOMWindowCreated.xul
+++ b/dom/tests/mochitest/chrome/test_DOMWindowCreated.xul
@@ -18,12 +18,12 @@
 </div>
 <pre id="test">
 </pre>
 </body>
 
 <script>
 SimpleTest.waitForExplicitFinish();
 var root = getRootDirectory(window.location.href);
-window.open(root + "DOMWindowCreated_chrome.xul", "_blank", "chrome,width=600,height=550");
+window.openDialog(root + "DOMWindowCreated_chrome.xul", "_blank", "chrome,width=600,height=550,noopener", window);
 </script>
 
 </window>
--- a/dom/tests/mochitest/chrome/test_DOM_element_instanceof.xul
+++ b/dom/tests/mochitest/chrome/test_DOM_element_instanceof.xul
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <iframe type="content"></iframe>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
   /** Test for Bug 824917 **/
 
   function runTests() {
-    window.open("file_DOM_element_instanceof.xul", "_blank", "chrome,width=600,height=550");
+    window.openDialog("file_DOM_element_instanceof.xul", "_blank", "chrome,width=600,height=550,noopener", window);
   }
 
   addLoadEvent(runTests);
 
   SimpleTest.waitForExplicitFinish();
 
   ]]>
   </script>
--- a/dom/tests/mochitest/chrome/test_MozDomFullscreen_event.xul
+++ b/dom/tests/mochitest/chrome/test_MozDomFullscreen_event.xul
@@ -33,17 +33,18 @@ pm.removeFromPrincipal(principal, "fulls
 SpecialPowers.pushPrefEnv({"set": [
   ['full-screen-api.enabled', true],
   ['full-screen-api.allow-trusted-requests-only', false],
   ['full-screen-api.transition-duration.enter', '0 0'],
   ['full-screen-api.transition-duration.leave', '0 0']
 ]}, setup);
 
 function setup() {
-   newwindow = window.open("MozDomFullscreen_chrome.xul", "_blank","chrome,resizable=yes,width=400,height=400");
+   newwindow = docShell.rootTreeItem.domWindow.openDialog(
+      "MozDomFullscreen_chrome.xul", "_blank","chrome,dialog=no,resizable=yes,width=400,height=400", window);
 }
 
 function done()
 {
   newwindow.close();
   SimpleTest.finish();
 }
 
--- a/dom/tests/mochitest/chrome/test_activation.xul
+++ b/dom/tests/mochitest/chrome/test_activation.xul
@@ -21,17 +21,17 @@
   <script type="application/javascript" 
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
 
 <box id="box" height="100"/>
 
 <script>
 SimpleTest.waitForExplicitFinish();
 
-newwindow = window.open("window_activation.xul", "_blank","chrome,width=300,height=200");
+newwindow = docShell.rootTreeItem.domWindow.openDialog("window_activation.xul", "_blank","chrome,width=300,height=200", window);
 
 function complete()
 {
   newwindow.close();
   SimpleTest.finish();
 }
 
 </script>
--- a/dom/tests/mochitest/chrome/test_bug1224790-1.xul
+++ b/dom/tests/mochitest/chrome/test_bug1224790-1.xul
@@ -18,17 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
    * 1. Opens modal dialog
    * 2. Open non-modal window from modal dialog
    * 3. Close non-modal window
    * 4. Close modal dialog
    * 5. Click button to ensure mouse event is working
    */
 
   function startTest() {
-    window.openDialog('file_bug1224790-1_modal.xul', '', 'modal');
+    window.openDialog('file_bug1224790-1_modal.xul', '', 'modal,noopener', window);
   }
 
   function modalClosed() {
     SimpleTest.waitForFocus(gotFocus);
   }
 
   var timer = null;
   function gotFocus() {
--- a/dom/tests/mochitest/chrome/test_bug1224790-2.xul
+++ b/dom/tests/mochitest/chrome/test_bug1224790-2.xul
@@ -19,17 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
    * 2. Open non-modal window from modal dialog
    * 3. Close modal dialog
    * 4. Wait for a while for destructor for modal dialog
    * 5. Close non-modal window
    * 6. Click button to ensure mouse event is working
    */
 
   function startTest() {
-    window.openDialog('file_bug1224790-2_modal.xul', '', 'modal');
+    window.openDialog('file_bug1224790-2_modal.xul', '', 'modal,noopener', window);
   }
 
   function nonModalClosed() {
     SimpleTest.waitForFocus(gotFocus);
   }
 
   var timer = null;
   function gotFocus() {
--- a/dom/tests/mochitest/chrome/test_bug799299.xul
+++ b/dom/tests/mochitest/chrome/test_bug799299.xul
@@ -16,16 +16,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
   /** Test for Bug 799299 **/
 
   function runTests() {
-    window.open("file_bug799299.xul", "_blank", "chrome,width=600,height=550");
+    window.openDialog("file_bug799299.xul", "_blank", "chrome,width=600,height=550,noopener", window);
   }
 
   SimpleTest.waitForExplicitFinish();
 
   ]]>
   </script>
 </window>
--- a/dom/tests/mochitest/chrome/test_bug800817.xul
+++ b/dom/tests/mochitest/chrome/test_bug800817.xul
@@ -18,24 +18,24 @@ https://bugzilla.mozilla.org/show_bug.cg
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
   /** Test for Bug 800817 **/
 
   var testMozBrowser = false;
   function runTests() {
     // Run a first round of tests for non-mozbrowser iframes.
-    window.open("file_bug800817.xul", "_blank", "chrome,width=600,height=550");
+    window.openDialog("file_bug800817.xul", "_blank", "chrome,width=600,height=550,noopener", window);
   }
 
   function finishedTests() {
     if (!testMozBrowser) {
       testMozBrowser = true;
       // Run a second round of tests for mozbrowser iframes.
-      window.open("file_bug800817.xul", "_blank", "chrome,width=600,height=550");
+      window.openDialog("file_bug800817.xul", "_blank", "chrome,width=600,height=550,noopener", window);
     } else {
       SimpleTest.finish();
     }
   }
 
   SimpleTest.waitForExplicitFinish();
 
   ]]>
--- a/dom/tests/mochitest/chrome/test_bug830858.xul
+++ b/dom/tests/mochitest/chrome/test_bug830858.xul
@@ -11,17 +11,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
 
   /** Test for Bug 830858 **/
 
   function runTests() {
-    window.open("file_bug830858.xul", "_blank", "chrome,width=600,height=550");
+    window.openDialog("file_bug830858.xul", "_blank", "chrome,width=600,height=550,noopener", window);
   }
 
   function finishedTests() {
     SimpleTest.finish();
   }
 
   SimpleTest.waitForExplicitFinish();
 
--- a/dom/tests/mochitest/chrome/test_clipboard_events_chrome.html
+++ b/dom/tests/mochitest/chrome/test_clipboard_events_chrome.html
@@ -6,17 +6,17 @@
 
 <script>
 // This test checks that the dom.event.clipboardevents.enabled does not apply to chrome shells.
 
 SimpleTest.waitForExplicitFinish();
 function runTest()
 {
   SpecialPowers.pushPrefEnv({"set": [['dom.event.clipboardevents.enabled', false]]}, function() {
-    window.open("file_clipboard_events_chrome.html", "_blank", "chrome,width=200,height=200");
+    window.openDialog("file_clipboard_events_chrome.html", "_blank", "chrome,width=200,height=200,noopener", window);
   });
 }
 
 var event_fired = false;
 
 function doChecks(win)
 {
   var windowFocused = function() {
--- a/dom/tests/mochitest/chrome/test_docshell_swap.xul
+++ b/dom/tests/mochitest/chrome/test_docshell_swap.xul
@@ -12,18 +12,18 @@
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
 
   SimpleTest.waitForExplicitFinish();
 
   // Create two identical windows, each with a <browser> element.
-  let win1 = window.openDialog("window_docshell_swap.xul", "_blank","chrome,width=300,height=200");
-  let win2 = window.openDialog("window_docshell_swap.xul", "_blank","chrome,width=300,height=200");
+  let win1 = docShell.rootTreeItem.domWindow.openDialog("window_docshell_swap.xul", "_blank","chrome,width=300,height=200");
+  let win2 = docShell.rootTreeItem.domWindow.openDialog("window_docshell_swap.xul", "_blank","chrome,width=300,height=200");
 
   let loadCount = 0;
   function loadHandler() {
     loadCount++;
     if (loadCount < 2)
       return;
 
     let browser1 = win1.document.getElementById("browser");
--- a/dom/tests/mochitest/chrome/test_focus.xul
+++ b/dom/tests/mochitest/chrome/test_focus.xul
@@ -11,17 +11,17 @@
 <script>
 if (navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 1);
 }
 
 SimpleTest.waitForExplicitFinish();
 function runTest()
 {
-  window.open("window_focus.xul", "_blank", "chrome,width=600,height=550");
+  window.openDialog("window_focus.xul", "_blank", "chrome,width=600,height=550,noopener", window);
 }
 </script>
 
 <body xmlns="http://www.w3.org/1999/xhtml">
 <p id="display">
 </p>
 <div id="content" style="display: none">
 </div>
--- a/dom/tests/mochitest/chrome/test_focus_docnav.xul
+++ b/dom/tests/mochitest/chrome/test_focus_docnav.xul
@@ -6,17 +6,17 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
 <script>
 SimpleTest.waitForExplicitFinish();
 function runTest()
 {
-  window.open("window_focus_docnav.xul", "_blank", "chrome,width=600,height=550");
+  window.openDialog("window_focus_docnav.xul", "_blank", "chrome,width=600,height=550,noopener", window);
 }
 </script>
 
 <body xmlns="http://www.w3.org/1999/xhtml">
 <p id="display">
 </p>
 <div id="content" style="display: none">
 </div>
--- a/dom/tests/mochitest/chrome/test_fullscreen.xul
+++ b/dom/tests/mochitest/chrome/test_fullscreen.xul
@@ -8,17 +8,17 @@
         sizemode="fullscreen">
 
   <script type="application/javascript" 
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
 
 <script>
 SimpleTest.waitForExplicitFinish();
 
-newwindow = window.open("fullscreen.xul", "_blank","chrome,resizable=yes");
+newwindow = docShell.rootTreeItem.domWindow.openDialog("fullscreen.xul", "_blank","chrome,resizable=yes", window);
 
 function done()
 {
   // because we are cancelling the fullscreen event, it
   // takes a bit for the fullScreen property to be set
   setTimeout(function() { this.complete(); }, 0);
 }
 
--- a/dom/tests/mochitest/chrome/test_sizemode_attribute.xul
+++ b/dom/tests/mochitest/chrome/test_sizemode_attribute.xul
@@ -8,17 +8,17 @@
         sizemode="fullscreen">
 
   <script type="application/javascript" 
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
 
 <script>
 SimpleTest.waitForExplicitFinish();
 
-newwindow = window.open("sizemode_attribute.xul", "_blank","chrome,resizable=yes");
+newwindow = docShell.rootTreeItem.domWindow.openDialog("sizemode_attribute.xul", "_blank","chrome,resizable=yes", window);
 
 function done() {
   newwindow.close();
   SimpleTest.finish();
 }
 
 </script>
 <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px;"/>
--- a/dom/tests/mochitest/chrome/window_activation.xul
+++ b/dom/tests/mochitest/chrome/window_activation.xul
@@ -13,25 +13,25 @@
 " type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
 <box id="box" height="100"/>
 
 <script type="application/javascript"><![CDATA[
 
-var ok = window.opener.wrappedJSObject.ok;
-var complete = window.opener.wrappedJSObject.complete;
-var openerDoc = window.opener.wrappedJSObject.document;
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+var ok = window.arguments[0].ok;
+var complete = window.arguments[0].complete;
+var openerDoc = window.arguments[0].document;
+var SimpleTest = window.arguments[0].SimpleTest;
 
 SimpleTest.waitForFocus(function () {
   ok(getComputedStyle(document.getElementById("box"), "").backgroundColor, "rgb(0, 0, 255)");
   ok(getComputedStyle(openerDoc.getElementById("box"), "").backgroundColor, "rgb(0, 255, 255)");
-  window.opener.focus();
+  window.arguments[0].focus();
   ok(getComputedStyle(document.getElementById("box"), "").backgroundColor, "rgb(0, 255, 255)");
   ok(getComputedStyle(openerDoc.getElementById("box"), "").backgroundColor, "rgb(0, 0, 255)");
   complete();
 }, window);
 
 ]]></script>
 
 </window>
--- a/dom/tests/mochitest/chrome/window_focus.xul
+++ b/dom/tests/mochitest/chrome/window_focus.xul
@@ -34,18 +34,18 @@ var gEvents = "";
 var gExpectedEvents = "";
 var gEventMatched = true;
 var gShowOutput = false;
 var gChildWindow = null;
 
 var gOldExpectedWindow = null;
 var gNewExpectedWindow = null;
 
-function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
-function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
+function is(l, r, n) { window.arguments[0].SimpleTest.is(l,r,n); }
+function ok(v, n) { window.arguments[0].SimpleTest.ok(v,n); }
 
 function initEvents(target)
 {
   target.addEventListener("focus", eventOccured, true);
   target.addEventListener("blur", eventOccured, true);
   getTopWindow(target).addEventListener("activate", eventOccured, true);
   getTopWindow(target).addEventListener("deactivate", eventOccured, true);
 }
@@ -317,19 +317,19 @@ function mouseOnElement(element, expecte
     expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal),
                      element.ownerGlobal,
                      expectedElement, focusChanged, testid);
   }
 }
 
 function done()
 {
-  var opener = window.opener;
+  var opener = window.arguments[0];
   window.close();
-  opener.wrappedJSObject.SimpleTest.finish();
+  window.arguments[0].SimpleTest.finish();
 }
 
 var pressTab = () => synthesizeKey("KEY_Tab");
 
 function setFocusTo(id, fwindow)
 {
   gLastFocus = getById(id);
   gLastFocusWindow = fwindow;
@@ -1159,17 +1159,18 @@ function modalWindowOpened(modalWindow)
   SimpleTest.waitForFocus(modalWindowClosed);
 }
 
 function modalWindowClosed()
 {
   is(fm.activeWindow, window, "modal window closed activeWindow");
   is(fm.focusedElement, getById("n2"), "modal window closed focusedElement");
 
-  window.open("focus_frameset.html", "_blank", "width=400,height=400,toolbar=no");
+  window.arguments[0].framesetWindowLoaded = framesetWindowLoaded;
+  window.arguments[0].open("focus_frameset.html", "_blank", "width=400,height=400,toolbar=no");
 }
 
 function framesetWindowLoaded(framesetWindow)
 {
   gLastFocus = null;
   gLastFocusWindow = framesetWindow;
   gEvents = "";
 
--- a/dom/tests/mochitest/chrome/window_focus_docnav.xul
+++ b/dom/tests/mochitest/chrome/window_focus_docnav.xul
@@ -20,18 +20,18 @@
 <browser id="browser" type="content" src="focus_frameset.html" width="500" height="400"/>
 
 <script type="application/javascript">
 <![CDATA[
 
 var fm = Cc["@mozilla.org/focus-manager;1"].
            getService(Ci.nsIFocusManager);
 
-function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
-function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
+function is(l, r, n) { window.arguments[0].SimpleTest.is(l,r,n); }
+function ok(v, n) { window.arguments[0].SimpleTest.ok(v,n); }
 
 function noChildrenTest()
 {
   // Remove the browser element and test navigation when there are no other documents.
   // The focus should move or stay on the first focusable element.
   let browser = document.getElementById("browser");
   browser.remove();
 
@@ -46,19 +46,18 @@ function noChildrenTest()
   previous(window, textbox1.inputField, "Focus backward when no child documents");
   previous(window, textbox1.inputField, "Focus backward again when no child documents");
 
   done();
 }
 
 function done()
 {
-  var opener = window.opener;
   window.close();
-  opener.wrappedJSObject.SimpleTest.finish();
+  window.arguments[0].SimpleTest.finish();
 }
 
 function previous(expectedWindow, expectedElement, desc)
 {
   synthesizeKey("KEY_F6", {shiftKey: true});
   is(fm.focusedWindow, expectedWindow, desc);
   is(fm.focusedElement, expectedElement, desc + " element");
 }
@@ -109,17 +108,17 @@ function runTests(panel, popupCount)
   else if (panel == document.getElementById("panel2"))
     panel.hidePopup();
   else
     document.getElementById("panel").openPopup(null, "after_start");
 }
 
 function start()
 {
-  window.opener.wrappedJSObject.SimpleTest.waitForExplicitFinish();
-  window.opener.wrappedJSObject.SimpleTest.waitForFocus(
+  window.arguments[0].SimpleTest.waitForExplicitFinish();
+  window.arguments[0].SimpleTest.waitForFocus(
     function() { runTests(null, 0); },
     document.getElementById("browser").contentWindow);
 }
 
 ]]></script>
 
 </window>
--- a/dom/tests/mochitest/keyhandling/test_input.html
+++ b/dom/tests/mochitest/keyhandling/test_input.html
@@ -49,19 +49,19 @@ if (IS_MAC) {
   VK.HOME = WIN_VK_HOME;
   CHARS.HOME = "";
   VK.BACKSPACE = WIN_VK_BACK;
   CHARS.BACKSPACE = "";
   VK.Z = WIN_VK_Z;
   VK.SPACE = WIN_VK_SPACE;
 }
 
-if (window.opener) {
-  ok = window.opener.ok;
-  is = window.opener.is;
+if (window.arguments && window.arguments[0]) {
+  ok = window.arguments[0].ok;
+  is = window.arguments[0].is;
 }
 
 function synthesizeKey(keyCode, modifiers, chars, event = "keyup") {
   return new Promise((resolve, reject) => {
     window.addEventListener(event, resolve, { once: true });
 
     if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars)) {
       reject();
@@ -205,17 +205,17 @@ async function startTest() {
   await synthesizeKey(VK.O, {}, "o");
   await synthesizeKey(VK.O, {}, "o");
   await checkElement(input, 8, 8, "text foo");
 }
 
 async function runTest() {
   // When running in windowed mode the caller will start the test once we have
   // focus.
-  if (window.opener) {
+  if (window.arguments && window.arguments[0]) {
     return;
   }
 
   SimpleTest.waitForExplicitFinish();
   await startTest();
   SimpleTest.finish();
 }
 </script>
--- a/dom/tests/mochitest/keyhandling/test_textarea.html
+++ b/dom/tests/mochitest/keyhandling/test_textarea.html
@@ -49,19 +49,19 @@ if (IS_MAC) {
   VK.HOME = WIN_VK_HOME;
   CHARS.HOME = "";
   VK.BACKSPACE = WIN_VK_BACK;
   CHARS.BACKSPACE = "";
   VK.Z = WIN_VK_Z;
   VK.SPACE = WIN_VK_SPACE;
 }
 
-if (window.opener) {
-  ok = window.opener.ok;
-  is = window.opener.is;
+if (window.arguments && window.arguments[0]) {
+  ok = window.arguments[0].ok;
+  is = window.arguments[0].is;
 }
 
 function synthesizeKey(keyCode, modifiers, chars, event = "keyup") {
   return new Promise((resolve, reject) => {
     window.addEventListener(event, resolve, { once: true });
 
     if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars)) {
       reject();
@@ -205,17 +205,17 @@ async function startTest() {
   await synthesizeKey(VK.O, {}, "o");
   await synthesizeKey(VK.O, {}, "o");
   await checkElement(input, 8, 8, "text foo");
 }
 
 async function runTest() {
   // When running in windowed mode the caller will start the test once we have
   // focus.
-  if (window.opener) {
+  if (window.arguments && window.arguments[0]) {
     return;
   }
 
   SimpleTest.waitForExplicitFinish();
   await startTest();
   SimpleTest.finish();
 }
 </script>
--- a/dom/tests/mochitest/keyhandling/test_windowed.xul
+++ b/dom/tests/mochitest/keyhandling/test_windowed.xul
@@ -6,17 +6,18 @@
 
   <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <script type="application/javascript">
   <![CDATA[
     SimpleTest.waitForExplicitFinish();
 
     async function run_test(path) {
-      let win = window.openDialog(path, "_blank", "width=500,height=500");
+      let win = window.docShell.rootTreeItem.domWindow
+                      .openDialog(path, "_blank", "width=500,height=500", window);
       await SimpleTest.promiseFocus(win);
       await win.startTest();
     }
 
     async function test() {
       await run_test("test_input.html");
       await run_test("test_textarea.html");
       SimpleTest.finish();
--- a/dom/xul/test/test_bug583948.xul
+++ b/dom/xul/test/test_bug583948.xul
@@ -9,30 +9,33 @@
 
 <body xmlns="http://www.w3.org/1999/xhtml">
   <div id="content" style="display: none"/>
 </body>
 
 <script>
 SimpleTest.waitForExplicitFinish();
 
+let chromeWindow = docShell.rootTreeItem.domWindow;
+
 var attempts = 0;
 
-function update() {
+chromeWindow.update = function () {
   // without the crash fix, this usually crashes after 2 to 4 reloads
   if (++attempts == 6) {
     ok(true, "didn't crash after 6 attempts");
     otherWindow.close();
     SimpleTest.waitForFocus(function() {
+      chromeWindow.update = null;
       SimpleTest.finish();
     });
   } else {
     otherWindow.document.commandDispatcher.updateCommands('');
     setTimeout(function() {
       otherWindow.location.reload()
     }, 0);
   }
 }
 
-var otherWindow = window.open("window_bug583948.xul", "_new", "chrome");
+var otherWindow = chromeWindow.open("window_bug583948.xul", "_blank", "chrome");
 </script>
 
 </window>
--- a/dom/xul/test/test_bug757137.xul
+++ b/dom/xul/test/test_bug757137.xul
@@ -15,17 +15,17 @@
 SimpleTest.waitForExplicitFinish();
 
 // Force off out-of-process mozbrowser because we need to grab its
 // |window| synchronously from here.  Out-of-process docshell creation
 // for mozbrowser haves entirely differently.
 SpecialPowers.pushPrefEnv({"set":[["dom.ipc.tabs.disabled", true]]}, startTest);
 
 function startTest() {
-  var otherWindow = window.open("window_bug757137.xul", "", "chrome");
+  var otherWindow = docShell.rootTreeItem.domWindow.open("window_bug757137.xul", "", "chrome");
   ok(otherWindow.isChromeWindow, 'XUL window should be a ChromeWindow');
 
   otherWindow.onload = function () {
     var w = otherWindow.document.getElementById('f').contentWindow;
     ok(w !== null, 'got the |window| for a mozbrowser iframe');
     ok(!w.isChromeWindow, 'mozbrowser iframe should not be a ChromeWindow');
 
     otherWindow.close();
--- a/js/xpconnect/tests/chrome/bug503926.xul
+++ b/js/xpconnect/tests/chrome/bug503926.xul
@@ -15,15 +15,15 @@ https://bugzilla.mozilla.org/show_bug.cg
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
       var gWindowUtils = window.windowUtils;
       var passed = false;
       var obj = { QueryInterface: function() { passed = true; } }
       gWindowUtils.xpconnectArgument(obj);
       var isDialog = location.hash != '#iframe';
-      var outer = XPCNativeWrapper.unwrap(isDialog ? opener : parent);
+      var outer = XPCNativeWrapper.unwrap(isDialog ? window.arguments[0] : parent);
       outer.ok(passed, "chrome/chrome test passed: " + (isDialog ? "dialog" : "iframe"));
       if (isDialog)
         close();
   ]]>
   </script>
 </window>
--- a/js/xpconnect/tests/chrome/file_bug618176.xul
+++ b/js/xpconnect/tests/chrome/file_bug618176.xul
@@ -16,33 +16,33 @@ https://bugzilla.mozilla.org/show_bug.cg
 "data:text/html,<script>var a=[1,2,3];</script>Hi";
 
     const FRAME_SCRIPT = 
 "data:,addEventListener('pageshow', function() { sendAsyncMessage('test', content.wrappedJSObject.a) }, false);";
    // s/content.wrappedJSObject.a/[ 1, 2, 3]/ and the test passes
 
     function recvTest(m) {
       var a = m.json;
-      opener.wrappedJSObject.is(a.length, 3, "array was serialized and deserialized");
+      window.arguments[0].is(a.length, 3, "array was serialized and deserialized");
 
       messageManager.removeMessageListener("test", recvTest);
       finish();
     }
 
     function start() {
       messageManager.addMessageListener("test", recvTest);
       messageManager.loadFrameScript(FRAME_SCRIPT, true);
       const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
       let triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
       setTimeout(function () {
         document.getElementById("browser").loadURI(TEST_PAGE, {triggeringPrincipal});
       }, 0);
     }
 
     function finish() {
-      opener.setTimeout(function() { this.done(); }, 0);
+      window.arguments[0].setTimeout(function() { this.done(); }, 0);
       window.close();
     }
 
   ]]></script>
 
   <browser id="browser" type="content" style="width: 200px; height: 200px;"/>
 </window>
--- a/js/xpconnect/tests/chrome/test_bug1124898.html
+++ b/js/xpconnect/tests/chrome/test_bug1124898.html
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   /** Test for Bug 1124898 **/
   SimpleTest.waitForExplicitFinish();
   (async () => {
     await SpecialPowers.pushPrefEnv({"set": [["security.allow_eval_with_system_principal", true]]});
 
     SimpleTest.expectAssertions(0, 1); // Dumb unrelated widget assertion - see bug 1126023.
 
-    var w = window.open("about:blank", "w", "chrome");
+    var w = docShell.rootTreeItem.domWindow.open("about:blank", "w", "chrome");
     is(w.eval('typeof getAttention'), 'function', 'getAttention exists on regular chrome window');
     is(w.eval('typeof messageManager'), 'object', 'messageManager exists on regular chrome window');
     var contentURL = "http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html";
     w.location = contentURL;
     tryWindow();
 
     function tryWindow() {
       if (w.document.title != 'empty test page') {
--- a/js/xpconnect/tests/chrome/test_bug503926.xul
+++ b/js/xpconnect/tests/chrome/test_bug503926.xul
@@ -42,16 +42,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     // Try with a content object.
     var contentWin = $('ifrContent').contentWindow.wrappedJSObject;
     contentWin.passed = false;
     var contentObj = contentWin.eval('({ QueryInterface: function() { passed = true; } })');
     gWindowUtils.xpconnectArgument(contentObj);
     ok(!contentWin.passed, "untrusted QI should not be called");
 
     // Try with a dialog.
-    openDialog("bug503926.xul", "chromeDialog", "modal");
+    docShell.rootTreeItem.domWindow.openDialog("bug503926.xul", "chromeDialog", "modal", window);
     SimpleTest.finish();
   }
 
   SimpleTest.waitForExplicitFinish();
   ]]>
   </script>
 </window>
--- a/js/xpconnect/tests/chrome/test_bug618176.xul
+++ b/js/xpconnect/tests/chrome/test_bug618176.xul
@@ -19,12 +19,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"><![CDATA[
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    window.open("file_bug618176.xul", "", "chrome");
+    window.openDialog("file_bug618176.xul", "", "chrome,noopener", window);
   });
   ]]></script>
 </window>
--- a/layout/base/tests/chrome/bug1041200_window.html
+++ b/layout/base/tests/chrome/bug1041200_window.html
@@ -4,22 +4,22 @@
   <title>Test for Bug 1041200</title>
   <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
   <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
 </head>
 <body>
 <iframe style="width:700px; height:500px; margin-top:200px;" id="ourFrame"></iframe>
 <script>
-var SpecialPowers = window.opener.wrappedJSObject.SpecialPowers;
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
-var ok = window.opener.wrappedJSObject.ok;
-var info = window.opener.wrappedJSObject.info;
+var SpecialPowers = window.arguments[0].SpecialPowers;
+var SimpleTest = window.arguments[0].SimpleTest;
+var ok = window.arguments[0].ok;
+var info = window.arguments[0].info;
 
-var viewer = SpecialPowers.wrap(ourFrame).contentWindow.docShell.contentViewer;
+var viewer = ourFrame.contentWindow.docShell.contentViewer;
 viewer.fullZoom = 2;
 
 SimpleTest.waitForExplicitFinish();
 
 window.onload = function() {
   window.waitForAllPaintsFlushed(function () {
     // Supply random key to ensure load actually happens
     ourFrame.src = "bug1041200_frame.html?" + Math.random();
--- a/layout/base/tests/chrome/chrome_content_integration_window.xul
+++ b/layout/base/tests/chrome/chrome_content_integration_window.xul
@@ -17,17 +17,17 @@
     <!-- the top 100px is a strip of black above the content iframe -->
     <vbox style="border-top:100px solid black;"/>
   </stack>
 
   <script type="application/javascript">
     <![CDATA[
     var imports = [ "SimpleTest", "is", "isnot", "ok", "SpecialPowers" ];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
     
     function runTests() {
       var testCanvas = snapshotWindow(window);
 
       var refCanvas = snapshotWindow(window);
       var ctx = refCanvas.getContext('2d');
       ctx.fillStyle = "black";
--- a/layout/base/tests/chrome/chrome_over_plugin_window.xul
+++ b/layout/base/tests/chrome/chrome_over_plugin_window.xul
@@ -14,17 +14,17 @@
       <vbox style="height:50px;"/> <!-- plugin should be visible here -->
     </vbox>
   </stack>
 
   <script type="application/javascript">
     <![CDATA[
     var imports = [ "SimpleTest", "is", "isnot", "ok", "todo" ];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
 
     var plugin;
     function waitForPaint() {
       if (plugin.getPaintCount() < 1) {
         setTimeout(waitForPaint, 0);
         return;
       }
--- a/layout/base/tests/chrome/default_background_window.xul
+++ b/layout/base/tests/chrome/default_background_window.xul
@@ -10,17 +10,17 @@
   <iframe type="content" id="f" src="about:blank" style="border:1px solid black;"/>
 
   <script type="application/javascript">
   <![CDATA[
     SimpleTest.waitForExplicitFinish();
 
     var imports = [ "SimpleTest", "is", "isnot", "ok" ];
     for (var name of imports) {
-      window[name] = window.opener.wrappedJSObject[name];
+      window[name] = window.arguments[0][name];
     }
     
     function snapshot(win) {
       var el = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
       el.width = win.innerWidth;
       el.height = win.innerHeight;
 
       var ctx = el.getContext("2d");
--- a/layout/base/tests/chrome/dialog_with_positioning_window.xul
+++ b/layout/base/tests/chrome/dialog_with_positioning_window.xul
@@ -4,20 +4,20 @@
         onload="setTimeout(runTest, 0)">
   <vbox>
     <text value="powered by example.com" style="padding: 16px;"/>
   </vbox>
   <hbox id="t" style="position: fixed; right: 16px; bottom: 16px;">
     <button label="OK"/>
   </hbox>
 <script><![CDATA[
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
-var SpecialPowers = window.opener.wrappedJSObject.SpecialPowers;
-var is = window.opener.wrappedJSObject.is;
-var ok = window.opener.wrappedJSObject.ok;
+var SimpleTest = window.arguments[0].SimpleTest;
+var SpecialPowers = window.arguments[0].SpecialPowers;
+var is = window.arguments[0].is;
+var ok = window.arguments[0].ok;
 
 // We run this off a setTimeout from onload, because the XUL window
 // only does its intrinsic-height layout after the load event has
 // finished
 function runTest() {
   var t = document.getElementById("t");
   var tBottom = t.getBoundingClientRect().bottom;
   is(tBottom, document.documentElement.getBoundingClientRect().bottom - 16,
--- a/layout/base/tests/chrome/file_bug1018265.xul
+++ b/layout/base/tests/chrome/file_bug1018265.xul
@@ -26,25 +26,25 @@ https://bugzilla.mozilla.org/show_bug.cg
   function errorPageLoaded() {
     testcontent.addEventListener("pageshow", didGoBack, true);
     setTimeout(function() {testcontent.contentWindow.history.back();}, 0);
   }
 
   function didGoBack(e) {
     testcontent.removeEventListener("pageshow", didGoBack, true);
     shouldHaveTwoNonHiddenContentViewers();
-    opener.done();
+    window.arguments[0].done();
     window.close();
   }
 
   function getContentViewer(win) {
     return win.docShell.contentViewer;
   }
 
   function shouldHaveTwoNonHiddenContentViewers() {
-    opener.is(getContentViewer(testcontent.contentWindow).isHidden, false, "Top level ContentViewer should not be hidden.");
-    opener.is(getContentViewer(testcontent.contentWindow.frames[0]).isHidden, false, " Iframe's ContentViewer should not be hidden.");
+    window.arguments[0].is(getContentViewer(testcontent.contentWindow).isHidden, false, "Top level ContentViewer should not be hidden.");
+    window.arguments[0].is(getContentViewer(testcontent.contentWindow.frames[0]).isHidden, false, " Iframe's ContentViewer should not be hidden.");
   }
   ]]>
   </script>
 
   <browser type="content" id="testcontent" flex="1" src="data:text/html,&lt;iframe&gt;&lt;/iframe&gt;"/>
 </window>
--- a/layout/base/tests/chrome/printpreview_bug396024_helper.xul
+++ b/layout/base/tests/chrome/printpreview_bug396024_helper.xul
@@ -10,20 +10,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 <iframe id="i" src="about:blank" type="content"></iframe>
 <iframe src="about:blank" type="content"></iframe>
 <script type="application/javascript">
 <![CDATA[
 // Note: We can't use window.frames directly here because the type="content"
 // attributes isolate the frames into their own BrowsingContext hierarchies.
 let frameElts = document.getElementsByTagName("iframe");
 
-var is = window.opener.wrappedJSObject.is;
-var ok = window.opener.wrappedJSObject.ok;
-var todo = window.opener.wrappedJSObject.todo;
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+var is = window.arguments[0].is;
+var ok = window.arguments[0].ok;
+var todo = window.arguments[0].todo;
+var SimpleTest = window.arguments[0].SimpleTest;
 var gWbp;
 function printpreview() {
   gWbp = frameElts[1].contentWindow.docShell.initOrReusePrintPreviewViewer();
   var listener = {
     onLocationChange: function(webProgress, request, location, flags) { },
     onProgressChange: function(webProgress, request, curSelfProgress, 
                                maxSelfProgress, curTotalProgress,
                                maxTotalProgress) { },
--- a/layout/base/tests/chrome/printpreview_bug482976_helper.xul
+++ b/layout/base/tests/chrome/printpreview_bug482976_helper.xul
@@ -10,20 +10,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 <iframe src="about:blank" type="content"></iframe>
 <iframe src="about:blank" type="content"></iframe>
 <script type="application/javascript">
 <![CDATA[
 // Note: We can't use window.frames directly here because the type="content"
 // attributes isolate the frames into their own BrowsingContext hierarchies.
 let frameElts = document.getElementsByTagName("iframe");
 
-var is = window.opener.wrappedJSObject.is;
-var ok = window.opener.wrappedJSObject.ok;
-var todo = window.opener.wrappedJSObject.todo;
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+var is = window.arguments[0].is;
+var ok = window.arguments[0].ok;
+var todo = window.arguments[0].todo;
+var SimpleTest = window.arguments[0].SimpleTest;
 var gWbp;
 function printpreview() {
   gWbp = frameElts[1].contentWindow.docShell.initOrReusePrintPreviewViewer();
   var listener = {
     onLocationChange: function(webProgress, request, location, flags) { },
     onProgressChange: function(webProgress, request, curSelfProgress, 
                                maxSelfProgress, curTotalProgress,
                                maxTotalProgress) { },
--- a/layout/base/tests/chrome/printpreview_helper.xul
+++ b/layout/base/tests/chrome/printpreview_helper.xul
@@ -7,21 +7,21 @@
 <iframe height="200" width="600" type="content"></iframe>
 <iframe height="200" width="600" type="content"></iframe>
 <script type="application/javascript">
 <![CDATA[
 // Note: We can't use window.frames directly here because the type="content"
 // attributes isolate the frames into their own BrowsingContext hierarchies.
 let frameElts = document.getElementsByTagName("iframe");
 
-var is = window.opener.wrappedJSObject.is;
-var isnot = window.opener.wrappedJSObject.isnot;
-var ok = window.opener.wrappedJSObject.ok;
-var todo = window.opener.wrappedJSObject.todo;
-var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+var is = window.arguments[0].is;
+var isnot = window.arguments[0].isnot;
+var ok = window.arguments[0].ok;
+var todo = window.arguments[0].todo;
+var SimpleTest = window.arguments[0].SimpleTest;
 var gWbp;
 var ctx1;
 var ctx2;
 var counter = 0;
 
 var file = Cc["@mozilla.org/file/directory_service;1"]
              .getService(Ci.nsIProperties)
              .get("TmpD", Ci.nsIFile);
--- a/layout/base/tests/chrome/test_bug1018265.xul
+++ b/layout/base/tests/chrome/test_bug1018265.xul
@@ -14,17 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript">
   <![CDATA[
 
   /** Test for Bug 1018265 **/
 
   SimpleTest.waitForExplicitFinish();
 
   function run() {
-    window.open("file_bug1018265.xul", "contentViewerTest", "chrome,width=100,height=100");
+    window.openDialog("file_bug1018265.xul", "contentViewerTest", "chrome,width=100,height=100,noopener", window);
   }
 
   function done() {
     ok(true, "done");
     setTimeout(function() { SimpleTest.finish(); }, 0);
   }
   ]]>
   </script>
--- a/layout/base/tests/chrome/test_bug1041200.xul
+++ b/layout/base/tests/chrome/test_bug1041200.xul
@@ -10,13 +10,13 @@
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
     SimpleTest.waitForExplicitFinish();
     // Run the test in a separate window so that the test runs as a chrome
     // window
-    window.open("bug1041200_window.html", "bug1041200",
-                "chrome,width=800,height=800");
+    window.openDialog("bug1041200_window.html", "bug1041200",
+                      "chrome,width=800,height=800,noopener", window);
   ]]>
   </script>
 </window>
--- a/layout/base/tests/chrome/test_bug458898.html
+++ b/layout/base/tests/chrome/test_bug458898.html
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=458898">Mozilla Bug 458898</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
-var win = window.openDialog("file_bug458898.html");
+var win = docShell.rootTreeItem.domWindow.openDialog("file_bug458898.html");
 
 function loaded() {
   var disableWindowResizePref = "dom.disable_window_move_resize";
   SpecialPowers.pushPrefEnv({"set":[[disableWindowResizePref, false]]}, function() {
     win.sizeToContent();
     ok(win.innerWidth >= 100, "innerWidth: " + win.innerWidth + " >= 100 ?");
     ok(win.innerHeight >= 200, "innerHeight: " + win.innerHeight + " >= 200 ?");
     win.close();
--- a/layout/base/tests/chrome/test_chrome_content_integration.xul
+++ b/layout/base/tests/chrome/test_chrome_content_integration.xul
@@ -12,13 +12,13 @@
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
     SimpleTest.waitForExplicitFinish();
     // Run the test in a separate window so that the test runs as a chrome
     // window
     var root = getRootDirectory(window.location.href);
-    window.open(root + "chrome_content_integration_window.xul", "chrome_content_integration",
-                "chrome,width=200,height=300");
+    window.openDialog(root + "chrome_content_integration_window.xul", "chrome_content_integration",
+                      "chrome,width=200,height=300,noopener", window);
   ]]>
   </script>
 </window>
--- a/layout/base/tests/chrome/test_chrome_over_plugin.xul
+++ b/layout/base/tests/chrome/test_chrome_over_plugin.xul
@@ -12,13 +12,13 @@
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
     SimpleTest.waitForExplicitFinish();
     // Run the test in a separate window so that the test runs as a chrome
     // window
     SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
-    var w = window.open("chrome_over_plugin_window.xul", "chrome_over_plugin",
-                         "chrome,width=200,height=300");
+    var w = window.openDialog("chrome_over_plugin_window.xul", "chrome_over_plugin",
+                              "chrome,width=200,height=300,noopener", window);
   ]]>
   </script>
 </window>
--- a/layout/base/tests/chrome/test_css_visibility_propagation.xul
+++ b/layout/base/tests/chrome/test_css_visibility_propagation.xul
@@ -7,22 +7,22 @@
 <body xmlns="http://www.w3.org/1999/xhtml"></body>
 <script>
 <![CDATA[
 const baseURL = "chrome://mochitests/content/chrome/layout/base/tests/chrome/";
 
 // Tests that iframe visibility is updated when it's swapped.
 add_task(async () => {
   // Open two new windows to swap iframes.
-  const window1 =
-      window.open(baseURL + "window_css_visibility_propagation-1.html",
-                  "_blank", "chrome");
-  const window2 =
-      window.open(baseURL + "window_css_visibility_propagation-2.html",
-                  "_blank", "chrome");
+  const window1 = docShell.rootTreeItem.domWindow.open(
+      baseURL + "window_css_visibility_propagation-1.html",
+      "_blank", "chrome");
+  const window2 = docShell.rootTreeItem.domWindow.open(
+      baseURL + "window_css_visibility_propagation-2.html",
+      "_blank", "chrome");
 
   const loadWindow1 =
       new Promise(resolve => window1.addEventListener("load", resolve));
   const loadWindow2 =
       new Promise(resolve => window2.addEventListener("load", resolve));
 
   await Promise.all([ loadWindow1, loadWindow2 ]);
 
--- a/layout/base/tests/chrome/test_default_background.xul
+++ b/layout/base/tests/chrome/test_default_background.xul
@@ -10,13 +10,13 @@
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
     SimpleTest.waitForExplicitFinish();
     // Run the test in a separate window so that the test runs as a chrome
     // window
-    window.open("default_background_window.xul", "default_background",
-                "chrome,width=200,height=300");
+    window.openDialog("default_background_window.xul", "default_background",
+                      "chrome,width=200,height=300,noopener", window);
   ]]>
   </script>
 </window>
--- a/layout/base/tests/chrome/test_dialog_with_positioning.html
+++ b/layout/base/tests/chrome/test_dialog_with_positioning.html
@@ -8,13 +8,13 @@
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
 SimpleTest.waitForExplicitFinish();
 
 var root = getRootDirectory(window.location.href);
 window.openDialog(root + "dialog_with_positioning_window.xul", "dialog_with_positioning",
-                  "dialog,chrome");
+                  "dialog,chrome,noopener", window);
 </script>
 </pre>
 </body>
 </html>
--- a/layout/base/tests/chrome/test_printpreview.xul
+++ b/layout/base/tests/chrome/test_printpreview.xul
@@ -5,11 +5,11 @@
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 <body xmlns="http://www.w3.org/1999/xhtml">
 </body>
   <!-- test code goes here -->
 <script type="application/javascript">
 <![CDATA[
 SimpleTest.waitForExplicitFinish();
-window.open("printpreview_helper.xul", "printpreview", "chrome,width=100,height=100");
+window.openDialog("printpreview_helper.xul", "printpreview", "chrome,width=100,height=100,noopener", window);
 ]]></script>
 </window>
--- a/layout/base/tests/chrome/test_printpreview_bug396024.xul
+++ b/layout/base/tests/chrome/test_printpreview_bug396024.xul
@@ -11,11 +11,11 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body xmlns="http://www.w3.org/1999/xhtml">
 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=396024"
    target="_blank">Mozilla Bug 396024</a>
 </body>
   <!-- test code goes here -->
 <script type="application/javascript">
 <![CDATA[
 SimpleTest.waitForExplicitFinish();
-window.open("printpreview_bug396024_helper.xul", "bug396024", "chrome,width=100,height=100");
+window.openDialog("printpreview_bug396024_helper.xul", "bug396024", "chrome,width=100,height=100,noopener", window);
 ]]></script>
 </window>
--- a/layout/base/tests/chrome/test_printpreview_bug482976.xul
+++ b/layout/base/tests/chrome/test_printpreview_bug482976.xul
@@ -11,11 +11,11 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body xmlns="http://www.w3.org/1999/xhtml">
 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=482976"
    target="_blank">Mozilla Bug 482976</a>
 </body>
   <!-- test code goes here -->
 <script type="application/javascript">
 <![CDATA[
 SimpleTest.waitForExplicitFinish();
-window.open("printpreview_bug482976_helper.xul", "bug482976", "chrome,width=100,height=100");
+window.openDialog("printpreview_bug482976_helper.xul", "bug482976", "chrome,width=100,height=100,noopener", window);
 ]]></script>
 </window>
--- a/layout/forms/test/bug665540_window.xul
+++ b/layout/forms/test/bug665540_window.xul
@@ -1,17 +1,17 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 
 <window title="Test Select Dropdown Positioning in Fullscreen Window"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         sizemode="fullscreen">
 
   <script>
-    opener.SimpleTest.waitForFocus(opener.childFocused, window);
+    window.arguments[0].SimpleTest.waitForFocus(window.arguments[0].childFocused, window);
   </script>
 
   <body xmlns="http://www.w3.org/1999/xhtml">
     <select id="select" style="-moz-appearance:none">
       <option id="optiona">a</option>
       <option>b</option>
     </select>
   </body>
--- a/layout/forms/test/test_bug665540.html
+++ b/layout/forms/test/test_bug665540.html
@@ -26,17 +26,18 @@ var win;
 var select;
 var optiona;
 var eventType = "mouseover";
 var timeoutID;
 var eventOffsetX = 2;
 var eventOffsetY = 2;
 
 function openFullscreenWindow() {
-    win = open("bug665540_window.xul", "_blank", "resizable=yes,chrome");
+    win = window.docShell.rootTreeItem.domWindow
+                .openDialog("bug665540_window.xul", "_blank", "resizable=yes,chrome", window);
     win.addEventListener("sizemodechange",
                          function() {
                            info("sizemodechange. windowState = " + win.windowState + " fullScreen = " + win.fullScreen);
                          });
     win.addEventListener("fullscreen",
                          function() {
                            info("fullscreen event. windowState = " + win.windowState + " fullScreen = " + win.fullScreen);
                          });
--- a/layout/generic/test/file_bug514732_window.xul
+++ b/layout/generic/test/file_bug514732_window.xul
@@ -3,16 +3,20 @@
 
 <window id="514732Test"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         width="600"
         height="600"
         onload="setTimeout(nextTest,0);"
         title="bug 514732 test">
 
+  <script type="application/javascript"><![CDATA[
+    window.opener = window.arguments[0];
+  ]]></script>
+
   <script src="chrome://mochikit/content/tests/SimpleTest/docshell_helpers.js">
   </script>
 
   <script type="application/javascript"><![CDATA[
   
     // Define the generator-iterator for the tests.
     var tests = testIterator();
 
--- a/layout/generic/test/test_bug514732-2.xul
+++ b/layout/generic/test/test_bug514732-2.xul
@@ -26,15 +26,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 /** Test for Bug 514732 **/
 
 SimpleTest.waitForExplicitFinish();
-window.open("file_bug514732_window.xul", "bug514732",
-            "chrome,width=600,height=600,scrollbars");
+window.openDialog("file_bug514732_window.xul", "bug514732",
+                  "chrome,width=600,height=600,scrollbars,noopener", window);
 
 ]]>
 </script>
 
 </window>
--- a/layout/xul/test/test_resizer.xul
+++ b/layout/xul/test/test_resizer.xul
@@ -63,29 +63,29 @@ XUL <resizer> tests
     function doResizerWindowTests() {
       step++;
       if (step == 1) {
         openPopup();
         return;
       }
 
       if (/Mac/.test(navigator.platform)) {
-        window.open("window_resizer.xul", "_blank", "left=200,top=200,outerWidth=300,outerHeight=300,chrome");
+        window.openDialog("window_resizer.xul", "_blank", "left=200,top=200,outerWidth=300,outerHeight=300,chrome,noopener", window);
       }
       else {
         // Skip window_resizer.xul tests.
         todo(false, "We can't test GTK and Windows native drag resizing implementations.");
         // Run window_resizer_element.xul test only.
         lastResizerTest();
       }
     }
 
     function lastResizerTest()
     {
-      window.open("window_resizer_element.xul", "_blank", "left=200,top=200,outerWidth=300,outerHeight=300,chrome");
+      window.openDialog("window_resizer_element.xul", "_blank", "left=200,top=200,outerWidth=300,outerHeight=300,chrome,noopener", window);
     }
 
     SimpleTest.waitForFocus(openPopup);
    ]]></script>
 
 <panel id="panel" onpopupshown="popupShown(event)" onpopuphidden="doResizerWindowTests()">
   <resizer id="resizer" dir="bottomend" width="16" height="16"/>
   <hbox width="50" height="50" flex="1"/>
--- a/layout/xul/test/test_windowminmaxsize.xul
+++ b/layout/xul/test/test_windowminmaxsize.xul
@@ -81,17 +81,17 @@ function nextTest()
   // the attributes or style defined for that test. The comparisons will be
   // done by windowOpened. gTestId holds the index into the tests array.
   if (++gTestId >= tests.length) {
     // Now do the popup tests
     gTestId = -1;
     SimpleTest.waitForFocus(function () { nextPopupTest(document.getElementById("panel")) } );
   }
   else {
-    tests[gTestId].window = window.open(tests[gTestId].src, "_blank", "chrome,resizable=yes");
+    tests[gTestId].window = docShell.rootTreeItem.domWindow.open(tests[gTestId].src, "_blank", "chrome,resizable=yes");
     SimpleTest.waitForFocus(windowOpened, tests[gTestId].window);
   }
 }
 
 function windowOpened(otherWindow)
 {
   // Check the width and the width plus one due to bug 696746.
   ok(otherWindow.innerWidth == tests[gTestId].width ||
@@ -164,17 +164,17 @@ function doPanelTest(panel)
   panel.hidePopup();
 }
 
 function nextPopupTest(panel)
 {
   if (++gTestId >= popupTests.length) {
     // Next, check a panel that has a titlebar to ensure that it is accounted for
     // properly in the size.
-    var titledPanelWindow = window.open("titledpanelwindow.xul", "_blank", "chrome,resizable=yes");
+    var titledPanelWindow = docShell.rootTreeItem.domWindow.open("titledpanelwindow.xul", "_blank", "chrome,resizable=yes");
     SimpleTest.waitForFocus(titledPanelWindowOpened, titledPanelWindow);
   }
   else {
     function setattr(attr) {
       if (attr in popupTests[gTestId])
         panel.setAttribute(attr, popupTests[gTestId][attr]);
       else
         panel.removeAttribute(attr);
--- a/layout/xul/test/window_resizer.xul
+++ b/layout/xul/test/window_resizer.xul
@@ -1,15 +1,15 @@
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
     screenX="200" screenY="200" width="300" height="300"
 	onload="setTimeout(doTest, 0)">
 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 <script><![CDATA[
-var is = window.opener.SimpleTest.is;
+var is = window.arguments[0].SimpleTest.is;
 
 function doTest() {
   // from test_resizer.xul
   var expectX = 200;
   var expectY = 200;
   var expectXMost = 500;
   var expectYMost = 500;
   var screenScale = expectX/window.screenX;
@@ -85,17 +85,17 @@ function doTest() {
   Array.prototype.forEach.call(resizers, function (element) {
     is(getComputedStyle(element, "").cursor,
        element.dir == "bottomend" ? "sw-resize" :
          element.getAttribute("expectedcursor"),
        "cursor for " + element.dir);
   });
 
   window.close();
-  window.opener.lastResizerTest();
+  window.arguments[0].lastResizerTest();
 }
 ]]></script>
 	<hbox id="container" flex="1">
 		<vbox flex="1">
 			<resizer dir="topleft" expectedcursor="nw-resize" flex="1"/>
 			<resizer dir="left" expectedcursor="ew-resize" flex="1"/>
 			<resizer dir="bottomleft" expectedcursor="sw-resize" flex="1"/>
 		</vbox>
--- a/layout/xul/test/window_resizer_element.xul
+++ b/layout/xul/test/window_resizer_element.xul
@@ -1,15 +1,15 @@
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         align="start">
 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 <script><![CDATA[
-var is = window.opener.SimpleTest.is;
-window.onerror = window.opener.onerror;
+var is = window.arguments[0].SimpleTest.is;
+window.onerror = window.arguments[0].onerror;
 
 const anchorPositions =
   [ "before_start", "before_end", "after_start", "after_end",
     "start_before", "start_after", "end_before", "end_after", "overlap", "screen"];
 var currentPosition;
 
 function testResizer(resizerid, noShrink, hResize, vResize, testid)
 {
@@ -98,17 +98,17 @@ function popupShown(event)
 
   event.target.hidePopup();
 }
 
 function popupHidden()
 {
   if (anchorPositions.length == 0) {
     window.close();
-    window.opener.SimpleTest.finish();
+    window.arguments[0].SimpleTest.finish();
     return;
   }
 
   currentPosition = anchorPositions.shift();
   var anchor = document.getElementById("anchor");
   var popup = document.getElementById("anchored-panel-container");
 
   if (currentPosition == "screen")
@@ -142,17 +142,17 @@ function anchoredPopupShown(event)
 
     document.getElementById("anchored-panel").dir = resizerType;
     testResizer("anchored-panel", false, horiz, vert, currentPosition + " " + resizerType);
   }
 
   event.target.hidePopup();
 }
 
-window.opener.SimpleTest.waitForFocus(doTest, window);
+window.arguments[0].SimpleTest.waitForFocus(doTest, window);
 ]]></script>
 
 <resizer id="outside" dir="bottomend" element="outside-container"/>
 <resizer id="notfound" dir="bottomend" element="nothing"/>
 <hbox id="outside-container">
   <hbox minwidth="46" minheight="39"/>
 </hbox>
 <html:div id="html-container" xmlns:html="http://www.w3.org/1999/xhtml">
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -17,34 +17,34 @@
 **/
 
 var SimpleTest = { };
 var parentRunner = null;
 
 // In normal test runs, the window that has a TestRunner in its parent is
 // the primary window.  In single test runs, if there is no parent and there
 // is no opener then it is the primary window.
-var isSingleTestRun = (parent == window && !opener)
+var isSingleTestRun = (parent == window && !(opener || window.arguments && window.arguments[0].SimpleTest));
 try {
   var isPrimaryTestWindow = !!parent.TestRunner || isSingleTestRun;
 } catch(e) {
   dump("TEST-UNEXPECTED-FAIL, Exception caught: " + e.message +
                 ", at: " + e.fileName + " (" + e.lineNumber +
                 "), location: " + window.location.href + "\n");
 }
 // Finds the TestRunner for this test run and the SpecialPowers object (in
 // case it is not defined) from a parent/opener window.
 //
 // Finding the SpecialPowers object is needed when we have ChromePowers in
 // harness.xul and we need SpecialPowers in the iframe, and also for tests
 // like test_focus.xul where we open a window which opens another window which
 // includes SimpleTest.js.
 (function() {
     function ancestor(w) {
-        return w.parent != w ? w.parent : w.opener;
+        return w.parent != w ? w.parent : w.opener || w.arguments && w.arguments[0];
     }
 
     var w = ancestor(window);
     while (w && (!parentRunner || !window.SpecialPowers)) {
         if (!parentRunner) {
             parentRunner = w.TestRunner;
             if (!parentRunner && w.wrappedJSObject) {
                 parentRunner = w.wrappedJSObject.TestRunner;
--- a/testing/web-platform/meta/2dcontext/wide-gamut-canvas/canvas-colorManaged-convertToBlob-roundtrip.html.ini
+++ b/testing/web-platform/meta/2dcontext/wide-gamut-canvas/canvas-colorManaged-convertToBlob-roundtrip.html.ini
@@ -1,5 +1,8 @@
 [canvas-colorManaged-convertToBlob-roundtrip.html]
-  expected: ERROR
+  expected: TIMEOUT
   [Test canvas convertToBlob(): mimeType: image/png, blobPixelFormat: uint8, source color space: srgb, pixel format: uint8, alpha: 0.5]
     expected: NOTRUN
 
+  [Overall test]
+    expected: FAIL
+
--- a/testing/web-platform/meta/2dcontext/wide-gamut-canvas/canvas-draw-high-bit-depth-images.html.ini
+++ b/testing/web-platform/meta/2dcontext/wide-gamut-canvas/canvas-draw-high-bit-depth-images.html.ini
@@ -1,122 +1,121 @@
 [canvas-draw-high-bit-depth-images.html]
-  expected: ERROR
   [Canvas color params: srgb, float16. Testing 2x2_8bit_Rec2020_opaque.png vs 2x2_16bit_Rec2020_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_ProPhoto_opaque.png vs 2x2_16bit_interlaced_ProPhoto_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_sRGB_opaque.png vs 2x2_16bit_sRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_DisplayP3_opaque.png vs 2x2_16bit_DisplayP3_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_sRGB_transparent.png vs 2x2_16bit_sRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_DisplayP3_transparent.png vs 2x2_16bit_interlaced_DisplayP3_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_ProPhoto_opaque.png vs 2x2_16bit_ProPhoto_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_ProPhoto_transparent.png vs 2x2_16bit_interlaced_ProPhoto_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_AdobeRGB_transparent.png vs 2x2_16bit_interlaced_AdobeRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_DisplayP3_transparent.png vs 2x2_16bit_DisplayP3_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_DisplayP3_opaque.png vs 2x2_16bit_interlaced_DisplayP3_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_ProPhoto_opaque.png vs 2x2_16bit_ProPhoto_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_Rec2020_transparent.png vs 2x2_16bit_Rec2020_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_AdobeRGB_opaque.png vs 2x2_16bit_AdobeRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_AdobeRGB_opaque.png vs 2x2_16bit_interlaced_AdobeRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_ProPhoto_transparent.png vs 2x2_16bit_interlaced_ProPhoto_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_Rec2020_transparent.png vs 2x2_16bit_interlaced_Rec2020_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_ProPhoto_transparent.png vs 2x2_16bit_ProPhoto_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_AdobeRGB_transparent.png vs 2x2_16bit_AdobeRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_AdobeRGB_transparent.png vs 2x2_16bit_interlaced_AdobeRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_sRGB_opaque.png vs 2x2_16bit_interlaced_sRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_DisplayP3_transparent.png vs 2x2_16bit_interlaced_DisplayP3_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_sRGB_opaque.png vs 2x2_16bit_sRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_AdobeRGB_opaque.png vs 2x2_16bit_interlaced_AdobeRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_AdobeRGB_transparent.png vs 2x2_16bit_AdobeRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_Rec2020_opaque.png vs 2x2_16bit_interlaced_Rec2020_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_Rec2020_opaque.png vs 2x2_16bit_interlaced_Rec2020_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_DisplayP3_opaque.png vs 2x2_16bit_interlaced_DisplayP3_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_Rec2020_transparent.png vs 2x2_16bit_interlaced_Rec2020_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_ProPhoto_transparent.png vs 2x2_16bit_ProPhoto_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_DisplayP3_opaque.png vs 2x2_16bit_DisplayP3_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_Rec2020_transparent.png vs 2x2_16bit_Rec2020_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_DisplayP3_transparent.png vs 2x2_16bit_DisplayP3_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_sRGB_transparent.png vs 2x2_16bit_sRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_sRGB_transparent.png vs 2x2_16bit_interlaced_sRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_AdobeRGB_opaque.png vs 2x2_16bit_AdobeRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_Rec2020_opaque.png vs 2x2_16bit_Rec2020_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_ProPhoto_opaque.png vs 2x2_16bit_interlaced_ProPhoto_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, uint8. Testing 2x2_8bit_sRGB_transparent.png vs 2x2_16bit_interlaced_sRGB_transparent.png]
-    expected: TIMEOUT
+    expected: FAIL
 
   [Canvas color params: srgb, float16. Testing 2x2_8bit_sRGB_opaque.png vs 2x2_16bit_interlaced_sRGB_opaque.png]
-    expected: TIMEOUT
+    expected: FAIL
 
--- a/testing/web-platform/meta/accelerometer/Accelerometer.https.html.ini
+++ b/testing/web-platform/meta/accelerometer/Accelerometer.https.html.ini
@@ -123,8 +123,197 @@
     expected: FAIL
 
   [LinearAccelerationSensor: sensor reading is correct when options.referenceFrame is 'screen']
     expected: FAIL
 
   [LinearAccelerationSensor: throw 'TypeError' if referenceFrame is not one of enumeration values]
     expected: FAIL
 
+  [LinearAccelerationSensor: frequency hint works.]
+    expected: FAIL
+
+  [Accelerometer: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [GravitySensor: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [Accelerometer: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [Accelerometer: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [GravitySensor: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [Accelerometer: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [GravitySensor: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [GravitySensor: sensor reading is correct.]
+    expected: FAIL
+
+  [GravitySensor: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [GravitySensor: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [GravitySensor: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
+  [Accelerometer: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [GravitySensor: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [GravitySensor: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [Accelerometer: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [Accelerometer: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [Accelerometer: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [GravitySensor: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [Accelerometer: sensor reading is correct.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [GravitySensor: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [GravitySensor: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [Accelerometer: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [GravitySensor: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
+  [GravitySensor: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [GravitySensor: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [Accelerometer: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [Accelerometer: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [Accelerometer: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [GravitySensor: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [Accelerometer: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [Accelerometer: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [GravitySensor: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [Accelerometer: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [GravitySensor: frequency hint works.]
+    expected: FAIL
+
+  [Accelerometer: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [GravitySensor: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: sensor reading is correct.]
+    expected: FAIL
+
+  [GravitySensor: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [Accelerometer: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [Accelerometer: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [LinearAccelerationSensor: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [Accelerometer: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [Accelerometer: frequency hint works.]
+    expected: FAIL
+
+  [GravitySensor: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [LinearAccelerationSensor: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/ambient-light/AmbientLightSensor.https.html.ini
+++ b/testing/web-platform/meta/ambient-light/AmbientLightSensor.https.html.ini
@@ -33,8 +33,65 @@
     expected: FAIL
 
   [AmbientLightSensor: sensor receives suspend / resume notifications when  cross-origin subframe is focused]
     expected: FAIL
 
   [AmbientLightSensor: throw 'TypeError' if frequency is invalid]
     expected: FAIL
 
+  [AmbientLightSensor: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [AmbientLightSensor: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [AmbientLightSensor: sensor reading is correct.]
+    expected: FAIL
+
+  [AmbientLightSensor: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [AmbientLightSensor: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [AmbientLightSensor: frequency hint works.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [AmbientLightSensor: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [AmbientLightSensor: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [AmbientLightSensor: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [AmbientLightSensor: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [AmbientLightSensor: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/content-security-policy/navigate-to/href-location-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/navigate-to/href-location-blocked.sub.html.ini
@@ -1,5 +1,6 @@
 [href-location-blocked.sub.html]
   [Violation report status OK.]
     expected:
+      if (os == "android") and not debug: ["PASS", "FAIL"]
       if (os == "android") and debug: ["PASS", "FAIL"]
 
--- a/testing/web-platform/meta/cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html.ini
+++ b/testing/web-platform/meta/cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html.ini
@@ -1,22 +1,22 @@
 [serviceworker_cookieStore_subscriptions.tentative.https.html]
   disabled:
     if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1573036
     if (os == "win") and (processor == "aarch64"): https://bugzilla.mozilla.org/show_bug.cgi?id=1573036
   expected:
-    if (os == "mac") and not debug: ["TIMEOUT", "OK"]
+    if (os == "mac") and not debug: ["OK", "TIMEOUT"]
     TIMEOUT
   [getChangeSubscriptions returns subscriptions passed to subscribeToChanges]
     expected:
-      if (os == "mac") and not debug: ["TIMEOUT", "FAIL"]
+      if (os == "mac") and not debug: ["FAIL", "TIMEOUT"]
       TIMEOUT
 
   [subscribeToChanges rejects when called outside the install handler]
     expected:
-      if (os == "mac") and not debug: ["NOTRUN", "FAIL"]
+      if (os == "mac") and not debug: ["FAIL", "NOTRUN"]
       NOTRUN
 
   [cookiechange dispatched with cookie change that matches subscription]
     expected:
-      if (os == "mac") and not debug: ["NOTRUN", "FAIL"]
+      if (os == "mac") and not debug: ["FAIL", "NOTRUN"]
       NOTRUN
 
--- a/testing/web-platform/meta/css/CSS2/positioning/relpos-percentage-top-in-scrollable.html.ini
+++ b/testing/web-platform/meta/css/CSS2/positioning/relpos-percentage-top-in-scrollable.html.ini
@@ -1,6 +1,6 @@
 [relpos-percentage-top-in-scrollable.html]
   [Top percentage resolved correctly for overflow contribution]
     expected:
+      if (os == "android") and not debug: ["FAIL", "PASS"]
       if (os == "android") and debug: FAIL
-      if (os == "android") and not debug: ["PASS", "FAIL"]
 
--- a/testing/web-platform/meta/css/css-pseudo/first-letter-property-whitelist.html.ini
+++ b/testing/web-platform/meta/css/css-pseudo/first-letter-property-whitelist.html.ini
@@ -11,23 +11,18 @@
   [Whitelisted property borderRadius should be applied to first-letter pseudo elements.]
     expected: FAIL
 
   [Whitelisted property font should be applied to first-letter pseudo elements.]
     expected: FAIL
 
   [Whitelisted property fontVariationSettings should be applied to first-letter pseudo elements.]
     expected:
-      if (os == "android") and not e10s: PASS
       if ((os == "mac") and (version == "OS X 10.14")) or (version == "OS X 10.13"): PASS
-      if ((os == "mac") and (version == "OS X 10.14.5")) or (version == "OS X 10.13"): PASS
-      if os == "linux": PASS
-      if (os == "win") and (version == "10.0.17134"): PASS
-      if (os == "android") and e10s: PASS
-      FAIL
+      if (processor == "x86") and (os == "win"): FAIL
 
   [Whitelisted property margin should be applied to first-letter pseudo elements.]
     expected: FAIL
 
   [Whitelisted property padding should be applied to first-letter pseudo elements.]
     expected: FAIL
 
   [Whitelisted property opacity should be applied to first-letter pseudo elements.]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-transforms/animation/perspective-interpolation.html.ini
@@ -0,0 +1,318 @@
+[perspective-interpolation.html]
+  expected:
+    if (processor == "x86") and debug: CRASH
+  [CSS Transitions: property <perspective> from [inherit\] to [20px\] at (-0.3) should be [33px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [50px\] to [100px\] at (1.5) should be [125px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [Web Animations: property <perspective> from neutral to [20px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [Web Animations: property <perspective> from [unset\] to [20px\] at (0.5) should be [20px\]]
+    expected:
+      if (os == "win") and (processor == "x86_64"): FAIL
+
+  [CSS Transitions: property <perspective> from neutral to [20px\] at (1.5) should be [25px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [50px\] to [100px\] at (-0.3) should be [35px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [inherit\] to [20px\] at (-20) should be [230px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [50px\] to [100px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [CSS Animations: property <perspective> from neutral to [20px\] at (0.6) should be [16px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from neutral to [20px\] at (0.6) should be [16px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [50px\] to [100px\] at (1.5) should be [125px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [100px\] at (1.5) should be [125px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from neutral to [20px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Transitions: property <perspective> from [50px\] to [100px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Animations: property <perspective> from neutral to [20px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [100px\] at (-0.3) should be [35px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [100px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [Web Animations: property <perspective> from [50px\] to [100px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [CSS Transitions: property <perspective> from [50px\] to [100px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from neutral to [20px\] at (1.5) should be [25px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [50px\] to [100px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Animations: property <perspective> from [inherit\] to [20px\] at (1.5) should be [15px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [50px\] to [100px\] at (0.3) should be [65px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [unset\] to [20px\] at (0.6) should be [20px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [inherit\] to [20px\] at (0.6) should be [24px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [inherit\] to [20px\] at (-1) should be [40px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [50px\] to [100px\] at (0.6) should be [80px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [100px\] at (0.3) should be [65px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [inherit\] to [20px\] at (0.6) should be [24px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [inherit\] to [20px\] at (0.6) should be [24px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from neutral to [20px\] at (-0.3) should be [7px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [inherit\] to [20px\] at (0.3) should be [27px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [inherit\] to [20px\] at (-20) should be [230px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [inherit\] to [20px\] at (1.5) should be [15px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from neutral to [20px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [none\] at (0.5) should be [none\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [100px\] at (0.6) should be [80px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [inherit\] to [20px\] at (0.3) should be [27px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [none\] at (0.6) should be [none\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [unset\] to [20px\] at (0.5) should be [20px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [50px\] to [100px\] at (0.6) should be [80px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [Web Animations: property <perspective> from neutral to [20px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [100px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Transitions: property <perspective> from neutral to [20px\] at (0.3) should be [13px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from neutral to [20px\] at (0.3) should be [13px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [initial\] to [20px\] at (0.5) should be [20px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [inherit\] to [20px\] at (-0.3) should be [33px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [Web Animations: property <perspective> from [initial\] to [20px\] at (0.5) should be [20px\]]
+    expected:
+      if (os == "win") and (processor == "x86_64"): FAIL
+
+  [CSS Transitions: property <perspective> from [inherit\] to [20px\] at (-20) should be [230px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [Web Animations: property <perspective> from [50px\] to [none\] at (0.5) should be [none\]]
+    expected:
+      if (os == "win") and (processor == "x86_64"): FAIL
+
+  [CSS Animations: property <perspective> from [initial\] to [20px\] at (0.6) should be [20px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from neutral to [20px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [CSS Transitions: property <perspective> from neutral to [20px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from neutral to [20px\] at (0.3) should be [13px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [50px\] to [100px\] at (-0.3) should be [35px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from neutral to [20px\] at (1.5) should be [25px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from neutral to [20px\] at (-0.3) should be [7px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [50px\] to [100px\] at (0.3) should be [65px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from [inherit\] to [20px\] at (1.5) should be [15px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from neutral to [20px\] at (-0.3) should be [7px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective> from neutral to [20px\] at (0.6) should be [16px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [inherit\] to [20px\] at (-0.3) should be [33px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [50px\] to [none\] at (1.5) should be [none\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [Web Animations: property <perspective> from [50px\] to [100px\] at (-20) should be [none\]]
+    expected: FAIL
+
+  [CSS Transitions: property <perspective> from neutral to [20px\] at (-1) should be [none\]]
+    expected: FAIL
+
+  [CSS Animations: property <perspective> from [inherit\] to [20px\] at (-1) should be [40px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective> from [inherit\] to [20px\] at (-1) should be [40px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [initial\] to [20px\] at (1.5) should be [20px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [unset\] to [20px\] at (1.5) should be [20px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective> from [inherit\] to [20px\] at (0.3) should be [27px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-transforms/animation/perspective-origin-interpolation.html.ini
@@ -0,0 +1,303 @@
+[perspective-origin-interpolation.html]
+  expected:
+    if (processor == "x86") and debug: CRASH
+  [CSS Transitions with transition: all: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (1.5) should be [75px 100px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [unset\] to [20px 20px\] at (1.5) should be [17.5px 17.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [initial\] to [20px 20px\] at (0.6) should be [22px 22px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [inherit\] to [20px 20px\] at (0.6) should be [24px 16px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [initial\] to [20px 20px\] at (0.3) should be [23.5px 23.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from neutral to [20px 20px\] at (0.6) should be [16px 24px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [inherit\] to [20px 20px\] at (0.3) should be [27px 13px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [initial\] to [20px 20px\] at (0.3) should be [23.5px 23.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (0.6) should be [30px 55px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from neutral to [20px 20px\] at (0.3) should be [13px 27px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [unset\] to [20px 20px\] at (-0.3) should be [26.5px 26.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [inherit\] to [20px 20px\] at (-0.3) should be [33px 7px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (0.3) should be [15px 40px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [inherit\] to [20px 20px\] at (0.3) should be [27px 13px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from neutral to [20px 20px\] at (0.6) should be [16px 24px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (0.3) should be [15px 40px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [inherit\] to [20px 20px\] at (0.3) should be [27px 13px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [unset\] to [20px 20px\] at (0.3) should be [23.5px 23.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from neutral to [20px 20px\] at (0.3) should be [13px 27px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [inherit\] to [20px 20px\] at (0.6) should be [24px 16px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [unset\] to [20px 20px\] at (0.6) should be [22px 22px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [unset\] to [20px 20px\] at (0.3) should be [23.5px 23.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from neutral to [20px 20px\] at (0.6) should be [16px 24px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [unset\] to [20px 20px\] at (1.5) should be [17.5px 17.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [initial\] to [20px 20px\] at (0.6) should be [22px 22px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from neutral to [20px 20px\] at (-0.3) should be [7px 33px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [inherit\] to [20px 20px\] at (-0.3) should be [33px 7px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [initial\] to [20px 20px\] at (-0.3) should be [26.5px 26.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [initial\] to [20px 20px\] at (1.5) should be [17.5px 17.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [inherit\] to [20px 20px\] at (1.5) should be [15px 25px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [unset\] to [20px 20px\] at (-0.3) should be [26.5px 26.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [inherit\] to [20px 20px\] at (0.6) should be [24px 16px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (0.6) should be [30px 55px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [initial\] to [20px 20px\] at (1.5) should be [17.5px 17.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (0.6) should be [30px 55px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [initial\] to [20px 20px\] at (1.5) should be [17.5px 17.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (1.5) should be [75px 100px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [inherit\] to [20px 20px\] at (1.5) should be [15px 25px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [unset\] to [20px 20px\] at (0.6) should be [22px 22px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [unset\] to [20px 20px\] at (0.3) should be [23.5px 23.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from neutral to [20px 20px\] at (0.3) should be [13px 27px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [inherit\] to [20px 20px\] at (1.5) should be [15px 25px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [unset\] to [20px 20px\] at (1.5) should be [17.5px 17.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (-0.3) should be [-15px 10px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (1.5) should be [75px 100px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [initial\] to [20px 20px\] at (0.6) should be [22px 22px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [unset\] to [20px 20px\] at (-0.3) should be [26.5px 26.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (-0.3) should be [-15px 10px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [initial\] to [20px 20px\] at (-0.3) should be [26.5px 26.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from neutral to [20px 20px\] at (1.5) should be [25px 15px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from neutral to [20px 20px\] at (1.5) should be [25px 15px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [inherit\] to [20px 20px\] at (-0.3) should be [33px 7px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [unset\] to [20px 20px\] at (0.6) should be [22px 22px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions with transition: all: property <perspective-origin> from [initial\] to [20px 20px\] at (-0.3) should be [26.5px 26.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (0.3) should be [15px 40px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from neutral to [20px 20px\] at (-0.3) should be [7px 33px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from neutral to [20px 20px\] at (-0.3) should be [7px 33px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Animations: property <perspective-origin> from [0% 50%\] to [100% 150%\] at (-0.3) should be [-15px 10px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from neutral to [20px 20px\] at (1.5) should be [25px 15px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
+  [CSS Transitions: property <perspective-origin> from [initial\] to [20px 20px\] at (0.3) should be [23.5px 23.5px\]]
+    expected:
+      if (processor == "x86") and (os == "win"): FAIL
+      if processor == "aarch64": FAIL
+
--- a/testing/web-platform/meta/css/css-ui/appearance-auto-001.html.ini
+++ b/testing/web-platform/meta/css/css-ui/appearance-auto-001.html.ini
@@ -1,7 +1,7 @@
 [appearance-auto-001.html]
   disabled:
     if debug and (os == "win") and (version == "6.1.7601"): https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
   expected:
-    if (os == "win") and (processor == "x86"): FAIL
     if (os == "win") and (processor == "x86_64"): FAIL
     if (os == "win") and (processor == "aarch64"): ["FAIL", "PASS"]
+    if (os == "win") and (processor == "x86"): FAIL
--- a/testing/web-platform/meta/css/css-ui/appearance-checkbox-001.html.ini
+++ b/testing/web-platform/meta/css/css-ui/appearance-checkbox-001.html.ini
@@ -1,7 +1,7 @@
 [appearance-checkbox-001.html]
   disabled:
     if debug and (os == "win") and (version == "6.1.7601"): https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
   expected:
     if (os == "win") and (processor == "x86"): FAIL
+    if (os == "win") and (processor == "aarch64"): ["FAIL", "PASS"]
     if (os == "win") and (processor == "x86_64"): FAIL
-    if (os == "win") and (processor == "aarch64"): ["FAIL", "PASS"]
--- a/testing/web-platform/meta/css/css-ui/appearance-textfield-001.html.ini
+++ b/testing/web-platform/meta/css/css-ui/appearance-textfield-001.html.ini
@@ -1,5 +1,5 @@
 [appearance-textfield-001.html]
   expected:
-    if (os == "win") and (processor == "x86"): ["FAIL", "PASS"]
-    if (os == "win") and (processor == "x86_64"): ["FAIL", "PASS"]
-    if (os == "win") and (processor == "aarch64"): ["FAIL", "PASS"]
+    if (os == "win") and debug and (processor == "x86_64"): ["FAIL", "PASS"]
+    if (os == "win") and debug and (processor == "x86"): ["PASS", "FAIL"]
+    if (os == "win") and not debug: ["FAIL", "PASS"]
--- a/testing/web-platform/meta/css/css-variables/variable-presentation-attribute.html.ini
+++ b/testing/web-platform/meta/css/css-variables/variable-presentation-attribute.html.ini
@@ -1,13 +1,13 @@
 [variable-presentation-attribute.html]
   [Testing 'clip' on '#test4'.]
     expected:
+      if os == "android": FAIL
       if os == "linux": FAIL
-      if os == "android": FAIL
 
   [Testing 'alignment-baseline'.]
     expected: FAIL
 
   [Testing 'baseline-shift'.]
     expected: FAIL
 
   [Testing 'color-interpolation-filters'.]
--- a/testing/web-platform/meta/css/motion/parsing/offset-path-parsing-valid.html.ini
+++ b/testing/web-platform/meta/css/motion/parsing/offset-path-parsing-valid.html.ini
@@ -1,10 +1,9 @@
 [offset-path-parsing-valid.html]
-
   [Serialization should round-trip after setting e.style['offset-path'\] = "fill-box ellipse(50% 60%)"]
     expected: FAIL
 
   [e.style['offset-path'\] = "url(\\"http://www.example.com/index.html#polyline1\\")" should set the property value]
     expected: FAIL
 
   [Serialization should round-trip after setting e.style['offset-path'\] = "url(\\"http://www.example.com/index.html#polyline1\\")"]
     expected: FAIL
--- a/testing/web-platform/meta/fetch/sec-metadata/redirect/redirect-http-upgrade.tentative.sub.html.ini
+++ b/testing/web-platform/meta/fetch/sec-metadata/redirect/redirect-http-upgrade.tentative.sub.html.ini
@@ -32,17 +32,17 @@
       if (os == "win") and debug: [wpt-sync Bug 1565002, https://bugzilla.mozilla.org/show_bug.cgi?id=1568816]
       if (os == "linux") and (processor == "x86_64") and not debug and webrender: wpt-sync Bug 1565002
       if (os == "linux") and (processor == "x86_64") and not debug and not webrender: wpt-sync Bug 1565002
       if (os == "linux") and (processor == "x86_64") and debug and webrender: wpt-sync Bug 1565002
       if (os == "linux") and (processor == "x86_64") and debug and not webrender and not sw-e10s: wpt-sync Bug 1565002
       if (os == "linux") and (processor == "x86_64") and debug and not webrender and sw-e10s: wpt-sync Bug 1565002
       if (os == "mac") and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1568816
     expected:
-      if os == "linux": ["TIMEOUT", "FAIL"]
+      if os == "linux": ["FAIL", "TIMEOUT"]
       FAIL
 
   [Http upgrade fetch() api => No headers]
     expected: FAIL
 
   [redirect-http-upgrade]
     expected: FAIL
 
--- a/testing/web-platform/meta/geolocation-sensor/GeolocationSensor.https.html.ini
+++ b/testing/web-platform/meta/geolocation-sensor/GeolocationSensor.https.html.ini
@@ -33,8 +33,65 @@
     expected: FAIL
 
   [GeolocationSensor: sensor receives suspend / resume notifications when  cross-origin subframe is focused]
     expected: FAIL
 
   [GeolocationSensor: throw 'TypeError' if frequency is invalid]
     expected: FAIL
 
+  [GeolocationSensor: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [GeolocationSensor: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [GeolocationSensor: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [GeolocationSensor: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [GeolocationSensor: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [GeolocationSensor: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [GeolocationSensor: frequency hint works.]
+    expected: FAIL
+
+  [GeolocationSensor: sensor reading is correct.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [GeolocationSensor: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [GeolocationSensor: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/gyroscope/Gyroscope.https.html.ini
+++ b/testing/web-platform/meta/gyroscope/Gyroscope.https.html.ini
@@ -39,8 +39,71 @@
     expected: FAIL
 
   [Gyroscope: sensor reading is correct when options.referenceFrame is 'screen']
     expected: FAIL
 
   [Gyroscope: throw 'TypeError' if referenceFrame is not one of enumeration values]
     expected: FAIL
 
+  [Gyroscope: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [Gyroscope: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [Gyroscope: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [Gyroscope: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [Gyroscope: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [Gyroscope: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [Gyroscope: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [Gyroscope: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [Gyroscope: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
+  [Gyroscope: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [Gyroscope: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [Gyroscope: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [Gyroscope: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [Gyroscope: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [Gyroscope: sensor reading is correct.]
+    expected: FAIL
+
+  [Gyroscope: frequency hint works.]
+    expected: FAIL
+
+  [Gyroscope: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
+  [Gyroscope: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [Gyroscope: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [Gyroscope: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [Gyroscope: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/html/semantics/forms/autofocus/skip-not-fully-active.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/autofocus/skip-not-fully-active.html.ini
@@ -1,7 +1,6 @@
 [skip-not-fully-active.html]
   [Autofocus element in not-fully-active document should be skipped while flusing.]
     expected:
-      if debug and (os == "linux") and webrender: ["PASS", "FAIL"]
-      if debug and (os == "linux") and not webrender: ["FAIL", "PASS"]
-      FAIL
+      if (os == "linux") and debug and not webrender: ["PASS", "FAIL"]
+      if (os == "linux") and debug and webrender: ["PASS", "FAIL"]
 
--- a/testing/web-platform/meta/html/semantics/forms/autofocus/update-the-rendering.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/autofocus/update-the-rendering.html.ini
@@ -1,10 +1,11 @@
 [update-the-rendering.html]
   ["Flush autofocus candidates" should be happen after the first animation frame callbacks, and before a resize event in the next iteration of window event loop.]
     expected:
-      if (os == "linux") and not debug and (processor == "x86_64") and webrender: ["FAIL", "PASS"]
+      if (os == "linux") and debug and not webrender and sw-e10s: ["FAIL", "PASS"]
+      if (os == "linux") and debug and not webrender and not sw-e10s: ["PASS", "FAIL"]
+      if (os == "linux") and not debug and (processor == "x86_64") and webrender: ["PASS", "FAIL"]
       if (os == "linux") and not debug and (processor == "x86_64") and not webrender: ["FAIL", "PASS"]
-      if (os == "linux") and debug and not sw-e10s: ["PASS", "FAIL"]
-      if (os == "linux") and debug and sw-e10s: ["FAIL", "PASS"]
+      if (os == "linux") and debug and webrender: ["FAIL", "PASS"]
       if (os == "win") and debug: ["FAIL", "PASS"]
       FAIL
 
--- a/testing/web-platform/meta/magnetometer/Magnetometer.https.html.ini
+++ b/testing/web-platform/meta/magnetometer/Magnetometer.https.html.ini
@@ -81,8 +81,134 @@
     expected: FAIL
 
   [UncalibratedMagnetometer: sensor reading is correct when options.referenceFrame is 'screen']
     expected: FAIL
 
   [UncalibratedMagnetometer: throw 'TypeError' if referenceFrame is not one of enumeration values]
     expected: FAIL
 
+  [UncalibratedMagnetometer: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [Magnetometer: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [Magnetometer: frequency hint works.]
+    expected: FAIL
+
+  [Magnetometer: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [Magnetometer: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [Magnetometer: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [Magnetometer: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [Magnetometer: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [Magnetometer: sensor reading is correct.]
+    expected: FAIL
+
+  [Magnetometer: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
+  [Magnetometer: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [Magnetometer: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [Magnetometer: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: sensor reading is correct.]
+    expected: FAIL
+
+  [Magnetometer: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
+  [Magnetometer: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [Magnetometer: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [Magnetometer: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [Magnetometer: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [Magnetometer: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [Magnetometer: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [Magnetometer: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [UncalibratedMagnetometer: frequency hint works.]
+    expected: FAIL
+
+  [Magnetometer: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/mathml/presentation-markup/operators/operator-dictionary-001.html.ini
@@ -0,0 +1,107 @@
+[operator-dictionary-001.html]
+  expected:
+    if debug and (os == "linux") and sw-e10s: ["CRASH", "OK"]
+    if debug and (os == "linux") and not sw-e10s: CRASH
+    if debug and (os == "mac"): CRASH
+    if debug and (os == "win"): CRASH
+  [Operator dictionary chunk 11 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 14 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 13 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 16 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 9 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 19 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 6 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 5 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 21 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 7 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 8 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 15 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 4 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 20 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 3 - accent]
+    expected: FAIL
+
+  [Operator dictionary chunk 22 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 18 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 1 - accent]
+    expected: FAIL
+
+  [Operator dictionary chunk 2 - accent]
+    expected: FAIL
+
+  [Operator dictionary chunk 23 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 10 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 12 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 1 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 3 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 2 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
+  [Operator dictionary chunk 17 - movablelimits]
+    expected:
+      if os == "win": FAIL
+
--- a/testing/web-platform/meta/mediacapture-fromelement/creation.html.ini
+++ b/testing/web-platform/meta/mediacapture-fromelement/creation.html.ini
@@ -1,9 +1,11 @@
 [creation.html]
+  expected:
+    if webrender and (os == "linux") and not debug: ["OK", "CRASH"]
   [Untitled]
     expected: FAIL
 
   [Untitled 1]
     expected: FAIL
 
   [Untitled 2]
     expected: FAIL
--- a/testing/web-platform/meta/mozilla-sync
+++ b/testing/web-platform/meta/mozilla-sync
@@ -1,2 +1,2 @@
-local: aa6b15de4eae0530e3dff3320ba5218289e4a7ec
-upstream: 9b5a07c75793477c12a9eb67f3d8b594dbab0e82
+local: 3d4dffa643fe969ce250e882aab5064ee3765e9c
+upstream: 6d3088b17a01314dde58a11a7ba0a99e33375e1a
--- a/testing/web-platform/meta/orientation-sensor/AbsoluteOrientationSensor.https.html.ini
+++ b/testing/web-platform/meta/orientation-sensor/AbsoluteOrientationSensor.https.html.ini
@@ -42,8 +42,71 @@
     expected: FAIL
 
   [AbsoluteOrientationSensor: sensor reading is correct when options.referenceFrame is 'screen']
     expected: FAIL
 
   [AbsoluteOrientationSensor: throw 'TypeError' if referenceFrame is not one of enumeration values]
     expected: FAIL
 
+  [AbsoluteOrientationSensor: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: frequency hint works.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: sensor reading is correct.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [AbsoluteOrientationSensor: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/orientation-sensor/RelativeOrientationSensor.https.html.ini
+++ b/testing/web-platform/meta/orientation-sensor/RelativeOrientationSensor.https.html.ini
@@ -42,8 +42,71 @@
     expected: FAIL
 
   [RelativeOrientationSensor: sensor reading is correct when options.referenceFrame is 'screen']
     expected: FAIL
 
   [RelativeOrientationSensor: throw 'TypeError' if referenceFrame is not one of enumeration values]
     expected: FAIL
 
+  [RelativeOrientationSensor: frequency hint works.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: sensor.stop() returns undefined.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that frequency is capped to the maximum supported frequency.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: sensor timestamp is updated when time passes.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: no exception is thrown when calling stop() on already stopped sensor.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: sensor.start() returns undefined.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: sensor reading is correct when options.referenceFrame is 'screen'.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that onerror is send when start() call has failed.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: sensor reading is correct.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that onerror is sent when permissions are not granted.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: throw 'TypeError' if referenceFrame is not one of enumeration values.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: sensor receives suspend / resume notifications when cross-origin subframe is focused.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that frequency is limited to the minimum supported frequency.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that onerror is sent when sensor is not supported.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that 'onreading' is called and sensor reading is valid.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that sensor can be constructed within an iframe allowed to use feature policy.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that frequency is capped to allowed maximum.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: throw 'TypeError' if frequency is invalid.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that fresh reading is fetched on start().]
+    expected: FAIL
+
+  [RelativeOrientationSensor: no exception is thrown when calling start() on already started sensor.]
+    expected: FAIL
+
+  [RelativeOrientationSensor: Test that sensor cannot be constructed within iframe disallowed to use feature policy.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/pointerevents/pointerlock/pointerevent_movementxy.html.ini
+++ b/testing/web-platform/meta/pointerevents/pointerlock/pointerevent_movementxy.html.ini
@@ -1,9 +1,8 @@
 [pointerevent_movementxy.html]
   expected:
-    if (os == "win") and debug and webrender: ["OK", "ERROR"]
-    if (os == "linux") and sw-e10s: ["OK", "ERROR"]
-    if os == "mac": ["OK", "ERROR"]
+    if debug and not webrender and (os == "mac"): ["OK", "ERROR"]
+    if debug and webrender: ["OK", "ERROR"]
     [ERROR, OK]
   [mouse pointerevent attributes]
     expected: FAIL
 
--- a/testing/web-platform/meta/pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html.ini
+++ b/testing/web-platform/meta/pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html.ini
@@ -1,12 +1,10 @@
 [pointerevent_movementxy_with_pointerlock.html]
   [mouse pointerevent movementX/Y with pointerlock test]
     expected:
-      if (os == "win") and (processor == "x86_64") and webrender and debug: ["FAIL", "PASS"]
-      if (os == "win") and (processor == "x86") and debug: ["FAIL", "PASS"]
-      if (os == "win") and (processor == "x86_64") and not webrender: ["FAIL", "PASS"]
+      if (os == "win") and (processor == "x86_64") and not webrender and not debug: ["FAIL", "PASS"]
+      if (os == "linux") and not sw-e10s and webrender and debug: ["FAIL", "PASS"]
       if (os == "win") and (processor == "aarch64"): ["FAIL", "PASS"]
       if (os == "linux") and sw-e10s: ["FAIL", "PASS"]
       if (os == "mac") and not debug: ["FAIL", "PASS"]
-      if (os == "mac") and debug: ["FAIL", "PASS"]
       [PASS, FAIL]
 
--- a/testing/web-platform/meta/proximity/ProximitySensor-iframe-access.https.html.ini
+++ b/testing/web-platform/meta/proximity/ProximitySensor-iframe-access.https.html.ini
@@ -3,8 +3,11 @@
     expected: FAIL
 
   [ProximitySensor: sensor is not suspended when focus traverses from to same-origin frame]
     expected: FAIL
 
   [ProximitySensor: losing a document's frame with an active sensor does not crash]
     expected: FAIL
 
+  [ProximitySensor iframe test]
+    expected: FAIL
+
--- a/testing/web-platform/meta/resize-observer/observe.html.ini
+++ b/testing/web-platform/meta/resize-observer/observe.html.ini
@@ -1,14 +1,14 @@
 [observe.html]
   expected:
-    if webrender and (os == "linux") and debug: ["OK", "TIMEOUT"]
     if webrender and (os == "linux") and not debug: ["OK", "TIMEOUT"]
+    if webrender and (os == "linux") and debug: ["TIMEOUT", "OK"]
   [guard]
     expected:
-      if webrender and (os == "linux") and debug: ["PASS", "NOTRUN"]
+      if webrender and (os == "linux") and debug: ["NOTRUN", "PASS"]
       if webrender and (os == "linux") and not debug: ["PASS", "NOTRUN"]
 
   [test6: iframe notifications]
     expected:
-      if webrender and (os == "linux") and debug: ["PASS", "FAIL"]
+      if webrender and (os == "linux") and debug: ["FAIL", "PASS"]
       if webrender and (os == "linux") and not debug: ["PASS", "FAIL"]
 
--- a/testing/web-platform/meta/resource-timing/status-codes-create-entry.html.ini
+++ b/testing/web-platform/meta/resource-timing/status-codes-create-entry.html.ini
@@ -1,11 +1,10 @@
 [status-codes-create-entry.html]
   [Make sure all status codes are reported]
     expected:
-      if (os == "win") and not webrender and (processor == "x86_64") and not debug: PASS
-      if (os == "linux") and debug and not webrender and sw-e10s: ["FAIL", "PASS"]
-      if (os == "linux") and debug and webrender: PASS
-      if (os == "linux") and not debug and (processor == "x86"): PASS
-      if (os == "android") and not debug: PASS
-      if (os == "android") and debug: ["FAIL", "PASS"]
+      if debug and (os == "linux") and not webrender and not sw-e10s: ["FAIL", "PASS"]
+      if not debug and (os == "win") and (processor == "x86_64") and not webrender: PASS
+      if debug and (os == "linux") and webrender: PASS
+      if not debug and (os == "linux") and (processor == "x86"): PASS
+      if not debug and (os == "android"): PASS
       [PASS, FAIL]
 
--- a/testing/web-platform/meta/service-workers/service-worker/client-navigate.https.html.ini
+++ b/testing/web-platform/meta/service-workers/service-worker/client-navigate.https.html.ini
@@ -1,32 +1,31 @@
 [client-navigate.https.html]
   disabled:
     if (os == "android") and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1499972
     if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview)
   expected:
-    if (os == "mac") and debug: ["OK", "TIMEOUT"]
-    if (os == "mac") and not debug: ["OK", "TIMEOUT"]
+    if (os == "linux") and webrender and not debug: ["OK", "TIMEOUT"]
+    if os == "mac": ["OK", "TIMEOUT"]
   [Frame location should not update on failed mixed-content navigation]
     expected:
+      if (os == "linux") and webrender and not debug: ["PASS", "NOTRUN"]
+      if (os == "mac") and debug: ["PASS", "TIMEOUT", "NOTRUN"]
       if (os == "mac") and not debug: ["PASS", "NOTRUN"]
-      if (os == "mac") and debug: ["PASS", "TIMEOUT", "NOTRUN"]
 
   [Frame location should update on successful navigation]
     expected:
-      if (os == "mac") and debug: ["PASS", "TIMEOUT"]
-      if (os == "mac") and not debug: ["PASS", "TIMEOUT"]
+      if os == "mac": ["PASS", "TIMEOUT"]
 
   [Frame location should not be accessible after cross-origin navigation]
     expected:
-      if (os == "mac") and not debug: ["PASS", "NOTRUN"]
-      if (os == "mac") and debug: ["PASS", "NOTRUN"]
+      if os == "mac": ["PASS", "NOTRUN"]
 
   [Frame location should not be accessible after redirect]
     expected:
-      if (os == "mac") and debug: ["PASS", "NOTRUN"]
-      if (os == "mac") and not debug: ["PASS", "NOTRUN"]
+      if os == "mac": ["PASS", "NOTRUN"]
 
   [Frame location should not update on failed about:blank navigation]
     expected:
-      if (os == "mac") and not debug: ["PASS", "NOTRUN"]
+      if (os == "linux") and webrender and not debug: ["PASS", "TIMEOUT"]
       if (os == "mac") and debug: ["PASS", "TIMEOUT", "NOTRUN"]
+      if (os == "mac") and not debug: ["PASS", "NOTRUN"]
 
--- a/testing/web-platform/meta/service-workers/service-worker/skip-waiting-using-registration.https.html.ini
+++ b/testing/web-platform/meta/service-workers/service-worker/skip-waiting-using-registration.https.html.ini
@@ -2,12 +2,12 @@
   disabled:
     if (os == "win") and (version == "6.1.7601"): https://bugzilla.mozilla.org/show_bug.cgi?id=1425175
     if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1425175
   expected:
     if os == "android": ["OK", "FAIL"]
     if os == "mac": ["OK", "FAIL"]
   [Test skipWaiting while a client is using the registration]
     expected:
-      if (os == "mac") and debug: ["PASS", "FAIL"]
+      if (os == "mac") and debug: ["FAIL", "PASS"]
       if (os == "mac") and not debug: ["PASS", "FAIL"]
       if os == "android": ["PASS", "FAIL"]
 
--- a/testing/web-platform/meta/signed-exchange/reporting/sxg-reporting-prefetch-cert_parse_error-downgraded.tentative.html.ini
+++ b/testing/web-platform/meta/signed-exchange/reporting/sxg-reporting-prefetch-cert_parse_error-downgraded.tentative.html.ini
@@ -1,22 +1,24 @@
 [sxg-reporting-prefetch-cert_parse_error-downgraded.tentative.html]
   expected:
     if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.14") and (processor == "x86_64") and (bits == 64): TIMEOUT
+    if not debug and (os == "linux") and not webrender and (processor == "x86"): TIMEOUT
     if not debug and (os == "linux") and not webrender and (processor == "x86_64"): ["TIMEOUT", "OK"]
+    if not debug and (os == "win") and (processor == "x86_64"): TIMEOUT
     if not debug and (os == "win") and (processor == "aarch64"): ["OK", "CRASH"]
-    if not debug and (os == "android"): OK
-    if debug: OK
-    TIMEOUT
+    if not debug and (os == "win") and (processor == "x86"): TIMEOUT
+    if not debug and (os == "linux") and webrender: TIMEOUT
+    if not debug and (os == "mac"): TIMEOUT
   [SXG reporting test of sxg.failed downgraded from sxg.cert_parse_error for prefetch.]
     expected:
       if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL
       if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL
       if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.14") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.14") and (processor == "x86_64") and (bits == 64): TIMEOUT
+      if not debug and (os == "linux") and not webrender and (processor == "x86"): TIMEOUT
       if not debug and (os == "linux") and not webrender and (processor == "x86_64"): ["TIMEOUT", "FAIL"]
-      if not debug and (os == "linux") and not webrender and (processor == "x86"): TIMEOUT
-      if not debug and (os == "linux") and webrender: TIMEOUT
       if not debug and (os == "win") and (processor == "x86"): TIMEOUT
       if not debug and (os == "win") and (processor == "x86_64"): TIMEOUT
+      if not debug and (os == "linux") and webrender: TIMEOUT
       if not debug and (os == "mac"): TIMEOUT
       FAIL
 
--- a/testing/web-platform/meta/signed-exchange/reporting/sxg-reporting-prefetch-invalid_integrity_header.tentative.html.ini
+++ b/testing/web-platform/meta/signed-exchange/reporting/sxg-reporting-prefetch-invalid_integrity_header.tentative.html.ini
@@ -1,16 +1,18 @@
 [sxg-reporting-prefetch-invalid_integrity_header.tentative.html]
   expected:
     if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.14") and (processor == "x86_64") and (bits == 64): TIMEOUT
+    if not debug and (os == "linux") and not webrender and (processor == "x86"): TIMEOUT
     if not debug and (os == "linux") and not webrender and (processor == "x86_64"): ["TIMEOUT", "OK"]
+    if not debug and (os == "linux") and webrender: TIMEOUT
+    if not debug and (os == "win") and (processor == "x86_64"): TIMEOUT
     if not debug and (os == "win") and (processor == "aarch64"): ["OK", "CRASH"]
-    if not debug and (os == "android"): OK
-    if debug: OK
-    TIMEOUT
+    if not debug and (os == "win") and (processor == "x86"): TIMEOUT
+    if not debug and (os == "mac"): TIMEOUT
   [SXG reporting test of sxg.invalid_integrity_header for prefetch.]
     expected:
       if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL
       if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL
       if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.14") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.14") and (processor == "x86_64") and (bits == 64): TIMEOUT
       if not debug and (os == "linux") and not webrender and (processor == "x86_64"): ["TIMEOUT", "FAIL"]
       if not debug and (os == "linux") and not webrender and (processor == "x86"): TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/storage-access-api/hasStorageAccess.sub.window.js.ini
@@ -0,0 +1,10 @@
+[hasStorageAccess.sub.window.html]
+  expected: TIMEOUT
+  [[top-level-context\] document.hasStorageAccess() should be allowed by default: true]
+    expected:
+      if os == "android": FAIL
+
+  [[top-level-context\] document.hasStorageAccess() should be supported on the document interface]
+    expected:
+      if os == "android": FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/storage-access-api/idl.window.js.ini
@@ -0,0 +1,9 @@
+[idl.window.html]
+  [Document interface: operation requestStorageAccess()]
+    expected:
+      if os == "android": FAIL
+
+  [Document interface: operation hasStorageAccess()]
+    expected:
+      if os == "android": FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/storage-access-api/requestStorageAccess.sub.window.js.ini
@@ -0,0 +1,10 @@
+[requestStorageAccess.sub.window.html]
+  expected: TIMEOUT
+  [[top-level-context\] document.requestStorageAccess() should be supported on the document interface]
+    expected:
+      if os == "android": FAIL
+
+  [[top-level-context\] document.requestStorageAccess() should be rejected by default with no user gesture]
+    expected:
+      if os == "android": FAIL
+
--- a/testing/web-platform/meta/storage/estimate-usage-details-indexeddb.https.tentative.any.js.ini
+++ b/testing/web-platform/meta/storage/estimate-usage-details-indexeddb.https.tentative.any.js.ini
@@ -1,17 +1,21 @@
 [estimate-usage-details-indexeddb.https.tentative.any.html]
+  expected:
+    if (os == "linux") and not debug and not webrender and (processor == "x86_64"): ["OK", "TIMEOUT"]
   [estimate() usage details reflects increase after large value is stored]
     expected: FAIL
 
   [estimate() resolves to dictionary with usageDetails member]
     expected: FAIL
 
   [estimate() usage details reflects increase in indexedDB after large value is stored]
-    expected: FAIL
+    expected:
+      if (os == "linux") and not debug and not webrender and (processor == "x86_64"): ["FAIL", "TIMEOUT"]
+      FAIL
 
 
 [estimate-usage-details-indexeddb.https.tentative.any.worker.html]
   [estimate() usage details reflects increase after large value is stored]
     expected: FAIL
 
   [estimate() resolves to dictionary with usageDetails member]
     expected: FAIL
--- a/testing/web-platform/meta/svg/animations/correct-events-for-short-animations-with-syncbases.html.ini
+++ b/testing/web-platform/meta/svg/animations/correct-events-for-short-animations-with-syncbases.html.ini
@@ -1,6 +1,7 @@
 [correct-events-for-short-animations-with-syncbases.html]
   [Correct events for short animations with syncbases]
     expected:
-      if (processor == "x86") and (os == "linux"): PASS
+      if (os == "linux") and (processor == "x86_64") and webrender and debug: ["FAIL", "PASS"]
+      if (os == "linux") and (processor == "x86"): PASS
       [PASS, FAIL]
 
--- a/testing/web-platform/meta/svg/animations/scripted/onhover-syncbases.html.ini
+++ b/testing/web-platform/meta/svg/animations/scripted/onhover-syncbases.html.ini
@@ -1,13 +1,13 @@
 [onhover-syncbases.html]
   expected:
-    if webrender and (os == "win") and not debug: ["OK", "ERROR"]
-    if webrender and (os == "linux") and debug: ["OK", "ERROR"]
-    if webrender and (os == "linux") and not debug: ["ERROR", "OK"]
+    if webrender and debug and (os == "linux"): ["OK", "ERROR"]
+    if webrender and not debug and (os == "linux"): ["OK", "ERROR"]
+    if webrender and not debug and (os == "win"): ["OK", "ERROR"]
   [Check if onhover events reset correctly when triggred multiple times]
     disabled: true
     expected:
       if webrender and (os == "linux") and not debug: [FAIL, TIMEOUT]
       if webrender and (os == "linux") and debug: [FAIL, PASS, TIMEOUT]
       if webrender and (os == "win") and debug: [PASS, TIMEOUT]
       if webrender and (os == "win") and not debug: [PASS, FAIL, TIMEOUT]
 
--- a/testing/web-platform/meta/svg/animations/slider-switch.html.ini
+++ b/testing/web-platform/meta/svg/animations/slider-switch.html.ini
@@ -1,9 +1,7 @@
 [slider-switch.html]
   [Check correct event bases for onclick]
     expected:
       if (os == "android") and not debug: ["FAIL", "PASS"]
-      if (os == "linux") and webrender: ["FAIL", "PASS"]
       if (os == "win") and (processor == "aarch64"): ["FAIL", "PASS"]
-      if (os == "mac") and debug: ["FAIL", "PASS"]
       [PASS, FAIL]
 
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/web-animations/interfaces/Animation/idlharness.window.js.ini
@@ -0,0 +1,4 @@
+[idlharness.window.html]
+  [Animation interface: attribute timeline]
+    expected: FAIL
+
--- a/testing/web-platform/meta/web-nfc/NFCWriter_push.https.html.ini
+++ b/testing/web-platform/meta/web-nfc/NFCWriter_push.https.html.ini
@@ -96,8 +96,11 @@
     expected: FAIL
 
   [NFCWriter.push should ignore reading data when ignoreRead is true.]
     expected: FAIL
 
   [NFCWriter.push should read data when ignoreRead is false.]
     expected: FAIL
 
+  [NFCWriter.push should replace all previously configured push operations.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/webdriver/tests/new_session/timeouts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/new_session/timeouts.py.ini
@@ -1,6 +1,6 @@
 [timeouts.py]
   disabled:
     if ccov and (os == "win") and (bits == 64) and (version == "10.0.17134"): https://bugzilla.mozilla.org/show_bug.cgi?id=1495002
   expected:
+    if (os == "linux") and not debug and not webrender: ["OK", "TIMEOUT"]
     if (os == "linux") and not debug and webrender: ["OK", "TIMEOUT"]
-    if (os == "linux") and not debug and not webrender: ["OK", "TIMEOUT"]
--- a/testing/web-platform/tests/2dcontext/wide-gamut-canvas/canvas-colorManaged-convertToBlob-roundtrip.html
+++ b/testing/web-platform/tests/2dcontext/wide-gamut-canvas/canvas-colorManaged-convertToBlob-roundtrip.html
@@ -139,11 +139,13 @@ function runAllTests() {
                 testScenario.alpha = alphaValues[k];
                 testScenarioSet.push(testScenario);
             }
 
     for (var i = 0; i < testScenarioSet.length; i++)
         runConvertToBlobTest(testScenarioSet[i]);
 }
 
-runAllTests();
+test(function() {
+    runAllTests();
+}, "Overall test");
 
 </script>
--- a/testing/web-platform/tests/2dcontext/wide-gamut-canvas/canvas-colorManaged-toBlob-toDataURL.html
+++ b/testing/web-platform/tests/2dcontext/wide-gamut-canvas/canvas-colorManaged-toBlob-toDataURL.html
@@ -135,11 +135,13 @@ function runAllTests() {
 
     for (var i = 0; i < testScenarioSet.length; i++)
         runToBlobTest(testScenarioSet[i]);
 
     for (var i = 0; i < testScenarioSet.length; i++)
         runToDataURLTest(testScenarioSet[i]);
 }
 
-runAllTests();
+test(function() {
+    runAllTests();
+}, "Overall test");
 
 </script>
--- a/testing/web-platform/tests/2dcontext/wide-gamut-canvas/canvas-draw-high-bit-depth-images.html
+++ b/testing/web-platform/tests/2dcontext/wide-gamut-canvas/canvas-draw-high-bit-depth-images.html
@@ -18,17 +18,17 @@ function runTest(testScenario) {
     var tolerance = defaultColorConversionTolerance;
     if (testScenario.canvasColorParams.pixelFormat == 'float16')
         tolerance = wideGamutColorConversionTolerance;
 
     var _8bitImage = new Image();
     var _16bitImage = new Image();
     var t_image = async_test(testScenarioToString(testScenario));
     _8bitImage.onload = t_image.step_func(function() {
-        _16bitImage.onload = function() {
+        _16bitImage.onload = t_image.step_func(function() {
             var refCanvas = document.createElement("canvas");
             refCanvas.width = refCanvas.height = 2;
             var refCtx = refCanvas.getContext(
                 '2d', testScenario.canvasColorParams);
             refCtx.drawImage(_8bitImage, 0, 0);
             var refPixels = refCtx.getImageData(0, 0, 2, 2).dataUnion;
 
             var testCanvas = document.createElement("canvas");
@@ -36,17 +36,17 @@ function runTest(testScenario) {
             var testCtx = testCanvas.getContext(
                 '2d', testScenario.canvasColorParams);
             testCtx.drawImage(_16bitImage, 0, 0);
             var testPixels = testCtx.getImageData(0, 0, 2, 2).dataUnion;
 
             assert_array_approx_equals(refPixels, testPixels, tolerance);
 
             t_image.done();
-            };
+        });
         _16bitImage.src = _16bitImageSrc;
     });
     _8bitImage.src = _8bitImageSrc;
 }
 
 function runAllTests() {
     var pngColorSpaces = [
         "_sRGB",
@@ -99,11 +99,13 @@ function runAllTests() {
 function testScenarioToString(testScenario) {
     var str = "Canvas color params: " +
         testScenario.canvasColorParams.colorSpace + ", " +
         testScenario.canvasColorParams.pixelFormat + ". Testing " +
         testScenario._8bitImagePath + " vs " + testScenario._16bitImagePath;
     return str;
 }
 
-runAllTests();
+test(function() {
+    runAllTests();
+}, "Overall test");
 
 </script>
--- a/testing/web-platform/tests/accelerometer/Accelerometer-iframe-access.https.html
+++ b/testing/web-platform/tests/accelerometer/Accelerometer-iframe-access.https.html
@@ -1,17 +1,17 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>Accelerometer iframe test</title>
 <meta name="timeout" content="long">
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://www.w3.org/TR/accelerometer/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
 <script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
 <div id="log"></div>
 <script>
 run_generic_sensor_iframe_tests('Accelerometer');
 run_generic_sensor_iframe_tests('LinearAccelerationSensor');
 run_generic_sensor_iframe_tests('GravitySensor');
 </script>
--- a/testing/web-platform/tests/accelerometer/Accelerometer.https.html
+++ b/testing/web-platform/tests/accelerometer/Accelerometer.https.html
@@ -1,17 +1,45 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>Accelerometer Test</title>
 <meta name="timeout" content="long">
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://www.w3.org/TR/accelerometer/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
 <script>
 
-runGenericSensorTests('Accelerometer');
-runGenericSensorTests('GravitySensor');
-runGenericSensorTests('LinearAccelerationSensor');
+'use strict';
+
+const kReadings = {
+    readings: [
+        [1.12345, 2.12345, 3.12345]
+    ],
+    expectedReadings: [
+        [1.12345, 2.12345, 3.12345]
+    ],
+    expectedRemappedReadings: [
+        [-2.12345, 1.12345, 3.12345]
+    ]
+};
+
+runGenericSensorTests(
+    'Accelerometer',
+    kReadings,
+    verifyXyzSensorReading,
+    ['accelerometer']);
+
+runGenericSensorTests(
+    'GravitySensor',
+    kReadings,
+    verifyXyzSensorReading,
+    ['accelerometer']);
+
+runGenericSensorTests(
+    'LinearAccelerationSensor',
+    kReadings,
+    verifyXyzSensorReading,
+    ['accelerometer']);
 
 </script>
deleted file mode 100644
--- a/testing/web-platform/tests/accelerometer/Accelerometer_onerror-manual.https.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Accelerometer Test: onerror</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<link rel="help" href="https://www.w3.org/TR/accelerometer/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
-<h2>Precondition</h2>
-<ol>
-  <li>
-    Disable the Accelerometer Sensor or run test on a device without Accelerometer Sensor.
-  </li>
-</ol>
-<script>
-
-runGenericSensorOnerror('Accelerometer');
-runGenericSensorOnerror('GravitySensor');
-runGenericSensorOnerror('LinearAccelerationSensor');
-
-</script>
--- a/testing/web-platform/tests/ambient-light/AmbientLightSensor-iframe-access.https.html
+++ b/testing/web-platform/tests/ambient-light/AmbientLightSensor-iframe-access.https.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>AmbientLightSensor iframe test</title>
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://w3c.github.io/ambient-light/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
 <script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
 <div id="log"></div>
 <script>
 run_generic_sensor_iframe_tests('AmbientLightSensor');
 </script>
--- a/testing/web-platform/tests/ambient-light/AmbientLightSensor.https.html
+++ b/testing/web-platform/tests/ambient-light/AmbientLightSensor.https.html
@@ -1,14 +1,29 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>AmbientLightSensor Test</title>
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://www.w3.org/TR/ambient-light/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
 <script>
 
-runGenericSensorTests('AmbientLightSensor');
+'use strict';
+
+const kReadings = {
+    readings: [
+        [3.1415]
+    ],
+    expectedReadings: [
+        [3.1415]
+    ]
+};
+
+runGenericSensorTests(
+    'AmbientLightSensor',
+    kReadings,
+    verifyAlsSensorReading,
+    ['ambient-light-sensor']);
 
 </script>
deleted file mode 100644
--- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_onerror-manual.https.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>AmbientLightSensor Test: onerror</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<link rel="help" href="https://www.w3.org/TR/ambient-light/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
-<h2>Precondition</h2>
-<ol>
-  <li>
-    Disable the Ambient Light Sensor or run test on a device without Amibent Light Sensor.
-  </li>
-</ol>
-<script>
-
-runGenericSensorOnerror('AmbientLightSensor');
-
-</script>
--- a/testing/web-platform/tests/common/security-features/resources/common.sub.js
+++ b/testing/web-platform/tests/common/security-features/resources/common.sub.js
@@ -1113,16 +1113,19 @@ function invokeRequest(subresource, sour
   // Defines invokers for each valid SourceContext.sourceContextType.
   const sourceContextMap = {
     "srcdoc": { // <iframe srcdoc></iframe>
       invoker: invokeFromIframe,
     },
     "iframe": { // <iframe src="same-origin-URL"></iframe>
       invoker: invokeFromIframe,
     },
+    "iframe-blank": { // <iframe></iframe>
+      invoker: invokeFromIframe,
+    },
     "worker-classic": {
       // Classic dedicated worker loaded from same-origin.
       invoker: invokeFromWorker.bind(undefined, false, {}),
     },
     "worker-classic-data": {
       // Classic dedicated worker loaded from data: URL.
       invoker: invokeFromWorker.bind(undefined, true, {}),
     },
@@ -1199,45 +1202,63 @@ function invokeFromWorker(isDataUrl, wor
 
 function invokeFromIframe(subresource, sourceContextList) {
   const currentSourceContext = sourceContextList[0];
   const frameUrl =
     "/common/security-features/scope/document.py?policyDeliveries=" +
     encodeURIComponent(JSON.stringify(
         currentSourceContext.policyDeliveries || []));
 
+  let iframe;
   let promise;
   if (currentSourceContext.sourceContextType === 'srcdoc') {
     promise = fetch(frameUrl)
       .then(r => r.text())
       .then(srcdoc => {
-          return createElement("iframe", {srcdoc: srcdoc}, document.body, true);
+          iframe = createElement(
+              "iframe", {srcdoc: srcdoc}, document.body, true);
+          return iframe.eventPromise;
         });
   } else if (currentSourceContext.sourceContextType === 'iframe') {
-    promise = Promise.resolve(
-        createElement("iframe", {src: frameUrl}, document.body, true));
+    iframe = createElement("iframe", {src: frameUrl}, document.body, true);
+    promise = iframe.eventPromise;
+  } else if (currentSourceContext.sourceContextType === 'iframe-blank') {
+    let frameContent;
+    promise = fetch(frameUrl)
+      .then(r => r.text())
+      .then(t => {
+          frameContnent = t;
+          iframe = createElement("iframe", {}, document.body, true);
+          return iframe.eventPromise;
+        })
+      .then(() => {
+          // Reinitialize `iframe.eventPromise` with a new promise
+          // that catches the load event for the document.write() below.
+          bindEvents(iframe);
+
+          iframe.contentDocument.write(frameContent);
+          iframe.contentDocument.close();
+          return iframe.eventPromise;
+        });
   }
 
   return promise
-    .then(iframe => {
-        return iframe.eventPromise
-          .then(() => {
-              const promise = bindEvents2(
-                  window, "message", iframe, "error", window, "error");
-              iframe.contentWindow.postMessage(
-                  {subresource: subresource,
-                   sourceContextList: sourceContextList.slice(1)},
-                  "*");
-              return promise;
-            })
-          .then(event => {
-              if (event.data.error)
-                return Promise.reject(event.data.error);
-              return event.data;
-            });
+    .then(() => {
+        const promise = bindEvents2(
+            window, "message", iframe, "error", window, "error");
+        iframe.contentWindow.postMessage(
+            {subresource: subresource,
+             sourceContextList: sourceContextList.slice(1)},
+            "*");
+        return promise;
+      })
+    .then(event => {
+        if (event.data.error)
+          return Promise.reject(event.data.error);
+        return event.data;
       });
 }
 
 // SanityChecker does nothing in release mode. See sanity-checker.js for debug
 // mode.
 function SanityChecker() {}
 SanityChecker.prototype.checkScenario = function() {};
 SanityChecker.prototype.setFailTimeout = function(test, timeout) {};
--- a/testing/web-platform/tests/common/security-features/tools/spec_validator.py
+++ b/testing/web-platform/tests/common/security-features/tools/spec_validator.py
@@ -96,19 +96,21 @@ def validate(spec_json, details):
     assert_non_empty_list(spec_json, "excluded_tests")
 
     specification = spec_json['specification']
     test_expansion_schema = spec_json['test_expansion_schema']
     excluded_tests = spec_json['excluded_tests']
 
     valid_test_expansion_fields = ['name'] + test_expansion_schema.keys()
 
+    # Should be consistent with `sourceContextMap` in
+    # `/common/security-features/resources/common.sub.js`.
     valid_source_context_names = [
-        "top", "iframe", "srcdoc", "worker-classic", "worker-module",
-        "worker-classic-data", "worker-module-data"
+        "top", "iframe", "iframe-blank", "srcdoc", "worker-classic",
+        "worker-module", "worker-classic-data", "worker-module-data"
     ]
 
     valid_subresource_names = [
         "a-tag", "area-tag", "audio-tag", "form-tag", "iframe-tag", "img-tag",
         "link-css-tag", "link-prefetch-tag", "object-tag", "picture-tag",
         "script-tag", "video-tag"
     ] + ["beacon", "fetch", "xhr", "websocket"] + [
         "worker-classic", "worker-module", "worker-import",
--- a/testing/web-platform/tests/cookies/resources/cookie-helper.sub.js
+++ b/testing/web-platform/tests/cookies/resources/cookie-helper.sub.js
@@ -108,17 +108,17 @@ window.SameSiteStatus = {
   CROSS_SITE: "cross-site",
   LAX: "lax",
   STRICT: "strict"
 };
 
 const wait_for_message = (type, origin) => {
   return new Promise((resolve, reject) => {
     window.addEventListener('message', e => {
-      if (e.origin != origin) {
+      if (origin && e.origin != origin) {
         reject("Message from unexpected origin in wait_for_message:" + e.origin);
         return;
       }
 
       if (e.data.type && e.data.type === type)
         resolve(e);
     }, { once: true });
   });
--- a/testing/web-platform/tests/cookies/resources/postToParent.py
+++ b/testing/web-platform/tests/cookies/resources/postToParent.py
@@ -5,19 +5,24 @@ def main(request, response):
     headers = helpers.setNoCacheAndCORSHeaders(request, response)
     cookies = helpers.readCookies(request)
     headers.append(("Content-Type", "text/html; charset=utf-8"))
 
     tmpl = """
 <!DOCTYPE html>
 <script>
   var data = %s;
+  data.type = "COOKIES";
 
-  if (window.parent != window)
+  if (window.parent != window) {
     window.parent.postMessage(data, "*");
+    if (window.top != window.parent)
+      window.top.postMessage(data, "*");
+  }
+
 
   if (window.opener)
     window.opener.postMessage(data, "*");
 
   window.addEventListener("message", e => {
     console.log(e);
     if (e.data == "reload")
       window.location.reload();
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/cookies/samesite/about-blank-nested.https.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<head>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/cookies/resources/cookie-helper.sub.js"></script>
+</head>
+<body onload="doTests()">
+  <iframe src="about:blank" id="if">
+  </iframe>
+  <script>
+  function doTests() {
+    promise_test(async function(t) {
+      var child = document.getElementById("if");
+      var grandKid = child.contentDocument.createElement("iframe");
+      child.contentDocument.body.appendChild(grandKid);
+      var value = "" + Math.random();
+      await resetSameSiteCookies(SECURE_ORIGIN, value);
+
+      // Using postToParent.py here to see cookies used when navigating the page.
+      grandKid.src = SECURE_ORIGIN + "/cookies/resources/postToParent.py"
+      var e = await wait_for_message("COOKIES", SECURE_ORIGIN);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_unspecified", value, true);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_lax", value, true);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_strict", value, true);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_none", value, true);
+    }, "SameSite cookies with intervening about:blank iframes and navigation");
+  }
+  </script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/cookies/samesite/resources/iframe-navigate-report.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<iframe src="/cookies/resources/postToParent.py">
+</iframe>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/cookies/samesite/resources/iframe-subresource-report.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<head>
+<script src="/cookies/resources/cookie-helper.sub.js"></script>
+<script>
+function reportSubresourceCookies() {
+  credFetch(SECURE_ORIGIN + "/cookies/resources/list.py")
+    .then(r => r.json())
+    .then(cookies => { cookies.type = "COOKIES";
+                       window.parent.postMessage(cookies, "*");});
+}
+</script>
+</head>
+<body onload="reportSubresourceCookies()">
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/cookies/samesite/sandbox-iframe-nested.https.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<head>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/cookies/resources/cookie-helper.sub.js"></script>
+</head>
+<body onload="doTests()">
+  <iframe id="if" sandbox="allow-scripts">
+  </iframe>
+  <script>
+  function doTests() {
+    promise_test(async function(t) {
+      var value = "" + Math.random();
+      await resetSameSiteCookies(SECURE_ORIGIN, value);
+      var child = document.getElementById("if");
+      child.src = SECURE_ORIGIN + "/cookies/samesite/resources/iframe-navigate-report.html";
+
+      // the iframe nested inside if should post COOKIES to here.
+      var e = await wait_for_message("COOKIES");
+      // Not testing unspecified here as to not depend on the presence or
+      // absence of upcoming change of behavior.
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_lax", value, false);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_strict", value, false);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_none", value, true);
+    }, "SameSite cookies with intervening sandboxed iframe and navigation");
+  }
+  </script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/cookies/samesite/sandbox-iframe-subresource.https.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<head>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/cookies/resources/cookie-helper.sub.js"></script>
+</head>
+<body onload="doTests()">
+  <iframe id="if" sandbox="allow-scripts">
+  </iframe>
+  <script>
+  function doTests() {
+    promise_test(async function(t) {
+      var value = "" + Math.random();
+      await resetSameSiteCookies(SECURE_ORIGIN, value);
+      var child = document.getElementById("if");
+      child.src = SECURE_ORIGIN + "/cookies/samesite/resources/iframe-subresource-report.html";
+
+      // the iframe nested inside if should post COOKIES to here.
+      var e = await wait_for_message("COOKIES");
+      // Not testing unspecified here as to not depend on the presence or
+      // absence of upcoming change of behavior.
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_lax", value, false);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_strict", value, false);
+      assert_cookie(SECURE_ORIGIN, e.data, "samesite_none", value, true);
+    }, "SameSite cookies with intervening sandboxed iframe and subresources");
+  }
+  </script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/CSS2/positioning/relpos-percentage-left-in-scrollable-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#propdef-left">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#relative-positioning">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#anonymous-block-level">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1002485">
+<p>There should be no red, and no scrollbar.</p>
+<div id="container" style="overflow:auto; width:500px; background:red;">
+  <div style="padding-right:90%; background:yellow;">
+    <div style="position:relative; left:900%; background:cyan;">
+      <div></div>
+      &nbsp;
+    </div>
+  </div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  container.scrollLeft = 123456;
+  test(()=> {
+      assert_equals(container.scrollLeft, 0);
+  }, "Left percentage resolved correctly for overflow contribution");
+</script>
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-auto-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-auto-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-auto</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#italic-mappings">
 <link rel="match" href="text-transform-math-auto-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-auto' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-italic.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-bold</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-mappings">
 <link rel="match" href="text-transform-math-bold-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-bold' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-fraktur-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-fraktur-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-bold-fraktur</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-fraktur-mappings">
 <link rel="match" href="text-transform-math-bold-fraktur-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-bold-fraktur' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-fraktur.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-italic-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-italic-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-bold-italic</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-italic-mappings">
 <link rel="match" href="text-transform-math-bold-italic-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-bold-italic' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-italic.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-sans-serif-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-sans-serif-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-bold-sans-serif</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-sans-serif-mappings">
 <link rel="match" href="text-transform-math-bold-sans-serif-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-bold-sans-serif' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-sans-serif.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-script-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-bold-script-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-bold-script</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-script-mappings">
 <link rel="match" href="text-transform-math-bold-script-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-bold-script' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-script.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-double-struck-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-double-struck-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-double-struck</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#double-struck-mappings">
 <link rel="match" href="text-transform-math-double-struck-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-double-struck' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-double-struck.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-fraktur-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-fraktur-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-fraktur</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#fraktur-mappings">
 <link rel="match" href="text-transform-math-fraktur-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-fraktur' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-fraktur.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-initial-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-initial-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-initial</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#initial-mappings">
 <link rel="match" href="text-transform-math-initial-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-initial' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-initial.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-italic-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-italic-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-italic</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#italic-mappings">
 <link rel="match" href="text-transform-math-italic-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-italic' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-italic.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-looped-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-looped-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-looped</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#looped-mappings">
 <link rel="match" href="text-transform-math-looped-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-looped' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-looped.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-monospace-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-monospace-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-monospace</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#monospace-mappings">
 <link rel="match" href="text-transform-math-monospace-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-monospace' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-monospace.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-sans-serif-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-sans-serif-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-sans-serif</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#sans-serif-mappings">
 <link rel="match" href="text-transform-math-sans-serif-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-sans-serif' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-sans-serif.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-sans-serif-bold-italic-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-sans-serif-bold-italic-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-sans-serif-bold-italic</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#sans-serif-bold-italic-mappings">
 <link rel="match" href="text-transform-math-sans-serif-bold-italic-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-sans-serif-bold-italic' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-sans-serif-bold-italic.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-sans-serif-italic-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-sans-serif-italic-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-sans-serif-italic</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#sans-serif-italic-mappings">
 <link rel="match" href="text-transform-math-sans-serif-italic-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-sans-serif-italic' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-sans-serif-italic.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-script-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-script-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-script</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#script-mappings">
 <link rel="match" href="text-transform-math-script-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-script' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-script.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-stretched-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-stretched-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-stretched</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretched-mappings">
 <link rel="match" href="text-transform-math-stretched-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-stretched' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-stretched.woff");
   }
   body > span {
--- a/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-tailed-001.tentative.html
+++ b/testing/web-platform/tests/css/css-text/text-transform/math/text-transform-math-tailed-001.tentative.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>text-transform math-tailed</title>
 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#tailed-mappings">
 <link rel="match" href="text-transform-math-tailed-001.tentative-ref.html"/>
 <meta name="assert" content="Verify that a character with 'text-transform: math-tailed' renders the same as the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-tailed.woff");
   }
   body > span {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transforms/animation/perspective-interpolation.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title> perspective interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-perspective">
+<meta name="assert" content="perspective supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  perspective: 30px;
+}
+.target {
+  perspective: 10px;
+}
+.transformed {
+  width: 50px;
+  height: 50px;
+  background: black;
+  transform: rotateY(45deg);
+}
+.expected .transformed {
+  background: green;
+}
+.expected {
+  position: relative;
+  left: -50px;
+  opacity: 0.75;
+}
+</style>
+<body>
+<template id="target-template">
+<div><div class="transformed"></div></div>
+</template>
+<script>
+test_interpolation({
+  property: 'perspective',
+  from: neutralKeyframe,
+  to: '20px',
+}, [
+  {at: -20, expect: 'none'},
+  {at: -1, expect: 'none'},
+  {at: -0.3, expect: '7px'},
+  {at: 0, expect: '10px'},
+  {at: 0.3, expect: '13px'},
+  {at: 0.6, expect: '16px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '25px'},
+]);
+
+test_no_interpolation({
+  property: 'perspective',
+  from: 'initial',
+  to: '20px',
+});
+
+test_interpolation({
+  property: 'perspective',
+  from: 'inherit',
+  to: '20px',
+}, [
+  {at: -20, expect: '230px'},
+  {at: -1, expect: '40px'},
+  {at: -0.3, expect: '33px'},
+  {at: 0, expect: '30px'},
+  {at: 0.3, expect: '27px'},
+  {at: 0.6, expect: '24px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '15px'},
+]);
+
+test_no_interpolation({
+  property: 'perspective',
+  from: 'unset',
+  to: '20px',
+});
+
+test_interpolation({
+  property: 'perspective',
+  from: '50px',
+  to: '100px',
+}, [
+  {at: -20, expect: 'none'}, // perspective does not accept 0 or negative values
+  {at: -1, expect: 'none'}, // perspective does not accept 0 or negative values
+  {at: -0.3, expect: '35px'},
+  {at: 0, expect: '50px'},
+  {at: 0.3, expect: '65px'},
+  {at: 0.6, expect: '80px'},
+  {at: 1, expect: '100px'},
+  {at: 1.5, expect: '125px'},
+]);
+
+test_no_interpolation({
+  property: 'perspective',
+  from: '50px',
+  to: 'none',
+});
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transforms/animation/perspective-origin-interpolation.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>perspective-origin interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property">
+<meta name="assert" content="perspective-origin supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  perspective-origin: 30px 10px;
+}
+.target {
+  display: inline-block;
+  perspective: 50;
+  margin-top: 50px;
+  margin-bottom: 25px;
+  perspective-origin: 10px 30px;
+}
+.transformed {
+  width: 50px;
+  height: 50px;
+  background: black;
+  transform: rotateY(45deg);
+}
+.expected .transformed {
+  background: green;
+}
+.expected {
+  position: relative;
+  left: -50px;
+  opacity: 0.75;
+}
+</style>
+<body>
+<template id="target-template">
+<div><div class="transformed"></div></div>
+</template>
+<script>
+test_interpolation({
+  property: 'perspective-origin',
+  from: neutralKeyframe,
+  to: '20px 20px',
+}, [
+  {at: -0.3, expect: '7px 33px'},
+  {at: 0, expect: '10px 30px'},
+  {at: 0.3, expect: '13px 27px'},
+  {at: 0.6, expect: '16px 24px'},
+  {at: 1, expect: '20px 20px'},
+  {at: 1.5, expect: '25px 15px'},
+]);
+
+test_interpolation({
+  property: 'perspective-origin',
+  from: 'initial',
+  to: '20px 20px',
+}, [
+  {at: -0.3, expect: '26.5px 26.5px'},
+  {at: 0, expect: '25px 25px'},
+  {at: 0.3, expect: '23.5px 23.5px'},
+  {at: 0.6, expect: '22px 22px'},
+  {at: 1, expect: '20px 20px'},
+  {at: 1.5, expect: '17.5px 17.5px'},
+]);
+
+test_interpolation({
+  property: 'perspective-origin',
+  from: 'inherit',
+  to: '20px 20px',
+}, [
+  {at: -0.3, expect: '33px 7px'},
+  {at: 0, expect: '30px 10px'},
+  {at: 0.3, expect: '27px 13px'},
+  {at: 0.6, expect: '24px 16px'},
+  {at: 1, expect: '20px 20px'},
+  {at: 1.5, expect: '15px 25px'},
+]);
+
+test_interpolation({
+  property: 'perspective-origin',
+  from: 'unset',
+  to: '20px 20px',
+}, [
+  {at: -0.3, expect: '26.5px 26.5px'},
+  {at: 0, expect: '25px 25px'},
+  {at: 0.3, expect: '23.5px 23.5px'},
+  {at: 0.6, expect: '22px 22px'},
+  {at: 1, expect: '20px 20px'},
+  {at: 1.5, expect: '17.5px 17.5px'},
+]);
+
+test_interpolation({
+  property: 'perspective-origin',
+  from: '0% 50%',
+  to: '100% 150%'
+}, [
+  {at: -0.3, expect: '-30% 20%'},
+  {at: 0, expect: '0% 50%'},
+  {at: 0.3, expect: '30% 80%'},
+  {at: 0.6, expect: '60% 110%'},
+  {at: 1, expect: '100% 150%'},
+  {at: 1.5, expect: '150% 200%'}
+]);
+</script>
+</body>
--- a/testing/web-platform/tests/docs/running-tests/android_webview.md
+++ b/testing/web-platform/tests/docs/running-tests/android_webview.md
@@ -1,35 +1,50 @@
 # Android WebView
 
 To run WPT on WebView on an Android device, some additional set-up is required.
 
 Currently, Android WebView support is experimental.
 
-* Please check [Chrome for Android](chrome_android) for the common
-  instructions for Android support first.
+## Prerequisites
+
+#### Please check [Chrome for Android](chrome_android.md) for the common instructions for Android support first.
+
+#### Ensure you have a userdebug or eng Android build installed on the device.
 
-* Install an up-to-date version of system webview shell:
-  * Go to
-  [chromium-browser-snapshots](https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Android/)
-  * Find the subdirectory with the highest number and click it.
-  * Download `chrome-android.zip` file and unzip it.
-  * Install `SystemWebViewShell.apk`.
-  * On emulator, system webview shell may already be installed by default. Then
-    you may need to remove the existing apk:
-     * Choose a userdebug build.
-     * Run an emulator with
-       [writable system partition from command line](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/android_emulator.md/)
+#### Install an up-to-date version of system webview shell.
+1. Go to [chromium-browser-snapshots](https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Android/)
+2. Find the subdirectory with the highest number and click it, this number can be found
+   in the "Commit Position" column of row "LAST_CHANGE" (at bottom of page).
+3. Download `chrome-android.zip` file and unzip it.
+4. Install `SystemWebViewShell.apk`.
+5. On emulator, system webview shell may already be installed by default. Then you may need to remove the existing apk:
+   * Choose a userdebug build.
+   * Run an emulator with
+     [writable system partition from command line](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/android_emulator.md/)
 
-* If you have an issue with ChromeDriver version, try removing
-  `_venv/bin/chromedriver` such that wpt runner can install a matching version
+#### If you have an issue with ChromeDriver version mismatch, try one of the following.
+  * Try removing `_venv/bin/chromedriver` such that wpt runner can install a matching version
   automatically. Failing that, please check your environment path and make
   sure that no other ChromeDriver is used.
+  * Download the [ChromeDriver binary](https://chromedriver.chromium.org/) matching your WebView's major version and specify it on the command line
+    ```
+    ./wpt run --webdriver-binary <binary path> ...
+    ```
 
-Example command line:
+#### Configure host remap rules in the [webview commandline file](https://cs.chromium.org/chromium/src/android_webview/docs/commandline-flags.md?l=57).
+```
+adb shell "echo '_ --host-resolver-rules=\"MAP nonexistent.*.test ~NOTFOUND, MAP *.test 127.0.0.1\"' > /data/local/tmp/webview-command-line"
+```
+
+#### Ensure that `adb` can be found on your system's PATH.
+
+## Running Tests
+
+#### Example command line:
 
 ```bash
 ./wpt run --test-type=testharness android_webview <TESTS>
 ```
 
 * Note that there is no support for channel or automatic installation. The test
   will be run against the current WebView version installed on the device.
 
--- a/testing/web-platform/tests/docs/writing-tests/test-templates.md
+++ b/testing/web-platform/tests/docs/writing-tests/test-templates.md
@@ -4,17 +4,17 @@ This page contains templates for creatin
 is compatible with several popular editors including TextMate, Sublime
 Text, and emacs' YASnippet mode.
 
 Templates for filenames are also given. In this case `{}` is used to
 delimit text to be replaced and `#` represents a digit.
 
 ## Reftests
 
-### Test
+### HTML test
 
 <!--
   Syntax highlighting cannot be enabled for the following template because it
   contains invalid CSS.
 -->
 
 ```
 <!DOCTYPE html>
@@ -26,17 +26,17 @@ delimit text to be replaced and `#` repr
 </style>
 <body>
     ${4:Test content}
 </body>
 ```
 
 Filename: `{test-topic}-###.html`
 
-### Reference:
+### HTML reference
 
 <!--
   Syntax highlighting cannot be enabled for the following template because it
   contains invalid CSS.
 -->
 
 ```
 <!DOCTYPE html>
@@ -47,38 +47,105 @@ Filename: `{test-topic}-###.html`
 </style>
 <body>
     ${3:Reference content}
 </body>
 ```
 
 Filename: `{description}.html` or `{test-topic}-###-ref.html`
 
+### SVG test
+
+``` svg
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>${1:Test title}</title>
+  <metadata>
+    <h:link rel="help" href="${2:Specification link}"/>
+    <h:link rel="match" href="${3:URL of match}"/>
+  </metadata>
+  ${4:Test body}
+</svg>
+```
+
+Filename: `{test-topic}-###.svg`
+
+### SVG reference
+
+``` svg
+<svg xmlns="http://www.w3.org/2000/svg">
+  <title>${1:Reference title}</title>
+  ${2:Reference content}
+</svg>
+```
+
+Filename: `{description}.svg` or `{test-topic}-###-ref.svg`
+
 ## testharness.js tests
 
+### HTML
+
 ``` html
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>${1:Test title}</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
 ${2:Test body}
 </script>
 ```
 
 Filename: `{test-topic}-###.html`
 
+### SVG
+
+``` svg
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>${1:Test title}</title>
+  <metadata>
+    <h:link rel="help" href="${2:Specification link}"/>
+  </metadata>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <script><![CDATA[
+  ${4:Test body}
+  ]]></script>
+</svg>
+```
+
+Filename: `{test-topic}-###.svg`
+
 ### Manual Test
 
+#### HTML
+
 ``` html
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>${1:Test title}</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
 setup({explicit_timeout: true});
 ${2:Test body}
 </script>
 ```
 
 Filename: `{test-topic}-###-manual.html`
+
+#### SVG
+
+``` svg
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>${1:Test title}</title>
+  <metadata>
+    <h:link rel="help" href="${2:Specification link}"/>
+  </metadata>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <script><![CDATA[
+  setup({explicit_timeout: true});
+  ${4:Test body}
+  ]]></script>
+</svg>
+```
+
+Filename: `{test-topic}-###-manual.svg`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bb747e06ba609d64d9ef6a583d43df25c00a6941
GIT binary patch
literal 16684
zc%1FKbyQnT->?g%g%&MEi<VMK@!}LMt|di-yF+k?kWz}Y6f5qfSaJ8@?%Lok0fGjH
zKtAs0mFJW9oPW;y-0Q4$PO@im{jT}V?5sVRot?FIyZ~}?08LE*28JX%1|9|m1}2~y
z0~6!Fd`Qd5y}-c0{)B<SxPgITFM+9t-jS2j{D6VMYH{C8bzf+{Mh--OkknMTclUYZ
z9vB#Xu-~wzp8yRmp8LT~?sMesi^*wz%(^+q)ENWg!3qWj)>jM+9PI2N>KhwN)BCY7
zAK&M2-WP$F1ZVU%_wwEe-N$tI<rT>pNxu!q-5Uer{pEekje+s>ry3Lk17zxbKOUye
zy~F;iJbd#J!_gFEdGCJzTmJ`w<BW=H&Q5Ob_stIXIVAVx1v&(S$2-m3#KOb`!>or9
z?bLlT?{B$c6@W=<THk>B!NoJ&`U!#=y=G$a;26VZ4sQVi<KOcG+S}TqJ6kancrX;@
zuu0o~VPeQ7JlOc_Xnn+Z_~zg8Oat150t4d%1Cv8%g8~ChAAPZMH7U2^!<xV^9>O;n
zYim17`nuXqjcqa3_VWlWaf0`P4TrVkaiRu>lpKaACf?(}#tDv+aO!ybv^(<(Xj#D8
zqgto=Ik2z)(_?BWv)?8=ZDSl#YR||_H<AJi^x*+tBGa#Tt}(C8*b@j}RUUYGjUJ9*
z92{c>4_<unFbRH4A1G4a30&diZw>Sd)1;}7!a1YzZo3wVFQnl1JFnBzrtH8za6YiU
z&sYxhqb%%g1BazNqAR}(VZx6Tn#`5^ic9#J*presZ%pAW6DYb$gS#}DW9&#!^G}OW
zEK%D8&1fwr8*}!ej(WO^Wo(mORf6nfl3{w&+(+05n^0M^EhTkAWbkl$MHj`nQd+t7
zG7rbVq&Rai3Ll=G`|IeYd*S0-_|>6r0dtb+=kIW2%6ILp744pc;GBwt27~<A*x6U9
z&S!hD4E<&Mj``rF62Cq3CX(7<(52D1@YfocYv&Qsnt;K$cUpJ+s1vCrWp8G(?!1!h
z@AoA&i|OgBi>6*z<1ich@o(p$dA>;C*N4Ghf>NG7qhbvC;(V&`3-aF2Ug=5Vvj?tZ
z6YoLqvlbV34$ddM-(nNynot@^RPl1pc)vYcd6jt^;N`gm&hW|bSt5(cm+AVPUM|_?
zK!U~mRX&a14qkHU-%&q!K~fpz=i3z{Rxj<U)MFv_+EOWRvvO##&}SIxIFcgkHf~U(
zQq;d&?OS}~S(RQ%D`M_74?h1SW=3D(G#lXCrzo@^=}Enq=GShhzP?-Bm}51SmI541
zHeU*GnredYI4}SQc2LnU3zP64M(<uQqrdqZal&32^IL~OO|I=<)=j<iB5ug+3;k-K
zM3grw<e@qMa;`e4Mig=L7mO6J?S?c;Z)D4eA8`1w>GmhMhF?jRoc$=>p1;NsD+M5&
zPM_S?+$lxv5-*bYKldm0r}L+x!N>l*WMW;;{Tsq(Fbs72L#w3)Dse1vEEO#+)@&(B
zE3J-$4@ksY4@x934-|BV-Wj2pS_co0ylzBLu!)QAf;F#hcWzw;@;N*Z-ieyvUE+H3
zQD<?_vQd$i(RS06t9m)kvoX9I6B3$F(qs6{tEAQKIx6)&GAdNB%{x5u%?yNyCd+9#
zJ1qO!{f8WNA{dBHSPeS8e)2lgE(edu^$l)6AU!VoDbBuTEDL0`;L0|U`!Z_JFWZN(
zvHo(JB}R<I_LX?)AJFtpYDq@_MKA=<<D~`VuuNamo2%Ky%Zss=$3FD?p_nL~ZG|uX
zU+6*@FQdlwiIGqA9!L~|eV>LL;f(Xf@$ZdV+t608LnQkLpD^zTDlK9}RL4;@=>F{K
z`4BhPL~$gMUA)h^>NM%;`@843OY`(YdbftW2O;Mw+cw!x9Bf1p_1jQ1Rx{S=i1&9+
z`7gO6G{NTHOKeV%FN#Y`E|lF>@;(NL#m?z$w)b~i<izR;4w#uT{VX_JSaE5t2IgX<
z{Ti{N{EFpuw*eG7%rSAoZb33!Cy;dRpx$yj&h{l8=Cg?xfGT?d9%<^$SqRiR)*<1w
zk7{k7_H1qG?_nggx({!Hm8%qSCt#bHlLPZOoRjVrMs+n5=R_D*j8dk{0f!gkzI}1K
z`1E!8tm{uHN{OK^_%Q#=q-ojLx38Rdm2Ydrm_@}=^JVXzM|<6A<<Y93JUu@--gP2t
z(u+<2I`0SyG5+mbXoV4k9>$l$zduR8k-@CLcl+sH{+iwBgVE&Vs^*J?CBO4MM}h1I
zswr<if7AJ>_Zag5Lm=t5m%mN2o`m6k#?>h|%MK%zEe|9hl~t3}Z2O!}xVyNqdeeMy
zv3z^DBmtw?dY4&ceKM4GlI$a)yQZvbrt-sbc1*aXqNF9ero`~a*H_Ax`NirAwz1Mm
zB2QRoPvfG7lSwK|6;NtYvtlI-ij~3N;Iq=|b~eR>l8}AhSk+1;Iu_Z1gm163)+V|q
znA9b9sBELBUPQ#aR-DX9o^Y_us+Q5?Ecv0WY@hpKLclh(T6vCbKao&TKDRZ8mnWW}
zQdu>|ZIh=#>VRRo54>@QeD9Mas^l0WvRQz{_o;<`G<wOE2<$J~1a6ifMUbJ$d?XO*
zg#;k!kt|onzZk5Zy-Lpc6c;PBqiEN^xnbvuRluCB$d;_&$iUlA<I3d|UHk&@1KuxO
zne4zU((j1me<u~G_BG{qEVd2yaK2^r=kuTZ)kOOMoC#BRQcza9J8Qb6^<=R76GK(t
z_#bzUMVY#BT6c;?<%>z_(>J%_8Kyjw+-xW1qzS{{k_Lo|%n~ax9o|s)_f&d%lBD);
zmCHJ?==W!sah0F#d7KN}eA+iPu4LQ;dZwjo{5Jb2s?_)+o0N@s^MUM}=6JTazyar6
zSzDl^wj<Dr1uw39fN_9iz-@ravZ~T>wqQ?N97y;kG~PJQd_b3Ae4Ae&0vKD^KTc|I
zmJ-hQCnX@oo-c@xAcZ^SNlJgpPKpTs3Ezcnf-T)2(GnlElW$x6!}=)~{FyfAwuE*8
zW2n4$1x$L)u)H&Sx9aY>u=58cW9KlVtY&Qy9T6!J?fJa)U(H&6iRX0tw{xM@QMQ@m
zEjf!n!G<@r=UDr6`-yW-H4=7Fh~FbQZo3oiOpU(}qzvN^)EDC$5$@9N5sg-cO$V<R
zL5)ow7rS&*Vg-Iib*go`b%u2sb@~?#2cHhg4=5J77j?zP_0Q<Q-^BHebAV?Ckczu!
zV2NA)YsqWuTguyqw-&eVx9QhD*Egqwr%}6^u-4xYS#-)B$L-BE;PmDc=S*T7GMPDs
z2AN=Ix0@bOPZ0Qos7nty$7IbpC$F-0o`qzE#Dutn5OxlS%o9}M<Kc%BL{VnE6}8qe
zpRw`oJStsf?6eLkBUq*m5J1@qf#SaFWp{52gnZZSkusmrvE8#Q<~`>pe7j^r<LJN>
zDX7Y$%DZHmW^Z6&U}s?K-%}5(@2?-O@2nrJpRQl_?(?4VUhsy!O09k!-Vee}u2c!m
zD=(Os8q~DjwWl&^9Oqk@vY>KGu}HCM?BtuS?yH`vo;Z!$c{J%eNj{mHccDU`+VYn6
zEv>+<nXv73Z*kHGtNeE+BX8lUgF|FnbX!zz^lp%o_a|>p-nfM~Op5*y?G&AdjzPPi
z3(x`R925rahYmwKp@YzA=(2yG{}d|m>bq?1HoJCs?+>&7T2ft2ygCDihOUWG*9gn#
z+;*NGo_3yDo<-Mu%ZyF&L7u_vgnSMzJ);V!mCqouWs_u3d{A<bC}EkMnH{2^{Kv*a
z=N9H}pHVYKRb^yRQfp+@JmA~x@!KQEBdw;>x9ZFj!H#%<FhelHn2Sesr*#DNmdji0
zZ~Ly3&+HKwu*?#O9$@}eD$J^)0mPu6P%=hdt2O64yXyc3VL1rSh0Lcotb<}5CLO$H
zw&uuZ6Xvw%GAf%*^quC-{3g#c_RZ%hYMmV99a`ri=SOA>7ES8zuLAh|N}IdrYK(2l
zDvj-0Cj!#JVa?-94o-E;7Olepb>Nm;%$v^h-u=-z<JwlcWjjdkUDmC}4e<PMPhu8b
zo>_@Tj0p`9CNggKxswVF(7MP2<V)6Fd;dgI)0{<)M{4)V^m0TdN4|^nqa_m77RqoJ
zJ=B5E?9Cj^?9A+6F1WP0%p8ZWC#@I93Z1E@P9ju1wuHjdiQ$h_SNHaz9X=&)<!)cx
zimQg-b^8>ZaKgn#ZqkX~(YuMS`}a4rUp1b9;5Z{<BV6gr!Vven1JNB+Z*IK`XFl7?
zfb(Y4fB{)4T`3ii9tfF!KmB(44KTcDlK&5XC;xoSSWQ>WLd`(UTn((Izh=0mvu3bn
zx@Os<&tvK=5%FE$6S1IO*PFgJ;z`k<CFo_m*V45(3XbrLZfY0n5o;Hl6<Y-7`(@mS
zU+`RHALK7`H5$9LZUqe9w%m|hh+jxv5FIQpFfTy-l6tpYyipnMfQ<Ypk`sfCf^&nd
zh5@%`>)+Nn)@k{jZdGv4QTEXXqh_Ow8O)-iJ}_?q-=!lc;;Qc?8E!v%k&!6|@m2L>
zDudY{H#RdkCDe^kpKJU2`5>U+W-O?nZ>V1?biFwiItlgihWk?ZB>Dn<Gm$MThKGx5
z;K`ee3-d#YB`2snwADAtZ}jT-=t|X%e+!>+X;~M=nc;R3(r~wF!Ykb=tZaOG&;DX@
zqiNWy&Z*@PbGfsn7d(1xbl$u>zw6g~k#(rC3~V{{m$<q+N=M!zrZ0yB5+$}rPbn@3
zZ(Se&ND0~%{pXGvb#^y?r;V0DbKE80y}R?fCAtP)W}ZqM8pD_OmJgP9miN&MkT%E+
zIvkyZcKG!06jQ&AT7h8W;Ww<9wnv!6+qCsBok1qfCNd@tKRMnqIoq$4wuuGaU=cl{
z!xJU(W+`Vl@?F_)!wD1%<ic9U4!}pz2|d4L{{8TSr1jgULyxy`20xRv)3v9VWSXE?
z+E&U}ew!$l^9u0`F$#&)zpZ~&FIvx9FI+EB&r;8E>3Gz+Qo7RHF4jK!ITPpNQ7i5N
z(Reh=#({$^D;LG)qI#~>%co0Bc4t1s(X0v|>ZZDzUa2qLwkQZKaKxOb&vJN>Jy9F%
zBqI^l7onP`Viu^a5sYkWXmt6&kxm=2A3;#UAw>37%Iqmr@LA}Tr!wCJ2X|WWV`<ID
zMn!F21?~MQtO_29U$VIsWWoCSh@7pS7}`ag^!29P65A=8G|F+|g4`PuZ~NZulf>^f
zI{{o}pSl?0pAz1`o5!L)1UcmD(;SNzq70^CxL@D@diq_f4bX)a`M$azA@oQC^PkU2
z)+FurYTP`nw<X^MUg4+g$}?rC%Ue@#={-7R9jd`~EBOo}b0{*=e>BfJqupMMTl=TH
zBm~6oP-Lnf(V%T!`sb)9#F!sdxC$g_wY${nETamzSEZeu)Jv#k=2RhZv@?l3y7z?k
zK9o-rI`AD>T+YH?|J^QR_coI1d-gwY47hp%)(Uc&GNIv5^5WPs4ELEfTdMg7;<f5s
z{^=+q52!gR3O43I*{uTqT@eO&92Er_)1r1)fH)HDgU<g(t-_ao+W(``FwuBgz0~QT
zki`C-OSnkNZmK+A1kJ2aLqT(PMQ%}7_;^asR^+uB=!`MtSw3|tbuUv+?wN#qy+XB@
zz;{*lniEU@9Bg%wmJ$ycYb+zY#5%7?YT)wt)ZAy`2lw+A{q4Hz#azl<@9R>U2#xrs
zOZ?FxCqZ~X$wCssb^ZCq7F)2Jlzd&}u5h8#^FIsCuxE+yH6M#=c^4jOvZd(Ddw}8B
z3B>Ryz4?@9ys8d91n|)Lxe1S#E?g#MW*Mwo1u&_`%seWV&^Dn5>k2vM?q-3J4xrBR
za;?G{RxO8kyNA3H&S9T4YXl?g?Mj`bAIUou+C7X^6Ovn{3}zHC;HUbqH<3Ljj6P}m
z<@~(|(aY?(xY6?@9iC4bY)@LMwy^wW>-j&ZzGsCh$R59xyS~Rc$UMmsKV#<R52e-f
zAY=Rh?#u2Kioc+uu`~}sWwWL{+4ZHGZ-w(Sy`5}MLq&7*%{Mhr#F-)V`mmaH#Srrl
z*BjW@^k9kXsPvQ9BPiR7VPHcK_q5O!RVawYEyBFiWr&}!RS30q6yC}8zX0nh@cDt=
zp$xs}>#_0U%=J>P2tz#Ld>2dhaf9KASeIRi-uh=0Ca>Zt6`ADJzs6{q{U<tq|6;yH
z!wXM(7bU<~!_Oxe>2%=G`xQ5ha(Z@QoUg?PSGD7Lj+Uez*?(Qh@^RN3M{s;4$U2cw
z#)4`+I)Hv+`&jg#hV{R$v{w~@tBOGttdvEc|8Fa8dHHHjlo$O&bFH`9kIacrG`mE}
zxVadPu>KMyA;ttKyOq%5Tv%Hf_6e4<R=MV*|K5t!ROo(Z|Eu4(vNfwJ`|{U^#{=uP
z$dEg&J3R3KI3`70{qdn7=Vxk)_K5J69$Dx0mo=*~AHHhxnRz2NmY)3TVQlV<udulQ
z?m@Y$UGPCP($u|UJr#w{@<6^lnkd$PEDKx(8ucfui-*##ky$S0HVc$gf+0N-|3Dp&
zoEz{kqgp#=1hw>f&saS-pCf(=m2^>0p?%X9S^L{@NJWab*|h!hrR4f2i*@A>sNEk4
zY~wnNxx8nJOn>*+7WpkZdu{u-kTC221#W%K_F1#Z5K3YGKatMJi13NDrozK#!Cf!N
zqJ?svbuc_oe^d}M_1=!*2(Ob1zx6FDx>LxNQl4<#^fGug^l?w;y(c369=b{qVoVue
zdRcHJjlJGyLi7APV~~r*+tLm|a3-z<SpX|a^OC{WMTRSKyPLRK=of|j=~|c(&3@N0
zFRT2~+G8V{_HagTmxo-DE8UDo;cZ0!42hvapDFHh)Gk+XfRQuZ*+=0WL^0uvt}Zg1
zk$v674MHy|<TuvB3~2B&|97cFOY^^FMzxnc2)MLOX9T&Rsz;6|h08wCn~}>8t%d2*
zaECKmxpc8dCUsYQd#BCa%ewUsY0mA&Zgnq-tAzf~%zsMgvw--cqA$iwf34LgtxA^+
zDlT7GBHwls=LvO?$|tQo)}S%{#`sSeN*_uuUc7Qy{+UtAMdnT9<8I<Cp_iocU)I7t
z(hz_9pX9%1iMo7Yjy&oj&JgM#k@sGE44|1>{Yi-9A@sZRAMPI{NlUov{4q30m}d3s
zfAna7L5S`0HY`Yz27k@u>3!GBPoMuizzGtf{I?NtVuZr}=du6U9h2)n_iDHHNdgD;
zZe<h`LU`$x^Ez^>D<(xq{jUZS8k}_@%HDP%!XB5mkwGpr-`D?B{YM(krBGWhra0k|
z%cm$Tf0~tb4Eldpm`6`O0Wka@tdL-2Vq89KW5)RZ)&KX@iUt<u-M?TrMIEI&@iSzd
zH8oF8O3PNiZe|ZMhscLA7iRzY8Z#cV3p>_ml;BYqb$X+4c&%T5+HyvlePfitIXACQ
zozf^FjXvahe0#V|s)S-xmihHVZbB)Wso5g>`wvAPW%7R3*_@xGKh$$HSw1Kw^5lf)
z(5V9o65T8Kw5VPYB!nnPZ#LyTpP;d=a4)J>_f=@o&tO`7S)=IHSCxA;p)uiVo8n$4
zDxbkN8haSy80(m5r8Jo<vU!Dk;FINF232SQv=~48p}HGKADxn;I3eRxF~#s9Cb5rb
zKzY*=DUIwzG9q0IB#ju#;^^b)W9bt!qk;W^0YE=saI|l9V6?wz6TV5YL9v;*k+{i^
z)bmM)8U@HMy=Y~1iWBTl-Q+;pBN0gLD*~TXs9}IcfO3F-fP4UOiQzDAId(ZwB3dF&
z;)hp%(`M8rU_%U<kF-V_UAbN1`DCJUQSqo6sImA92qS%5YkX^LYa&s9=q4kQ2pNS0
zAV-mER}@#kE5R$TE21mF71vdgzkxVIW*neDf0GxfdzFT&Lq(yuV!~7&XMG_Kwh2qv
z4$Ghni%AMg)(MNB2}>6Wi>(h!^$ttC49k3|5dB2~SCPr~Rk}sA$`9E}MZ$h2pI4cr
z(NeZ#EHArrzQq0DQCIDdVIqFU#H}v5mh;2e6|*7QK*l#ZBZs0P>9M+Op&~&6lgGxh
ziBtn6PDXIwW)9bmeCZ3|k0J$#EC2KNr3}+Q5PfGBFB$?D6tH93EgnBt3W@RMN#lzq
z&WZW{D!b2SLZ&CWA}9GfBS%jBcV-d=YFlR7oLH4tv3(Xi!3#2uuQmEPEU1!I9hvH4
z=KJw^VizP2UU|hd^|SM&4l%g(i@Fje1IVL;H;gL77UU0@iK4qLp7=zwGY$4hZ<rz<
z>#Ax;$8V@1DSgsJCADLi`!zOfk@!9dqVn3Y@P51vS>!XH<YET<e&NatsFc9{T+3B{
zb$G4cXTRZ584s1LjoIJ$fF!@4Oz9;ikv>%<olmC!d+}HFF@_d`_Y)v>9u4TXw&1!-
z^Oro2;pzu&*jHxKyjYG7+R#VRUS-g{4DBaIVqL|cWCC8x_j7Fkk<?e|D9O85kQnm~
zp?8w1KQuP@-bs)AaNBS~5?v)KY36-VANVcBuc_>z2_TqK_%NlyF{K2WQl*_zG@SY%
zHl+-n0$}keNb?2fP4K0t^4h!}{x!=Nx-}u10>HCj;P};D{Uu?7M^Cj=Gnbeums?MA
zz50i%FJ^PJk&NG1Mm0rq60V+Xku5<<uE*)Kxl|)1u59r3W;NHoeA!RnM3D`|m!I~1
zS=RIfV*AYfMRVYi0?v55`(s+A&~abkG=VYV>X^u!>}{JlnclIA>g335j_UZxd=eXK
zP(E#StZGi|wuNx;l8jTH#tw%&Rl2HEZr%9&4!&^glH_5I*Lc$oyKw4AmfMb~FHt&x
zVl4R7s4;9w{xF|ttlRwwIGQtea9jG+^!l-(DsU|RRPCA)oF*;_9B1CqIJLdT2PcTj
z11I4-c&D=0&%nv0S@t`^jTtRcf@8oPxyG-KdHUP-ryh;*Es}NP`==kS$-${D(#yFb
z+p5=e;LL#c5;^qahVFv5NdZz9V}KoNcdpyC0LhDSt{vd1ePbrw&*ib8Q~hh&+YGv2
zp*zIaShq2EGLSs^9j;U0HT7-!og_L3GH!k<Bqj-%&^YB2lOCOLJ9WAyx=mD6vHGIc
zlhnbdGU%={ia*q+GBm_KG~h5aLNnBFFf=SWH0VDx`hdMpiaj{Dk}qL|N9XmR*(`hL
zW~FGtD6S3zn^|}9m-tE^?U4=@OJZ_MZteE9;vX)am`%}!UB2ZR#S~3RPqe!WbqR_r
zJ@%f#QVj<<&A~I9#axKqQWIchkq*R@pSrEobh;8TbLQ}(DR8k5yQ1CUG4()5g|9#w
ze>rh+OoT=Dj18=-r@W##Il`QyI6lIfM2FhmnzlIhgGKC&g+TCPm!p-&EQbSC>WHId
zUB&z?zCi3^`+<d5Mbj+1K<com+pMT3QR*mpdGMZ5ZP;S(fi+Qix5E>^Xb#K48R<RK
z^T+xl+U4<kYUh-GX=3f#70k05d$#BJehFf|+Ewsbygk|TXMV{gruMVKwHeJF0_DJ2
zx!SKFEBzV!J&)S>=Jwi({k;$8<bJ8molBM?GpgrwewpAlaSQqiLkGc|Byh)hIbhb>
zf$Js>+<socH4EIcug#=2SuPLS(?6%Z$)Gh0oh3fUx{0~%3b2x&<=O+DQ{SZDw%=Jm
zD$MtUMA}s=HTL*KI!7wq_MFa%Zh$eQx(v8lNx$Au$rf#sHk*C?{!Njajl8>XhO}wz
zW7;=m7dE=?qD#`&XCFT+DJZI`$MZ26_J8DwXJ^vyS96UQWin>@h#UVhSBFJSDV`_S
z;0asdGqqnzDg__clyW=b@#65}!{g|b0J({-6))phbM*?;?BaztpXJuM7Pux)$Tt}5
z6rF06ek|22RljBfvSG#9$Jxgt;t=tH0|WyR11~Jgd1Rg!;%n^2uPO!cNZD%2v1Z4O
zE5-82Jul*8TaP2p)p}m0Vsd5JDx1c*sT3olvdy;mB0^~eC9p$htNW6$IJQ=iUeQ=l
zLW$Xeb$)}i;bY_=KT-?%)TdZfw}p}TNdohy7Vbc}*pr1j*31tk6X|V6x)00}U;mtn
z{xrn##D-n<{Yq|E-kp(Ita#jvJNkpeue+{1N<{}(Fi9%xch_roeKQT+gqc?`Ch}YP
zud*mcu^1iy+AcFz752y!nJOYhzQYX}-lbHVQuwoBr03cyB-T60`WaDgeEn?h*VJhd
z7v2!&*MeHfxuQQs^Ps;S)I3@J;t%5`;vjr-5rEiiHU4J4M0;#IIlDRjI=d~~1iOr>
z;y=)=tB)tSTR6im9OHU544}YTDgBaWbrBsAIT1w>ji!$`VduL0*!%i(Q8hT#@-_J$
zROuRtrEKGdKbvF(-vi6+#}|v6^u1aS)E4m?hZ|`dN8Oiq0;X?E1h<>79l$!v8q4yK
z<`%W(yv)+fBFM*9rB=CCEp%W&=3UrblB9qRzNB;ugVk>y15-*18y*$Dp||XBMIF3*
zj=rsa=ydE1=o}5vkn7%loA*3CVnN3mIwv$FG~yk5%()KkiSL0&q<%l7lHd=pM-6+A
z<Ouqx=;pa<5KUU<AygPuNK__O+*FiR07*sy&5pjyr@=erJ6u&30;yPAqHa^{L$^bM
zDe|cz!*!|fRC*o>kdf1p<C5jw94huICs=ncK~p&<cS7BM$LYD9ZLLbhf~~HFuBk3)
z*2br|ve$JCS+rTKW$mHQTVe?dFHY1es}a!Y)px2GspYH{cLeuer<{o);4o>JL<xFM
zMWB^qn*4qdBJ7*m1qNWIO~am1pyYj)dEt41dHLEh2Z=e=nSw<tKn2Cz`Z?8&);Ys@
z#d-g^$lk?V;(TURs~u$i?&~e}4c9p@VM*s^pL3irr~9d=!8+xEjfaZIkgMp5_t5b#
z^KkQg^RjinUiwH#nq2;9^15bvb6TPZj<CG&e0rTQ{9U4OrhBPJ%PMN@D)$5j?n2?B
zYsdf$Eb7qOZ=B$t;qT$^=bx+@I}1bTPGe8&mqr=l7|0vuFH+S_rXO&+7_YQ+iM1IX
zI=U?HwakNCZ`3aE4u%hC4@MW38z5fjeQs}Ph67+`a&ofQtvP>uax3{D8R0WlHBi-4
z_2(qeIujlSPXeCnK_#791h-0%Mys?NAf)Q)$Pwp}_#U|D=G(=GL&w8_!_g%T@oxB0
z?$tN&0ubIbCpaWH;uU+yxeRWJZ-IkT{SU9j&%lVAVXu+03qO?ZohyV0ZFz@4F``IN
zlPEWoG74~MeBOEhSw;t=%h6?@NZ;Z-2!y`pd-34*fgrXVjxbgo&K3?Gt|+Yz{S4g<
z*`@H2#)?Jsqy6?N6SZ<49qK)L8Y%}u)hA2O4M+`$4QLlA{h8~Tz29EiA2}#cxQ6mb
zTV{nzC5Ds|@PFwEb$l{R$U!JZ=gV@cx7|Dj&yvo%ziQ7*Qb(~gu*AfLYh33oMDwub
zGH%w!`Kc%5ipE!RTIvtTvl!>1l3ZWL=gp~WsN-p@7w{JVa|sn`Q-$B1MNau?B<71J
zUfb=?7i8uH#9k}!Ci8((*f<zV`1U)hmu#nV2mtmUQd0!j_5-VXCyZ3)f7J4VoaQcU
zAvw3Pjw%<q@SLKZ<_RtUeUdm&v)C={)MrO|GE>Dk^-k_ObjLUk9UUMVWTC?=_59Iu
zvgd!E1Fi5!C}X)<%&mGlzRUAu49`R#Yxnd%$Ki>zN*kH75aylaRp#O9gT8WmZw0ne
z-WpE!vR=x(vf08*PUZEo2uQdx+&WB#SU<0X>dxw}7H8;!D@#Z1hU^AYGWZ1%?ZsNU
z_La3(;OH7IgaWL>;obZX+M$urNK2rlag5lTCKf-l^Y43)W{IpNVsDksQ)ip1F09dM
zU{?8lmyMiFQut9?V_K10$maLK1{Qc}+KsFBmS|=b3w$vR;MOvH#Q`@c6`zhxjn~hZ
zXS}FfK)A|psP?5Nh%kF89*{I}!CNwJ0uCq|Lfy~<vB)8xKqwSylhKDr^fF)ChK@kz
zPqyG<aTo4O*U){RCS=RV4a=d0_+TA8e~V%hxHY|XF-o7ZoF>799zn@ou_1wQry&S4
z1aQ}mGCmn4-^N{dl>Er@5e1ono-;^Ny8ZIAKCTr7JEu2vCHM0*?h@N2bme1v<|8zD
z3hr%iLvTz-INlBU(nq1f^6aD94nN#PGI6c?QfK{D`CwzRJ00&|VdS&l)W6||ugUVu
z0?7zisPy?7wj+P}g(pym0Z;A5=VdcV!5XK^<H=^AiXx%x`s&M$wWaQ9QX(!#jto7~
zqRYUw-fzb2OX|=nZ>QsnZU`w_!;Jknek1NTQ?n8$*K-}7%ADp6*bg5jW#tTZU45in
ze<+i20_vkHG%ik0SvvPoE?MrMTwnqrC#{BXfxFdC$Ar96CdcB(YwexhTpXpSgbdEf
zxOamSgGvLOZ<=x(-s^&Om1l=7y%HCV&uwP$EK>(P<G|YIhO>v3kVNW%=FQp7Rb<8{
zc%Y2SiQS1U(@4Ay)sEEKv>&KTfP8EzLn&NUl+)CH30g%tvm21LycB)2K$=0BL2UFi
zKnSIB8Gn?zy106~n%SAJDeLju*3M<x_-i4ssB_9?_rtE?E_hez%*P}4y7ao>y5u_5
zm-APY_e<Rvq(W4mWenma<4cm4lP}#~D!&BC7)3(qd?b*v8_pYLze)M!vBse`e5}82
ze+kOT%Zp^!$;0L8zlqZt(l632lHCelYn)nq@7}AJ(orks(WXYwQ&ZVTe)zihT%S~*
zSf6&D(vSIEb}xUX0asbpSN4^=)m<7#zNceMox{5Z54^>-ck$rHQ-fNo!3MVj4H1B&
zSe=G_#n3xmEmf2<yxd*7@)Dw*Ci-U7)H*Li^m0^l7)`XUNZ$Wa_f@z>4Ez1BPKE!L
z0JTiY_BumCoR>dm@y}T%PWpC0I#Xd+fyQPE+U2W@^fZ%oWLj%aJ%h`E&LP?-!b5hN
zpJ6c=&Q)2ekcI;5tbsHP89>>7k^RnAg{vFwla{Y1lM8xyH9l-b$L;Q2w_5Ius)+IO
zA3Lt2A1E_#q5rz?$Hc?}<FoyFp|RxY@MfaFDIbQ)BOIr{?g`pofT-vrOhb<;mcPG#
z?Gna-jelPeGIS}@tUV2Vy7o%-{)N)tfquUC{CIRCVQE5tt};QZ*o+pTGpGlv_*PRa
zb&tKmo}sMTS>#&9mR`k{98FSWg=4gZAA?ynvj~Tq>;+3MW~b0z-kUQ%ExqI1>N%sv
z<g!wan=d6}4BfxMjQwswWnVMVsEZ=>Iy_YZ(sIdWAi^mVgJd&+Uyj-@``>jVjF%u+
zDaO8}>Evt6E&ASztdY1Hs|_tj2B%w1;Y*_E6Q{G_UKdl+_zq<2(w|fy`RxXE_+VM<
zsaA~muGp?bikPso`|0-7_*FKWykOJ;Et|NNxRu0~_-k6kI{|Npy_wUBVDqBh+Q@yx
znQ!<~*2T6ZxGX?HqBL`yYj^r|{yONH^w*j$-8Bw1rE8@S<=0A9$_Yv^Wltr-DC(&B
z$fn4f$fDkxs3@9DQE@N-tIM9_MUqC6Jdz0JIn_&m1pq&dQjFWf?5=Cz>oAF5h*{9A
ziC{g!kF4IeHk7<7)a3X@Asn4|inoe`ioJ@XidPng{aLZ=%+{)$83rN^VC2uKk9Hg$
z3BJnl6D<>~6JIB0CvqpwCekN5HF`8^HA*#FG<FN_G#K+=1BTP}#A{sarhoIMe2?f6
z$X-t3C!~~*(CG15|K>7T57aiW;;c$+7|f~6sBEvSsNAUxuKZJ3QhDnNZpd9wJ77s1
z^cxHv=pD2kpctGUs2e0wrB>AkhyeTmZ232;M41^vVt&3mr`J2_lcBG(`>kA){a^o?
za-!n?kg}yRm`5<_7+l(+Ij%FVy;|0%jj#D#TSaRKSgh%wy{APEOkvxPKTs;D%y%t!
zEp}~m&2p`AEplyDGPW#m)$}RcC|oMcDm*SsF6=I>Dcmo_s%m%O7a2CHGCSZUN@X6Z
z+G09s^y&520TtJ3H5G#Y*m*$C6wWNp49;B7<jx!;N_#XXbtbjf%lcvXQ{Q1Ke}<-u
zryO8==`7;r;^q?T;*9A#?|8kf_J&TAgL#XrYe)9<Pszi(O^<afl*=spcpQ@}*!5uS
z^9ey!Ayu%dk*cMtf!UU-PHX0okqkrOrT|a)o@q%1OdC;n_NTDswuZ4Lw#Kbyu!g#(
z3GNP8fm4mvq@QFCW>5<W`a13|pc>-cQsL*t-P%=u96j`z?4vx!gsswRIdy;~`mkGJ
zaC+{D8oVGD;fn~_?Lk=Wk|SWdwFtspf-{(}b#t9j!C?`7Y3A?D65~SSvgHB^Q72I+
zkwf7_k+O_K2?^H#Bx>Pm^Mo4i1rko}huPRyU4eAxKY^wMEK}=BW&}Wf6yLa#xMsNO
zxfCdTIq{7so8E#=S37otOYm+8uCbMavfC$L2%ZYy^M4l{;$s&m=64XJG2k<(HgY#Q
zHPYlfH>7D1a&b9do9I3Z7oi}cj)<t017?@0f%cqeY||Xl><t_jY!;exnk*WpybJb!
zpw-VO+H%L0H4?YDN(|<p)zg{_7LJvI4XHVK8F}q_6?r>(!Fhl3O7d<8uLlzbBL_1E
zk(*0{(uuuXqXtG$sHe{jGH}tPZZ6%k%&_8OHguolT=(V&c(KJ?0%`^|Yg%huYx-rh
z)5_y&i5ysn-(;f(dY0{$rj!a8ftq$(Q<{aHJx+J0{#+HY0R_tr4B1+&TC7^PT3#C>
z8U(ySdvm8X!S+SdwWa$ar-b31t4Bf>@@3|I+y_Z6?7}db`N$wd2m*!}K`bE#&RP(i
z)6Au#M#haT0buyGX;sB6Y|rkTzi9Y&m~l9E*ll=ln0mNL&|OePkjklg@o2ekiL##C
z*L=4J6%kLJDtMmOty(pC;4Z>s9pyImZY#}`QwW%@KXRLTotlsunVOM`99~M57VLEz
zSulV$c)HzeNrq>2&#gHe*S_HZb98c$a8z+9b09cGI6~{b*E!S~)cMy<>EG7LIeu75
zX{zzJUx$?{!+9F03_+Z&YzQjnh{imFlTxzjJo`h>W6%lc26O@1@f_W6pEs||cj8(w
zYHs%MYt>q|v-PO<)!T$E!Lne-uw+;_tOm9Z3la$tfr*TWEQt)Hw}^Cly*?OP(rv5?
zu!fJArdABYw(L%73P86YMo=us4KxU%1~qwkczy7qKCE3lTOMAbtrzk2+C4xm#y6#U
zUCf2g5AUCQdNoZgO^VNm!^9U`##-iD{<J^<kWtrBmr*xB%e0@<_R?i@vS0WG>;SYZ
z;!M4uT{pS!!FC{iQSR3vhA?t1Yw}tMy@<E~T^L?~FaF%zUdSH+mNJ`K{UPgj2Uv?(
zlR-T=AR-h|B@s5=ckv|Ow`h~i_N}1i&~Bn(qJ5%8qTEn1A{_civ9y5tBj>YKSSL7Y
z$^2MIlrCy-=M3McM~pW^b~MF$-tDOGsPDS(s_#a@XX?V{a=a^hR$e&@M!zpA?C;?3
z;J4?y=T|I#01-ucBaau>H+!k0yfU{lk}~+jZT;3DKfpXk7N`AFu~*D&0D;UspYUd@
zvPHzX(h}X_Pp=`7eZ!+t-#X|G;0(Y4paqBlHuIYSp&5}9={}8@?)y9ElR<>ip*5Ye
ztNR~?uZ2TIUJF}^BnZPqJcS7}pJ&cyG-O<56pUVHMu?{R3tTu{&Gu9oW{y}R`LE~v
z1B_vUE7WHnuC~BzEgzPbPS)UC@N@V9eBvYn9yHpU0gy2EZn^eHTm|H}Oit`<pSlmE
zH>XRducz~-ho{@8&!^*X;d2#prEx*I;wZpeA;v1uByh#4*=_eoxOD5d(@7Ibymj~R
zBI=U)*6q#`9RitdUCuqMbbr?<YUm1dn*KQLJ*_frHmx`9IW1Y2H9xn%ckaoy2wv=5
zBw4IlR9-|ZiY$g=nzxZVKk~=qAET#yqJq8kU@$PEtu!ZAMLm1!^;K>$--`$(jR|P=
zOOTRZ``XWUHbjj<>gCKrlr(s%I250Y+Dldf6zD6z&@ccL2+u-7q}H>N$INUvs%eEE
zQ+L41dG`p|R$Gpoy<dt_8{w9PdUb?Ws@3*$&NAPB-H5&f+)0t%eGziaInRZNnStje
z=nA;5<{4{aGcT;Ono0ENtBKxIe>qpPVH^|31kub{XMK>od0DM%V;oqEv2Q<?kOjt@
zqpCiXod0qzZ6h)kfDfXd8(o@fbRUb9;(gB+Y89f5H;i5KBn3+kuUf!{=%-JXhg9rO
z*{p&w<d|<(^8*mZocvD$=^LSHZkx<NfhYTTV^%-G&*wy|%cS%_pMS6^8f(D<Va*Z!
z1WDfzSBu$51bbe>VBm)-bb2g&B-K<l+BO7Zdt)hC4L@t7Pu?RwZH1D5&U>#cjR-vF
zsSdEA|19uu-+W9i3yeGWuzFN7HRPPh#%;_fxc2crVodvIGd75J4l!2yvl$aaF$efb
z3$1zdu-eR~H|u$pmQ>aIqEOi5eO5l^YHb@wo2aa-pB~b&S%K&WE3FupTo`wFpZ*^q
z-~n23MdAsHIS~EoDD&Z6Y#Zd+zf@8@L_cbWNFEtK{riyN$oMge;sH9i?Qg|)i0P3r
zC5i(3??mPxw8c>-{#|T4gy#}~jqYEOc>b@G#t%^xm}uEH2=U*FYDdPTD2hjD+4jE^
zyW1e#N5=Rl3aq~kGauY(v_Wt$0hnl(6^Tcv{7-1of2rgmybBLPudTES{jK=$k_+=r
z`4jrt--w^lKUP{_U2;A7I}z{*U9ciShRXkp);!9@z0+uiu>MPB;sbPU8-(S^829f(
z+aqHtR3bJyxBc%#%QndKBV%k-BIe(UkI<Iw5ZxnV^1lz?9T^j%60y*mZGS7aLwt^m
z=}?I{|Gjv-CQ^t*AEOTpOpDkY;CS=F9cRWtwfOt`W3ZoKqPf@A^iuPI=jJvyV*%%|
zb5Gjp>@obYfvn`LKT=ha_Mf*t!5)+l%wgFW*`$xXvQe{Ptro2|vMGB{{pp<8rgKc3
z5QINx{quv=&4cRaHpU?WMEgZ!2|vLkbF9^e@8>_AW7*7)1v~^1%>lA#TWZc|0`o$(
zafct4V5gAjVeyGnTiI~h?2n0#3IDvx3jWD5HZkV=vl+jHelGMUf#eNkwVF-lX93K8
zx3Rn|@RK>3YG4+J)Qxa8nN69be(1SyHHVGU`}yE=5*r*R(BaduZ_9H_r~|vj7+(e>
z-|US)9jV1!&BqhePJa9FWk?Cf+^_#PZO9@HINH8ok{mStpIZW2K3vs+1?5v%p7?d3
z!>y(~3|Eb97q@JLqPA+S(S|&tgGEm!)|qUC%taph6eyecu}eDUO&Wz12TiL&xI<Qp
z;pt<=Q*u=WsDY5_vC?YaFJq{&Ojl@kblBIZZ_CeEj_1u}Ho6YKjd%Eov-EU{bmim1
z4cCZp^MNSSRj9tdwhH-O#3<Q_U$^Ee^kvJ7mN!excLqb>FpoDouA-CJ(ul&ZI-Zl3
zeUm+=UbA0AnCY;Gw^Fn+-euW*@UPr9cJKKGK(IH4%PzwV$D6aaZyLSGA{8$VIts?l
zc9x2Yrp^#cWxNP%_tw&)aRRymm@aN>viqtjsaA)<<%cN>@iYF_r-EG^F8bBv;w}cS
z@G=>hk->ft>(!BEjwQxxT(4{KW6b0Bj@w(`)q?;H|6*qfdWu$NafSe6f4%SFqhU{u
z<=3LR;oX^G5@ft<qg{zz#$m0b5T=%wcY3IZOOa!OV~%4`h2AMZcA4ecaol%Yf&yH&
zeIrZV$Ya=W;J#YQhU=xTRX@Gkk)AQmzstFk;-2W?xhUe%+?eQbINtorFY^Gak!V*u
z=jJFTh0!`vCo=8UD~jbN_aFa7-S1`~#(41*qa6P9@xxnM?l4LG2Tw7MX+M%Q#Z#*h
W-RHE?gW%vzb2(AV-ZAg{_<sNk5PZh~
--- a/testing/web-platform/tests/generic-sensor/README.md
+++ b/testing/web-platform/tests/generic-sensor/README.md
@@ -1,16 +1,36 @@
-The `generic-sensor-tests.js` tests require an implementation of
+The `resources/generic-sensor-helpers.js` tests require an implementation of
 the `GenericSensorTest` interface, which should emulate platform
 sensor backends. The `GenericSensorTest` interface is defined as:
 
 ```
+  class MockSensor {
+    // Sets fake data that is used to deliver sensor reading updates.
+    async setSensorReading(FrozenArray<double> readingData);
+    setStartShouldFail(boolean shouldFail); // Sets flag that forces sensor to fail.
+    getSamplingFrequency(); // Return the sampling frequency.
+  };
+
+  class MockSensorProvider {
+    // Sets flag that forces mock SensorProvider to fail when getSensor() is
+    // invoked.
+    setGetSensorShouldFail(DOMString sensorType, boolean shouldFail);
+    // Sets flag that forces mock SensorProvider to permissions denied when
+    // getSensor() is invoked.
+    setPermissionsDenied(DOMString sensorType, boolean permissionsDenied);
+    getCreatedSensor(DOMString sensorType); // Return `MockSensor` interface.
+    setMaximumSupportedFrequency(double frequency); // Sets the maximum frequency.
+    setMinimumSupportedFrequency(double frequency); // Sets the minimum frequency.
+  }
+
   class GenericSensorTest {
-    async initialize();  // Sets up the testing enviroment.
+    initialize();  // Sets up the testing environment.
     async reset(); // Frees the resources.
+    getSensorProvider(); // Returns `MockSensorProvider` interface.
   };
 ```
 
 The Chromium implementation of the `GenericSensorTest` interface is located in
 [generic_sensor_mocks.js](../resources/chromium/generic_sensor_mocks.js).
 
 Other browser vendors should provide their own implementations of
 the `GenericSensorTest` interface.
--- a/testing/web-platform/tests/generic-sensor/generic-sensor-tests.js
+++ b/testing/web-platform/tests/generic-sensor/generic-sensor-tests.js
@@ -1,409 +1,549 @@
-// These tests rely on the User Agent providing an implementation of
-// platform sensor backends.
-//
-// In Chromium-based browsers this implementation is provided by a polyfill
-// in order to reduce the amount of test-only code shipped to users. To enable
-// these tests the browser must be run with these options:
-//
-//   --enable-blink-features=MojoJS,MojoJSTest
-let loadChromiumResources = Promise.resolve().then(() => {
-  if (!window.MojoInterfaceInterceptor) {
-    // Do nothing on non-Chromium-based browsers or when the Mojo bindings are
-    // not present in the global namespace.
-    return;
+'use strict';
+
+// Run a set of tests for a given |sensorName|.
+// |readingData| is an object with 3 keys, all of which are arrays of arrays:
+// 1. "readings". Each value corresponds to one raw reading that will be
+//    processed by a sensor.
+// 2. "expectedReadings". Each value corresponds to the processed value a
+//    sensor will make available to users (i.e. a capped or rounded value).
+//    Its length must match |readings|'.
+// 3. "expectedRemappedReadings" (optional). Similar to |expectedReadings|, but
+//    used only by spatial sensors, whose reference frame can change the values
+//    returned by a sensor.
+//    Its length should match |readings|'.
+// |verificationFunction| is called to verify that a given reading matches a
+// value in |expectedReadings|.
+// |featurePolicies| represents |sensorName|'s associated sensor feature name.
+
+function runGenericSensorTests(sensorName,
+                               readingData,
+                               verificationFunction,
+                               featurePolicies) {
+  const sensorType = self[sensorName];
+
+  function validateReadingFormat(data) {
+    return Array.isArray(data) && data.every(element => Array.isArray(element));
+  }
+
+  const { readings, expectedReadings, expectedRemappedReadings } = readingData;
+  if (!validateReadingFormat(readings)) {
+    throw new TypeError('readingData.readings must be an array of arrays.');
+  }
+  if (!validateReadingFormat(expectedReadings)) {
+    throw new TypeError('readingData.expectedReadings must be an array of ' +
+                        'arrays.');
+  }
+  if (readings.length != expectedReadings.length) {
+    throw new TypeError('readingData.readings and ' +
+                        'readingData.expectedReadings must have the same ' +
+                        'length.');
+  }
+  if (expectedRemappedReadings &&
+      !validateReadingFormat(expectedRemappedReadings)) {
+    throw new TypeError('readingData.expectedRemappedReadings must be an ' +
+                        'array of arrays.');
+  }
+  if (expectedRemappedReadings &&
+      readings.length != expectedRemappedReadings.length) {
+    throw new TypeError('readingData.readings and ' +
+      'readingData.expectedRemappedReadings must have the same ' +
+      'length.');
   }
 
-  let chain = Promise.resolve();
-  [
-    '/resources/chromium/mojo_bindings.js',
-    '/resources/chromium/string16.mojom.js',
-    '/resources/chromium/sensor.mojom.js',
-    '/resources/chromium/sensor_provider.mojom.js',
-    '/resources/chromium/generic_sensor_mocks.js',
-  ].forEach(path => {
-    let script = document.createElement('script');
-    script.src = path;
-    script.async = false;
-    chain = chain.then(() => new Promise(resolve => {
-      script.onload = resolve;
-    }));
-    document.head.appendChild(script);
-  });
+  sensor_test(async (t, sensorProvider) => {
+    assert_true(sensorName in self);
+    sensorProvider.setGetSensorShouldFail(sensorName, true);
+    const sensor = new sensorType;
+    const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
+    sensor.start();
+
+    const event = await sensorWatcher.wait_for("error");
+
+    assert_false(sensor.activated);
+    assert_equals(event.error.name, 'NotReadableError');
+  }, `${sensorName}: Test that onerror is sent when sensor is not supported.`);
 
-  return chain;
-});
+  sensor_test(async (t, sensorProvider) => {
+    assert_true(sensorName in self);
+    sensorProvider.setPermissionsDenied(sensorName, true);
+    const sensor = new sensorType;
+    const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
+    sensor.start();
+
+    const event = await sensorWatcher.wait_for("error");
+
+    assert_false(sensor.activated);
+    assert_equals(event.error.name, 'NotAllowedError');
+  }, `${sensorName}: Test that onerror is sent when permissions are not\
+ granted.`);
+
+  sensor_test(async (t, sensorProvider) => {
+    assert_true(sensorName in self);
+    const sensor = new sensorType({frequency: 560});
+    const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
+    sensor.start();
 
-async function initialize_generic_sensor_tests() {
-  if (typeof GenericSensorTest === 'undefined') {
-    await loadChromiumResources;
-  }
-  assert_true(
-    typeof GenericSensorTest !== 'undefined',
-    'Mojo testing interface is not available.'
-  );
-  let sensorTest = new GenericSensorTest();
-  await sensorTest.initialize();
-  return sensorTest;
-}
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+    mockSensor.setStartShouldFail(true);
+
+    const event = await sensorWatcher.wait_for("error");
+
+    assert_false(sensor.activated);
+    assert_equals(event.error.name, 'NotReadableError');
+  }, `${sensorName}: Test that onerror is send when start() call has failed.`);
+
+  sensor_test(async (t, sensorProvider) => {
+    assert_true(sensorName in self);
+    const sensor = new sensorType({frequency: 560});
+    const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
+    sensor.start();
+
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
 
-function sensor_test(func, name, properties) {
-  promise_test(async (t) => {
-    let sensorTest = await initialize_generic_sensor_tests();
-    try {
-      await func(t);
-    } finally {
-      await sensorTest.reset();
-    };
-  }, name, properties);
-}
+    await sensorWatcher.wait_for("activate");
+
+    assert_less_than_equal(mockSensor.getSamplingFrequency(), 60);
+    sensor.stop();
+    assert_false(sensor.activated);
+  }, `${sensorName}: Test that frequency is capped to allowed maximum.`);
+
+  sensor_test(async (t, sensorProvider) => {
+    assert_true(sensorName in self);
+    const maxSupportedFrequency = 5;
+    sensorProvider.setMaximumSupportedFrequency(maxSupportedFrequency);
+    const sensor = new sensorType({frequency: 50});
+    const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
+    sensor.start();
+
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+
+    await sensorWatcher.wait_for("activate");
 
-const properties = {
-  'AmbientLightSensor' : ['timestamp', 'illuminance'],
-  'Accelerometer' : ['timestamp', 'x', 'y', 'z'],
-  'LinearAccelerationSensor' : ['timestamp', 'x', 'y', 'z'],
-  "GravitySensor" : ['timestamp', 'x', 'y', 'z'],
-  'Gyroscope' : ['timestamp', 'x', 'y', 'z'],
-  'Magnetometer' : ['timestamp', 'x', 'y', 'z'],
-  "UncalibratedMagnetometer" : ['timestamp', 'x', 'y', 'z',
-                                'xBias', 'yBias', 'zBias'],
-  'AbsoluteOrientationSensor' : ['timestamp', 'quaternion'],
-  'RelativeOrientationSensor' : ['timestamp', 'quaternion'],
-  'GeolocationSensor' : ['timestamp', 'latitude', 'longitude', 'altitude',
-                         'accuracy', 'altitudeAccuracy', 'heading', 'speed'],
-  'ProximitySensor' : ['timestamp', 'max']
-};
-const spatialSensors = ['Accelerometer',
-                       'LinearAccelerationSensor',
-                       'GravitySensor',
-                       'Gyroscope',
-                       'Magnetometer',
-                       'UncalibratedMagnetometer',
-                       'AbsoluteOrientationSensor',
-                       'RelativeOrientationSensor'];
+    assert_equals(mockSensor.getSamplingFrequency(), maxSupportedFrequency);
+    sensor.stop();
+    assert_false(sensor.activated);
+  }, `${sensorName}: Test that frequency is capped to the maximum supported\
+ frequency.`);
+
+  sensor_test(async (t, sensorProvider) => {
+    assert_true(sensorName in self);
+    const minSupportedFrequency = 2;
+    sensorProvider.setMinimumSupportedFrequency(minSupportedFrequency);
+    const sensor = new sensorType({frequency: -1});
+    const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
+    sensor.start();
+
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+
+    await sensorWatcher.wait_for("activate");
+
+    assert_equals(mockSensor.getSamplingFrequency(), minSupportedFrequency);
+    sensor.stop();
+    assert_false(sensor.activated);
+  }, `${sensorName}: Test that frequency is limited to the minimum supported\
+ frequency.`);
 
-function assert_reading_not_null(sensor) {
-  for (let property in properties[sensor.constructor.name]) {
-    let propertyName = properties[sensor.constructor.name][property];
-    assert_not_equals(sensor[propertyName], null);
-  }
-}
+  promise_test(async t => {
+    assert_true(sensorName in self);
+    const iframe = document.createElement('iframe');
+    iframe.allow = featurePolicies.join(' \'none\'; ') + ' \'none\';';
+    iframe.srcdoc = '<script>' +
+                    '  window.onmessage = message => {' +
+                    '    if (message.data === "LOADED") {' +
+                    '      try {' +
+                    '        new ' + sensorName + '();' +
+                    '        parent.postMessage("FAIL", "*");' +
+                    '      } catch (e) {' +
+                    '        parent.postMessage("PASS", "*");' +
+                    '      }' +
+                    '    }' +
+                    '   };' +
+                    '<\/script>';
+    const iframeWatcher = new EventWatcher(t, iframe, "load");
+    document.body.appendChild(iframe);
+    await iframeWatcher.wait_for("load");
+    iframe.contentWindow.postMessage('LOADED', '*');
 
-function assert_reading_null(sensor) {
-  for (let property in properties[sensor.constructor.name]) {
-    let propertyName = properties[sensor.constructor.name][property];
-    assert_equals(sensor[propertyName], null);
-  }
-}
+    const windowWatcher = new EventWatcher(t, window, "message");
+    const message = await windowWatcher.wait_for("message");
+    assert_equals(message.data, 'PASS');
+  }, `${sensorName}: Test that sensor cannot be constructed within iframe\
+ disallowed to use feature policy.`);
 
-function reading_to_array(sensor) {
-  const arr = new Array();
-  for (let property in properties[sensor.constructor.name]) {
-    let propertyName = properties[sensor.constructor.name][property];
-    arr[property] = sensor[propertyName];
-  }
-  return arr;
-}
+  promise_test(async t => {
+    assert_true(sensorName in self);
+    const iframe = document.createElement('iframe');
+    iframe.allow = featurePolicies.join(';') + ';';
+    iframe.srcdoc = '<script>' +
+                    '  window.onmessage = message => {' +
+                    '    if (message.data === "LOADED") {' +
+                    '      try {' +
+                    '        new ' + sensorName + '();' +
+                    '        parent.postMessage("PASS", "*");' +
+                    '      } catch (e) {' +
+                    '        parent.postMessage("FAIL", "*");' +
+                    '      }' +
+                    '    }' +
+                    '   };' +
+                    '<\/script>';
+    const iframeWatcher = new EventWatcher(t, iframe, "load");
+    document.body.appendChild(iframe);
+    await iframeWatcher.wait_for("load");
+    iframe.contentWindow.postMessage('LOADED', '*');
 
-function runGenericSensorTests(sensorName) {
-  const sensorType = self[sensorName];
+    const windowWatcher = new EventWatcher(t, window, "message");
+    const message = await windowWatcher.wait_for("message");
+    assert_equals(message.data, 'PASS');
+  }, `${sensorName}: Test that sensor can be constructed within an iframe\
+ allowed to use feature policy.`);
 
-  sensor_test(async t => {
+  sensor_test(async (t, sensorProvider) => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
     sensor.start();
+    assert_false(sensor.hasReading);
+
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+    await mockSensor.setSensorReading(readings);
 
     await sensorWatcher.wait_for("reading");
-    assert_reading_not_null(sensor);
+    const expected = new RingBuffer(expectedReadings).next().value;
+    assert_true(verificationFunction(expected, sensor));
     assert_true(sensor.hasReading);
 
     sensor.stop();
-    assert_reading_null(sensor);
+    assert_true(verificationFunction(expected, sensor, /*isNull=*/true));
     assert_false(sensor.hasReading);
-  }, `${sensorName}: Test that 'onreading' is called and sensor reading is valid`);
+  }, `${sensorName}: Test that 'onreading' is called and sensor reading is\
+ valid.`);
 
-  sensor_test(async t => {
+  sensor_test(async (t, sensorProvider) => {
     assert_true(sensorName in self);
     const sensor1 = new sensorType();
+    const sensorWatcher = new EventWatcher(t, sensor1, ["reading", "error"]);
+    sensor1.start();
+
     const sensor2 = new sensorType();
-    const sensorWatcher = new EventWatcher(t, sensor1, ["reading", "error"]);
     sensor2.start();
-    sensor1.start();
+
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+    await mockSensor.setSensorReading(readings);
 
     await sensorWatcher.wait_for("reading");
+    const expected = new RingBuffer(expectedReadings).next().value;
     // Reading values are correct for both sensors.
-    assert_reading_not_null(sensor1);
-    assert_reading_not_null(sensor2);
+    assert_true(verificationFunction(expected, sensor1));
+    assert_true(verificationFunction(expected, sensor2));
 
-    //After first sensor stops its reading values are null,
-    //reading values for the second sensor remains
+    // After first sensor stops its reading values are null,
+    // reading values for the second sensor sensor remain.
     sensor1.stop();
-    assert_reading_null(sensor1);
-    assert_reading_not_null(sensor2);
+    assert_true(verificationFunction(expected, sensor1, /*isNull=*/true));
+    assert_true(verificationFunction(expected, sensor2));
+
     sensor2.stop();
-    assert_reading_null(sensor2);
-  }, `${sensorName}: sensor reading is correct`);
+    assert_true(verificationFunction(expected, sensor2, /*isNull=*/true));
+  }, `${sensorName}: sensor reading is correct.`);
 
   sensor_test(async t => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
     sensor.start();
 
     await sensorWatcher.wait_for("reading");
     const cachedTimeStamp1 = sensor.timestamp;
 
     await sensorWatcher.wait_for("reading");
     const cachedTimeStamp2 = sensor.timestamp;
 
     assert_greater_than(cachedTimeStamp2, cachedTimeStamp1);
     sensor.stop();
-  }, `${sensorName}: sensor timestamp is updated when time passes`);
+  }, `${sensorName}: sensor timestamp is updated when time passes.`);
 
   sensor_test(async t => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
     assert_false(sensor.activated);
     sensor.start();
     assert_false(sensor.activated);
 
     await sensorWatcher.wait_for("activate");
     assert_true(sensor.activated);
 
     sensor.stop();
     assert_false(sensor.activated);
-  }, `${sensorName}: Test that sensor can be successfully created and its states are correct.`);
+  }, `${sensorName}: Test that sensor can be successfully created and its\
+ states are correct.`);
 
   sensor_test(async t => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
     const start_return = sensor.start();
 
     await sensorWatcher.wait_for("activate");
     assert_equals(start_return, undefined);
     sensor.stop();
-  }, `${sensorName}: sensor.start() returns undefined`);
+  }, `${sensorName}: sensor.start() returns undefined.`);
 
   sensor_test(async t => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
     sensor.start();
     sensor.start();
 
     await sensorWatcher.wait_for("activate");
     assert_true(sensor.activated);
     sensor.stop();
-  }, `${sensorName}: no exception is thrown when calling start() on already started sensor`);
+  }, `${sensorName}: no exception is thrown when calling start() on already\
+ started sensor.`);
 
   sensor_test(async t => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
     sensor.start();
 
     await sensorWatcher.wait_for("activate");
     const stop_return = sensor.stop();
     assert_equals(stop_return, undefined);
-  }, `${sensorName}: sensor.stop() returns undefined`);
+  }, `${sensorName}: sensor.stop() returns undefined.`);
 
   sensor_test(async t => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]);
     sensor.start();
 
     await sensorWatcher.wait_for("activate");
     sensor.stop();
     sensor.stop();
     assert_false(sensor.activated);
-  }, `${sensorName}: no exception is thrown when calling stop() on already stopped sensor`);
+  }, `${sensorName}: no exception is thrown when calling stop() on already\
+ stopped sensor.`);
 
-  sensor_test(async t => {
+  sensor_test(async (t, sensorProvider) => {
     assert_true(sensorName in self);
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
     sensor.start();
 
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+    await mockSensor.setSensorReading(readings);
+
+    const expectedBuffer = new RingBuffer(expectedReadings);
     await sensorWatcher.wait_for("reading");
+    const expected1 = expectedBuffer.next().value;
     assert_true(sensor.hasReading);
+    assert_true(verificationFunction(expected1, sensor));
     const timestamp = sensor.timestamp;
     sensor.stop();
     assert_false(sensor.hasReading);
 
     sensor.start();
     await sensorWatcher.wait_for("reading");
     assert_true(sensor.hasReading);
+    // |readingData| may have a single reading/expectation value, and this
+    // is the second reading we are getting. For that case, make sure we
+    // also wrap around as if we had the same RingBuffer used in
+    // generic_sensor_mocks.js.
+    const expected2 = expectedBuffer.next().value;
+    assert_true(verificationFunction(expected2, sensor));
+    // Make sure that 'timestamp' is already initialized.
     assert_greater_than(timestamp, 0);
+    // Check that the reading is updated.
     assert_greater_than(sensor.timestamp, timestamp);
     sensor.stop();
-  }, `${sensorName}: Test that fresh reading is fetched on start()`);
+  }, `${sensorName}: Test that fresh reading is fetched on start().`);
 
 //  TBD file a WPT issue: visibilityChangeWatcher times out.
-//  sensor_test(async t => {
+//  sensor_test(async (t, sensorProvider) => {
+//    assert_true(sensorName in self);
 //    const sensor = new sensorType();
 //    const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
-//    const visibilityChangeWatcher = new EventWatcher(t, document, "visibilitychange");
+//    const visibilityChangeWatcher = new EventWatcher(t, document,
+//                                                     "visibilitychange");
 //    sensor.start();
 
+//    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+//    await mockSensor.setSensorReading(readings);
+
 //    await sensorWatcher.wait_for("reading");
-//    assert_reading_not_null(sensor);
-//    const cachedSensor1 = reading_to_array(sensor);
+//    const expected = new RingBuffer(expectedReadings).next().value;
+//    assert_true(verificationFunction(expected, sensor));
+//    const cachedTimestamp1 = sensor.timestamp;
 
 //    const win = window.open('', '_blank');
 //    await visibilityChangeWatcher.wait_for("visibilitychange");
-//    const cachedSensor2 = reading_to_array(sensor);
+//    const cachedTimestamp2 = sensor.timestamp;
 
 //    win.close();
 //    sensor.stop();
-//    assert_object_equals(cachedSensor1, cachedSensor2);
-//  }, `${sensorName}: sensor readings can not be fired on the background tab`);
+//    assert_equals(cachedTimestamp1, cachedTimestamp2);
+//  }, `${sensorName}: sensor readings can not be fired on the background tab.`);
 
-  sensor_test(async t => {
+  sensor_test(async (t, sensorProvider) => {
     assert_true(sensorName in self);
-    const fastSensor = new sensorType({frequency: 30});
-    const slowSensor = new sensorType({frequency: 5});
-    slowSensor.start();
+    const fastSensor = new sensorType({frequency: 60});
+    fastSensor.start();
+
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
 
     const fastCounter = await new Promise((resolve, reject) => {
-      let fastCounter = 0;
-      let slowCounter = 0;
+      let fastSensorNotifiedCounter = 0;
+      let slowSensorNotifiedCounter = 0;
 
       fastSensor.onreading = () => {
-        fastCounter++;
-      }
-      slowSensor.onreading = () => {
-        slowCounter++;
-        if (slowCounter == 1) {
-          fastSensor.start();
-        } else if (slowCounter == 3) {
-          fastSensor.stop();
-          slowSensor.stop();
-          resolve(fastCounter);
+        if (fastSensorNotifiedCounter === 0) {
+          // For Magnetometer and ALS, the maximum frequency is less than 60Hz
+          // we make "slow" sensor 4 times slower than the actual applied
+          // frequency, so that the "fast" sensor will immediately overtake it
+          // despite the notification adjustments.
+          const slowFrequency = mockSensor.getSamplingFrequency() * 0.25;
+          const slowSensor = new sensorType({frequency: slowFrequency});
+          slowSensor.onreading = () => {
+            // Skip the initial notification that always comes immediately.
+            if (slowSensorNotifiedCounter === 1) {
+              fastSensor.stop();
+              slowSensor.stop();
+              resolve(fastSensorNotifiedCounter);
+            }
+            slowSensorNotifiedCounter++;
+          }
+          slowSensor.onerror = reject;
+          slowSensor.start();
         }
+        fastSensorNotifiedCounter++;
       }
       fastSensor.onerror = reject;
-      slowSensor.onerror = reject;
     });
-    assert_greater_than(fastCounter, 2,
-                        "Fast sensor overtakes the slow one");
-  }, `${sensorName}: frequency hint works`);
+    assert_greater_than(fastCounter, 2, "Fast sensor overtakes the slow one");
+  }, `${sensorName}: frequency hint works.`);
 
-  sensor_test(async t => {
+  sensor_test(async (t, sensorProvider) => {
     assert_true(sensorName in self);
     // Create a focused editbox inside a cross-origin iframe,
     // sensor notification must suspend.
     const iframeSrc = 'data:text/html;charset=utf-8,<html><body>'
                     + '<input type="text" autofocus></body></html>';
     const iframe = document.createElement('iframe');
     iframe.src = encodeURI(iframeSrc);
 
     const sensor = new sensorType();
     const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
     sensor.start();
 
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+    await mockSensor.setSensorReading(readings);
+
     await sensorWatcher.wait_for("reading");
-    assert_reading_not_null(sensor);
-    const cachedTimestamp = sensor.timestamp;
-    const cachedSensor1 = reading_to_array(sensor);
+    const expected = new RingBuffer(expectedReadings).next().value;
+    assert_true(verificationFunction(expected, sensor));
+    const cachedTimestamp1 = sensor.timestamp;
 
     const iframeWatcher = new EventWatcher(t, iframe, "load");
     document.body.appendChild(iframe);
     await iframeWatcher.wait_for("load");
-    const cachedSensor2 = reading_to_array(sensor);
-    assert_array_equals(cachedSensor1, cachedSensor2);
+    const cachedTimestamp2 = sensor.timestamp;
+    assert_equals(cachedTimestamp1, cachedTimestamp2);
 
     iframe.remove();
     await sensorWatcher.wait_for("reading");
-    const cachedSensor3 = reading_to_array(sensor);
-    assert_greater_than(sensor.timestamp, cachedTimestamp);
+    assert_greater_than(sensor.timestamp, cachedTimestamp1);
 
     sensor.stop();
   }, `${sensorName}: sensor receives suspend / resume notifications when\
-  cross-origin subframe is focused`);
+ cross-origin subframe is focused.`);
 
 //  Re-enable after https://github.com/w3c/sensors/issues/361 is fixed.
 //  test(() => {
-//     assert_throws("NotSupportedError", () => { new sensorType({invalid: 1}) });
-//     assert_throws("NotSupportedError", () => { new sensorType({frequency: 60, invalid: 1}) });
-//     if (spatialSensors.indexOf(sensorName) == -1) {
-//       assert_throws("NotSupportedError", () => { new sensorType({referenceFrame: "screen"}) });
+//     assert_throws("NotSupportedError",
+//         () => { new sensorType({invalid: 1}) });
+//     assert_throws("NotSupportedError",
+//         () => { new sensorType({frequency: 60, invalid: 1}) });
+//     if (!expectedRemappedReadings) {
+//       assert_throws("NotSupportedError",
+//           () => { new sensorType({referenceFrame: "screen"}) });
 //     }
-//  }, `${sensorName}: throw 'NotSupportedError' for an unsupported sensor option`);
+//  }, `${sensorName}: throw 'NotSupportedError' for an unsupported sensor\
+// option.`);
 
   test(() => {
     assert_true(sensorName in self);
     const invalidFreqs = [
       "invalid",
       NaN,
       Infinity,
       -Infinity,
       {}
     ];
     invalidFreqs.map(freq => {
       assert_throws(new TypeError(),
                     () => { new sensorType({frequency: freq}) },
                     `when freq is ${freq}`);
     });
-  }, `${sensorName}: throw 'TypeError' if frequency is invalid`);
+  }, `${sensorName}: throw 'TypeError' if frequency is invalid.`);
 
-  if (spatialSensors.indexOf(sensorName) == -1) {
+  if (!expectedRemappedReadings) {
     // The sensorType does not represent a spatial sensor.
     return;
   }
 
-  sensor_test(async t => {
+  sensor_test(async (t, sensorProvider) => {
     assert_true(sensorName in self);
-    const sensor = new sensorType({referenceFrame: "screen"});
-    const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]);
-    sensor.start();
+    const sensor1 = new sensorType({frequency: 60});
+    const sensor2 = new sensorType({frequency: 60, referenceFrame: "screen"});
+    const sensorWatcher = new EventWatcher(t, sensor1, ["reading", "error"]);
+
+    sensor1.start();
+    sensor2.start();
+
+    const mockSensor = await sensorProvider.getCreatedSensor(sensorName);
+    await mockSensor.setSensorReading(readings);
 
     await sensorWatcher.wait_for("reading");
-    //TODO use mock data to verify sensor readings, blocked by issue:
-    // https://github.com/web-platform-tests/wpt/issues/9686
-    assert_reading_not_null(sensor);
+
+    const expected = new RingBuffer(expectedReadings).next().value;
+    const expectedRemapped =
+        new RingBuffer(expectedRemappedReadings).next().value;
+    assert_true(verificationFunction(expected, sensor1));
+    assert_true(verificationFunction(expectedRemapped, sensor2));
 
-    sensor.stop();
-  }, `${sensorName}: sensor reading is correct when options.referenceFrame is 'screen'`);
+    sensor1.stop();
+    assert_true(verificationFunction(expected, sensor1, /*isNull=*/true));
+    assert_true(verificationFunction(expectedRemapped, sensor2));
+
+    sensor2.stop();
+    assert_true(verificationFunction(expectedRemapped, sensor2,
+                                     /*isNull=*/true));
+  }, `${sensorName}: sensor reading is correct when options.referenceFrame\
+ is 'screen'.`);
 
   test(() => {
     assert_true(sensorName in self);
     const invalidRefFrames = [
       "invalid",
       null,
       123,
       {},
       "",
       true
     ];
     invalidRefFrames.map(refFrame => {
       assert_throws(new TypeError(),
                     () => { new sensorType({referenceFrame: refFrame}) },
                     `when refFrame is ${refFrame}`);
     });
-  }, `${sensorName}: throw 'TypeError' if referenceFrame is not one of enumeration values`);
+  }, `${sensorName}: throw 'TypeError' if referenceFrame is not one of\
+ enumeration values.`);
 }
 
 function runGenericSensorInsecureContext(sensorName) {
   test(() => {
     assert_false(sensorName in window, `${sensorName} must not be exposed`);
-  }, `${sensorName} is not exposed in an insecure context`);
+  }, `${sensorName} is not exposed in an insecure context.`);
 }
-
-function runGenericSensorOnerror(sensorName) {
-  const sensorType = self[sensorName];
-
-  promise_test(async t => {
-    assert_true(sensorName in self);
-    const sensor = new sensorType();
-    const sensorWatcher = new EventWatcher(t, sensor, ["error", "activate"]);
-    sensor.start();
-
-    const event = await sensorWatcher.wait_for("error");
-    assert_false(sensor.activated);
-    assert_true(event.error.name == 'NotReadableError' ||
-                event.error.name == 'NotAllowedError');
-  }, `${sensorName}: 'onerror' event is fired when sensor is not supported`);
-}
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/generic-sensor/resources/generic-sensor-helpers.js
@@ -0,0 +1,119 @@
+'use strict';
+
+// These tests rely on the User Agent providing an implementation of
+// platform sensor backends.
+//
+// In Chromium-based browsers this implementation is provided by a polyfill
+// in order to reduce the amount of test-only code shipped to users. To enable
+// these tests the browser must be run with these options:
+//
+//   --enable-blink-features=MojoJS,MojoJSTest
+const loadChromiumResources = async () => {
+  if (!('MojoInterfaceInterceptor' in self)) {
+    // Do nothing on non-Chromium-based browsers or when the Mojo bindings are
+    // not present in the global namespace.
+    return;
+  }
+
+  const resources = [
+    '/gen/layout_test_data/mojo/public/js/mojo_bindings.js',
+    '/gen/mojo/public/mojom/base/string16.mojom.js',
+    '/gen/services/device/public/mojom/sensor.mojom.js',
+    '/gen/services/device/public/mojom/sensor_provider.mojom.js',
+    '/resources/chromium/generic_sensor_mocks.js',
+  ];
+
+  await Promise.all(resources.map(path => {
+    const script = document.createElement('script');
+    script.src = path;
+    script.async = false;
+    const promise = new Promise((resolve, reject) => {
+      script.onload = resolve;
+      script.onerror = reject;
+    });
+    document.head.appendChild(script);
+    return promise;
+  }));
+};
+
+async function initialize_generic_sensor_tests() {
+  if (typeof GenericSensorTest === 'undefined') {
+    await loadChromiumResources();
+  }
+  assert_true(
+    typeof GenericSensorTest !== 'undefined',
+    'Mojo testing interface is not available.'
+  );
+  let sensorTest = new GenericSensorTest();
+  await sensorTest.initialize();
+  return sensorTest;
+}
+
+function sensor_test(func, name, properties) {
+  promise_test(async (t) => {
+    let sensorTest = await initialize_generic_sensor_tests();
+    try {
+      await func(t, sensorTest.getSensorProvider());
+    } finally {
+      await sensorTest.reset();
+    };
+  }, name, properties);
+}
+
+function verifySensorReading(pattern, values, timestamp, isNull) {
+  function round(val) {
+    return Number.parseFloat(val).toPrecision(6);
+  }
+
+  if (isNull) {
+    return (values === null || values.every(r => r === null)) &&
+           timestamp === null;
+  }
+
+  return values.every((r, i) => round(r) === round(pattern[i])) &&
+         timestamp !== null;
+}
+
+function verifyXyzSensorReading(pattern, {x, y, z, timestamp}, isNull) {
+  return verifySensorReading(pattern, [x, y, z], timestamp, isNull);
+}
+
+function verifyQuatSensorReading(pattern, {quaternion, timestamp}, isNull) {
+  return verifySensorReading(pattern, quaternion, timestamp, isNull);
+}
+
+function verifyAlsSensorReading(pattern, {illuminance, timestamp}, isNull) {
+  return verifySensorReading(pattern, [illuminance], timestamp, isNull);
+}
+
+function verifyGeoSensorReading(pattern, {latitude, longitude, altitude,
+  accuracy, altitudeAccuracy, heading, speed, timestamp}, isNull) {
+  return verifySensorReading(pattern, [latitude, longitude, altitude,
+    accuracy, altitudeAccuracy, heading, speed], timestamp, isNull);
+}
+
+// A "sliding window" that iterates over |data| and returns one item at a
+// time, advancing and wrapping around as needed. |data| must be an array of
+// arrays.
+class RingBuffer {
+  constructor(data) {
+    this.bufferPosition_ = 0;
+    // Validate |data|'s format and deep-copy every element.
+    this.data_ = Array.from(data, element => {
+      if (!Array.isArray(element)) {
+        throw new TypeError('Every |data| element must be an array.');
+      }
+      return Array.from(element);
+    })
+  }
+
+  next() {
+    const value = this.data_[this.bufferPosition_];
+    this.bufferPosition_ = (this.bufferPosition_ + 1) % this.data_.length;
+    return { done: false, value: value };
+  }
+
+  [Symbol.iterator]() {
+    return this;
+  }
+}
--- a/testing/web-platform/tests/generic-sensor/resources/iframe_sensor_handler.html
+++ b/testing/web-platform/tests/generic-sensor/resources/iframe_sensor_handler.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>iframe sensor tester</title>
 <script src="/resources/testharness.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script>
   let mockBackend = null;
   // Minimum frequency supported by the mock backend is 5Hz. Using 200ms
   // update period + 50ms threshold.
   const maxUpdatePeriod = 250;
   let sensor = null;
   let lastTimestamp = null;
 
@@ -55,9 +55,9 @@
         sensor.stop();
       }
       mockBackend.reset().then(() => {
         e.source.postMessage({command: e.data.command,
                               result: 'success'}, '*');
       });
     }
   }
-</script>
\ No newline at end of file
+</script>
--- a/testing/web-platform/tests/geolocation-sensor/GeolocationSensor-iframe-access.https.html
+++ b/testing/web-platform/tests/geolocation-sensor/GeolocationSensor-iframe-access.https.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>GeolocationSensor iframe test</title>
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://wicg.github.io/geolocation-sensor/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
 <script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
 <div id="log"></div>
 <script>
 run_generic_sensor_iframe_tests('GeolocationSensor');
 </script>
--- a/testing/web-platform/tests/geolocation-sensor/GeolocationSensor.https.html
+++ b/testing/web-platform/tests/geolocation-sensor/GeolocationSensor.https.html
@@ -1,13 +1,29 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>GeolocationSensor Test</title>
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://wicg.github.io/geolocation-sensor/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-tests.js"></script>
 <script>
 
-runGenericSensorTests('GeolocationSensor');
+'use strict';
+
+const kReadings = {
+    readings: [
+        [1.12345, 2.12345, 3.12345, 0.95, 0.96, 4.12345, 5.123]
+    ],
+    expectedReadings: [
+        [1.12345, 2.12345, 3.12345, 0.95, 0.96, 4.12345, 5.123]
+    ]
+};
+
+runGenericSensorTests(
+    'GeolocationSensor',
+    kReadings,
+    verifyXyzSensorReading,
+    ['geolocation']);
 
 </script>
deleted file mode 100644
--- a/testing/web-platform/tests/geolocation-sensor/GeolocationSensor_onerror-manual.https.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>GeolocationSensor Test: onerror</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<link rel="help" href="https://wicg.github.io/geolocation-sensor/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
-<h2>Precondition</h2>
-<ol>
-  <li>
-    Disable the Geolocation sensor or run test on a device without Geolocation sensor.
-  </li>
-</ol>
-<script>
-
-runGenericSensorOnerror('GeolocationSensor');
-
-</script>
--- a/testing/web-platform/tests/gyroscope/Gyroscope-iframe-access.https.html
+++ b/testing/web-platform/tests/gyroscope/Gyroscope-iframe-access.https.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>Gyroscope iframe test</title>
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://www.w3.org/TR/gyroscope/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
 <script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
 <div id="log"></div>
 <script>
 
 run_generic_sensor_iframe_tests('Gyroscope');
 </script>
--- a/testing/web-platform/tests/gyroscope/Gyroscope.https.html
+++ b/testing/web-platform/tests/gyroscope/Gyroscope.https.html
@@ -1,15 +1,33 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>Gyroscope Test</title>
 <meta name="timeout" content="long">
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://www.w3.org/TR/gyroscope/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
 <script>
 
-runGenericSensorTests('Gyroscope');
+'use strict';
+
+const kReadings = {
+    readings: [
+        [1.12345, 2.12345, 3.12345]
+    ],
+    expectedReadings: [
+        [1.12345, 2.12345, 3.12345]
+    ],
+    expectedRemappedReadings: [
+        [-2.12345, 1.12345, 3.12345]
+    ]
+};
+
+runGenericSensorTests(
+    'Gyroscope',
+    kReadings,
+    verifyXyzSensorReading,
+    ['gyroscope']);
 
 </script>
deleted file mode 100644
--- a/testing/web-platform/tests/gyroscope/Gyroscope_onerror-manual.https.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Gyroscope Test: onerror</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<link rel="help" href="https://www.w3.org/TR/gyroscope/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
-<h2>Precondition</h2>
-<ol>
-  <li>
-    Disable the Gyroscope Sensor or run test on a device without Gyroscope Sensor.
-  </li>
-</ol>
-<script>
-
-runGenericSensorOnerror('Gyroscope');
-
-</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/autofocus/autofocus-in-not-fully-active-document.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+<script>
+'use strict';
+
+promise_test(async () => {
+  let doc = document.cloneNode(false);
+  doc.appendChild(doc.createElement('html'))
+  doc.firstChild.innerHTML = '<body><input autofocus/></body>';
+  await waitUntilStableAutofocusState();
+  assert_equals(doc.activeElement, doc.body);
+}, 'Autofocus element in not-fully-active document should not be queued.');
+</script>
--- a/testing/web-platform/tests/html/semantics/forms/autofocus/skip-not-fully-active.html
+++ b/testing/web-platform/tests/html/semantics/forms/autofocus/skip-not-fully-active.html
@@ -4,23 +4,15 @@
 <script src="resources/utils.js"></script>
 
 <iframe srcdoc="<input autofocus><script>window.frameElement.remove();</script>"></iframe>
 
 <script>
 'use strict';
 
 promise_test(async () => {
-  let doc = document.cloneNode(false);
-  doc.appendChild(doc.createElement('html'))
-  doc.firstChild.innerHTML = '<body><input autofocus/></body>';
-  await waitUntilStableAutofocusState();
-  assert_equals(doc.activeElement, doc.body);
-}, 'Autofocus element in not-fully-active document should not be queued.');
-
-promise_test(async () => {
   let iframe = document.querySelector('iframe');
   let iframeDocument = iframe.contentDocument;
   await waitForLoad(window);
   assert_not_equals(document.activeElement, iframe);
   assert_equals(iframeDocument.activeElement, iframeDocument.body);
 }, 'Autofocus element in not-fully-active document should be skipped while flusing.');
 </script>
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html
@@ -46,16 +46,23 @@ test(t => {
   assert_equals(
       referrerSameRemote, "",
       "Referrer should not be sent for the remote-origin descendant script.");
 }, "Importing a remote-origin descendant script from a same-origin top-level " +
    "script with the no-referrer policy.");
 
 test(t => {
   assert_equals(
+      referrerRemoteRemote, "",
+      "Referrer should not be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+   "top-level script with the no-referrer policy.");
+
+test(t => {
+  assert_equals(
       referrerRemoteSame, "",
       "Referrer should not be sent for the same-origin descendant script.");
 }, "Importing a same-origin descendant script from a remote-origin " +
    "top-level script with the no-referrer policy.");
 
 </script>
 </body>
 </html>
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html
@@ -34,24 +34,26 @@ test(t => {
    "origin-when-cross-origin policy.");
 
 test(t => {
   assert_equals(
       referrerRemote, origin,
       "Referrer should be sent for the remote-origin top-level script.");
 }, "Importing a remote-origin top-level script with the " +
    "origin-when-cross-origin policy.");
+
 test(t => {
   const scriptURL =
       new URL("resources/import-referrer-checker.sub.js", location.href)
   assert_equals(
       referrerSameSame, scriptURL + "?name=same_same",
       "Referrer should be sent for the same-origin descendant script.");
 }, "Importing a same-origin descendant script from a same-origin top-level " +
    "script with the origin-when-cross-origin policy.");
+
 test(t => {
   assert_equals(
       referrerSameRemote, origin,
       "Referrer should be sent for the remote-origin descendant script.");
 }, "Importing a remote-origin descendant script from a same-origin top-level " +
    "script with the origin-when-cross-origin policy.");
 
 test(t => {
--- a/testing/web-platform/tests/interfaces/SVG.idl
+++ b/testing/web-platform/tests/interfaces/SVG.idl
@@ -22,29 +22,29 @@ dictionary SVGBoundingBoxOptions {
   boolean stroke = false;
   boolean markers = false;
   boolean clipped = false;
 };
 
 interface SVGGraphicsElement : SVGElement {
   [SameObject] readonly attribute SVGAnimatedTransformList transform;
 
-  DOMRect getBBox(optional SVGBoundingBoxOptions options);
+  DOMRect getBBox(optional SVGBoundingBoxOptions options = {});
   DOMMatrix? getCTM();
   DOMMatrix? getScreenCTM();
 };
 
 SVGGraphicsElement includes SVGTests;
 
 [Exposed=Window]
 interface SVGGeometryElement : SVGGraphicsElement {
   [SameObject] readonly attribute SVGAnimatedNumber pathLength;
 
-  boolean isPointInFill(optional DOMPointInit point);
-  boolean isPointInStroke(optional DOMPointInit point);
+  boolean isPointInFill(optional DOMPointInit point = {});
+  boolean isPointInStroke(optional DOMPointInit point = {});
   float getTotalLength();
   DOMPoint getPointAtLength(float distance);
 };
 
 [Exposed=Window]
 interface SVGNumber {
   attribute float value;
 };
@@ -500,17 +500,17 @@ interface SVGTextContentElement : SVGGra
 
   long getNumberOfChars();
   float getComputedTextLength();
   float getSubStringLength(unsigned long charnum, unsigned long nchars);
   DOMPoint getStartPositionOfChar(unsigned long charnum);
   DOMPoint getEndPositionOfChar(unsigned long charnum);
   DOMRect getExtentOfChar(unsigned long charnum);
   float getRotationOfChar(unsigned long charnum);
-  long getCharNumAtPosition(optional DOMPointInit point);
+  long getCharNumAtPosition(optional DOMPointInit point = {});
   void selectSubString(unsigned long charnum, unsigned long nchars);
 };
 
 [Exposed=Window]
 interface SVGTextPositioningElement : SVGTextContentElement {
   [SameObject] readonly attribute SVGAnimatedLengthList x;
   [SameObject] readonly attribute SVGAnimatedLengthList y;
   [SameObject] readonly attribute SVGAnimatedLengthList dx;
--- a/testing/web-platform/tests/interfaces/reporting.idl
+++ b/testing/web-platform/tests/interfaces/reporting.idl
@@ -1,55 +1,61 @@
 // GENERATED CONTENT - DO NOT EDIT
 // Content was automatically extracted by Reffy into reffy-reports
 // (https://github.com/tidoust/reffy-reports)
 // Source: Reporting API 1 (https://w3c.github.io/reporting/)
 
+[Exposed=Window]
 interface ReportBody {
 };
 
+[Exposed=Window]
 interface Report {
   readonly attribute DOMString type;
   readonly attribute DOMString url;
   readonly attribute ReportBody? body;
 };
 
+[Exposed=Window]
 interface ReportingObserver {
   constructor(ReportingObserverCallback callback, optional ReportingObserverOptions options = {});
   void observe();
   void disconnect();
   ReportList takeRecords();
 };
 
 callback ReportingObserverCallback = void (sequence<Report> reports, ReportingObserver observer);
 
 dictionary ReportingObserverOptions {
   sequence<DOMString> types;
   boolean buffered = false;
 };
 
 typedef sequence<Report> ReportList;
 
+[Exposed=Window]
 interface DeprecationReportBody : ReportBody {
   readonly attribute DOMString id;
   readonly attribute Date? anticipatedRemoval;
   readonly attribute DOMString message;
   readonly attribute DOMString? sourceFile;
   readonly attribute unsigned long? lineNumber;
   readonly attribute unsigned long? columnNumber;
 };
 
+[Exposed=Window]
 interface InterventionReportBody : ReportBody {
   readonly attribute DOMString id;
   readonly attribute DOMString message;
   readonly attribute DOMString? sourceFile;
   readonly attribute unsigned long? lineNumber;
   readonly attribute unsigned long? columnNumber;
 };
 
+[Exposed=Window]
 interface CrashReportBody : ReportBody {
   readonly attribute DOMString? reason;
 };
 
 dictionary GenerateTestReportParameters {
   required DOMString message;
   DOMString group = "default";
 };
--- a/testing/web-platform/tests/interfaces/web-animations.idl
+++ b/testing/web-platform/tests/interfaces/web-animations.idl
@@ -18,17 +18,17 @@ interface DocumentTimeline : AnimationTi
 };
 
 [Exposed=Window,
  Constructor(optional AnimationEffect? effect = null,
              optional AnimationTimeline? timeline)]
 interface Animation : EventTarget {
              attribute DOMString                id;
              attribute AnimationEffect?         effect;
-             attribute AnimationTimeline?       timeline;
+    readonly attribute AnimationTimeline?       timeline;
              attribute double?                  startTime;
              attribute double?                  currentTime;
              attribute double                   playbackRate;
     readonly attribute AnimationPlayState       playState;
     readonly attribute AnimationReplaceState    replaceState;
     readonly attribute boolean                  pending;
     readonly attribute Promise<Animation>       ready;
     readonly attribute Promise<Animation>       finished;
--- a/testing/web-platform/tests/interfaces/webxr.idl
+++ b/testing/web-platform/tests/interfaces/webxr.idl
@@ -5,17 +5,17 @@
 
 partial interface Navigator {
   [SecureContext, SameObject] readonly attribute XR xr;
 };
 
 [SecureContext, Exposed=Window] interface XR : EventTarget {
   // Methods
   Promise<void> supportsSession(XRSessionMode mode);
-  Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit options = {});
+  [NewObject] Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit options = {});
 
   // Events
   attribute EventHandler ondevicechange;
 };
 
 enum XRSessionMode {
   "inline",
   "immersive-vr"
@@ -35,17 +35,17 @@ enum XRVisibilityState {
 [SecureContext, Exposed=Window] interface XRSession : EventTarget {
   // Attributes
   readonly attribute XRVisibilityState visibilityState;
   [SameObject] readonly attribute XRRenderState renderState;
   [SameObject] readonly attribute XRInputSourceArray inputSources;
 
   // Methods
   void updateRenderState(optional XRRenderStateInit state = {});
-  Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceType type);
+  [NewObject] Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceType type);
 
   long requestAnimationFrame(XRFrameRequestCallback callback);
   void cancelAnimationFrame(long handle);
 
   Promise<void> end();
 
   // Events
   attribute EventHandler onend;
@@ -88,17 +88,17 @@ enum XRReferenceSpaceType {
   "local",
   "local-floor",
   "bounded-floor",
   "unbounded"
 };
 
 [SecureContext, Exposed=Window]
 interface XRReferenceSpace : XRSpace {
-  XRReferenceSpace getOffsetReferenceSpace(XRRigidTransform originOffset);
+  [NewObject] XRReferenceSpace getOffsetReferenceSpace(XRRigidTransform originOffset);
 
   attribute EventHandler onreset;
 };
 
 [SecureContext, Exposed=Window]
 interface XRBoundedReferenceSpace : XRReferenceSpace {
   readonly attribute FrozenArray<DOMPointReadOnly> boundsGeometry;
 };
--- a/testing/web-platform/tests/lint.whitelist
+++ b/testing/web-platform/tests/lint.whitelist
@@ -815,23 +815,26 @@ LAYOUTTESTS APIS: permissions/test-backg
 LAYOUTTESTS APIS: resources/chromium/generic_sensor_mocks.js
 LAYOUTTESTS APIS: resources/chromium/webxr-test.js
 
 # Signed Exchange files have hard-coded URLs in the certUrl field
 WEB-PLATFORM.TEST:signed-exchange/resources/*.sxg
 WEB-PLATFORM.TEST:signed-exchange/appcache/resources/*.sxg
 WEB-PLATFORM.TEST:signed-exchange/resources/generate-test-sxgs.sh
 
+# Tests that depend on resources in /gen/ in Chromium:
 # https://github.com/web-platform-tests/wpt/issues/16455
+# Please consult with ecosystem-infra@chromium.org before adding more.
 MISSING DEPENDENCY: idle-detection/interceptor.https.html
 MISSING DEPENDENCY: sms/resources/helper.js
 MISSING DEPENDENCY: web-nfc/resources/nfc-helpers.js
 MISSING DEPENDENCY: shape-detection/resources/shapedetection-helpers.js
 MISSING DEPENDENCY: webxr/resources/webxr_util.js
 MISSING DEPENDENCY: contacts/resources/helpers.js
+MISSING DEPENDENCY: generic-sensor/resources/generic-sensor-helpers.js
 
 # Tests that are false positives for using Ahem as a system font
 AHEM SYSTEM FONT: acid/acid3/test.html
 AHEM SYSTEM FONT: resource-timing/resources/all_resource_types.htm
 AHEM SYSTEM FONT: resource-timing/resources/iframe-reload-TAO.sub.html
 
 # These tests are imported from mozilla-central and can't be modified in WPT.
 # They do load Ahem as a web font, but they use their own copy which trips the
--- a/testing/web-platform/tests/magnetometer/Magnetometer-iframe-access.https.html
+++ b/testing/web-platform/tests/magnetometer/Magnetometer-iframe-access.https.html
@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>Magnetometer iframe test</title>
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://www.w3.org/TR/magnetometer/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
 <script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
 <div id="log"></div>
 <script>
 
 run_generic_sensor_iframe_tests('Magnetometer');
 run_generic_sensor_iframe_tests('UncalibratedMagnetometer');
 </script>
--- a/testing/web-platform/tests/magnetometer/Magnetometer.https.html
+++ b/testing/web-platform/tests/magnetometer/Magnetometer.https.html
@@ -1,16 +1,39 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>Magnetometer Test</title>
 <meta name="timeout" content="long">
 <link rel="author" title="Intel" href="http://www.intel.com">
 <link rel="help" href="https://www.w3.org/TR/magnetometer/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
 <script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
 <script>
 
-runGenericSensorTests('Magnetometer');
-runGenericSensorTests('UncalibratedMagnetometer');
+'use strict';
+
+const kReadings = {
+    readings: [
+        [-19.2, 12.1, -44.3]
+    ],
+    expectedReadings: [
+        [-19.2, 12.1, -44.3]
+    ],
+    expectedRemappedReadings: [
+        [-12.1, -19.2, -44.3]
+    ]
+};
+
+runGenericSensorTests(
+    'Magnetometer',
+    kReadings,
+    verifyXyzSensorReading,
+    ['magnetometer']);
+
+runGenericSensorTests(
+    'UncalibratedMagnetometer',
+    kReadings,
+    verifyXyzSensorReading,
+    ['magnetometer']);
 
 </script>
deleted file mode 100644
--- a/testing/web-platform/tests/magnetometer/Magnetometer_onerror-manual.https.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Magnetometer Test: onerror</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<link rel="help" href="https://www.w3.org/TR/magnetometer/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/generic-sensor/generic-sensor-tests.js"></script>
-<div id="log"></div>
-<h2>Precondition</h2>
-<ol>
-  <li>
-    Disable the Magnetometer Sensor or run test on a device without Magnetometer Sensor.
-  </li>
-</ol>
-<script>
-
-runGenericSensorOnerror('Magnetometer');
-runGenericSensorOnerror('UncalibratedMagnetometer');
-
-</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-001.html
@@ -0,0 +1,283 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<style>
+  @font-face {
+    font-family: operators;
+    src: url("/fonts/math/operators.woff");
+  }
+  math, math * {
+      font-family: operators;
+      /* Use large enough font-size so that 1/18em = 2.77px > epsilon and
+         one can really distinguish lspace/rspace values. */
+      font-size: 50px;
+  }
+</style>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+
+  async function runTests() {
+      let epsilon = 1;
+      let json = await fetchOperatorDictionary();
+
+      // The operator dictionary has more than one thousand of entries so the
+      // tests are grouped in chunks so that these don't get much more
+      // importance than other MathML tests. For easy debugging, one can set the
+      // chunk size to 1. Also, note that the test div will remain visible for
+      // failed tests.
+      const entryPerChunk = 50
+
+      var counter = 0;
+      var tests = {
+          "lspace/rspace": null,
+          "movablelimits": null,
+          "largeop": null,
+          "stretchy": null,
+          "symmetric": null,
+          "accent": null
+      };
+
+      for (key in json.dictionary) {
+
+          if (counter % entryPerChunk === 0) {
+              // Start of a new chunk.
+              // Complete current async tests and create new ones for the next chunk.
+              for (name in tests) {
+                  if (tests[name]) tests[name].done();
+                  tests[name] = async_test(`Operator dictionary chunk ${1 + counter / entryPerChunk} - ${name}`);
+              }
+          }
+
+          let parsedKey = splitKey(key);
+          let entry = json.dictionary[key];
+
+          tests["lspace/rspace"].step(function() {
+              assert_true(MathMLFeatureDetection.has_operator_spacing());
+              document.body.insertAdjacentHTML("beforeend", `<div>\
+lspace/rspace for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}" lspace="${defaultPropertyValue(entry, 'lspace')}" rspace="${defaultPropertyValue(entry, 'rspace')}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </mrow>\
+</math>\
+</div>`);
+              var div = document.body.lastElementChild;
+              var mrows = div.getElementsByTagName("mrow");
+              function spaceBetween(element, i, j) {
+                  return element.children[j].getBoundingClientRect().left -
+                      element.children[i].getBoundingClientRect().right;
+              }
+              var lspace = spaceBetween(mrows[0], 0, 1);
+              var rspace = spaceBetween(mrows[0], 1, 2);
+              var lspaceRef = spaceBetween(mrows[1], 0, 1);
+              var rspaceRef = spaceBetween(mrows[1], 1, 2);
+              assert_approx_equals(lspace, lspaceRef, epsilon, `lspace (${key})`);
+              assert_approx_equals(rspace, rspaceRef, epsilon, `rspace (${key})`);
+              div.style.display = "none";
+          });
+
+          tests["movablelimits"].step(function() {
+              assert_true(MathMLFeatureDetection.has_movablelimits());
+              var defaultValue = defaultPropertyValue(entry, "movablelimits");
+              document.body.insertAdjacentHTML("beforeend", `<div>\
+movablelimits for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <munder>\
+    <mo stretchy="false" form="${parsedKey.form}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </munder>\
+</math>\
+ VS \
+<math>\
+  <munder>\
+    <mo stretchy="false" form="${parsedKey.form}" movablelimits="${defaultValue}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </munder>\
+</math>\
+</div>`);
+              var div = document.body.lastElementChild;
+              var munders = div.getElementsByTagName("munder");
+              munder = munders[0].getBoundingClientRect()
+              munderRef = munders[1].getBoundingClientRect()
+              assert_approx_equals(munder.height, munderRef.height, epsilon, `Movablelimits property for ${key} should be '${defaultValue}'`);
+              div.style.display = "none";
+          });
+
+          tests["largeop"].step(function() {
+              // FIXME: Should really detect largeop support...
+              assert_true(MathMLFeatureDetection.has_mspace());
+              var defaultValue = defaultPropertyValue(entry, "largeop");
+              document.body.insertAdjacentHTML("beforeend", `<div>\
+largeop for "${parsedKey.characters}" (${parsedKey.form}): \
+<math displaystyle="true">\
+  <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+</math>\
+ VS \
+<math displaystyle="true">\
+  <mo form="${parsedKey.form}" largeop="${defaultValue}">${parsedKey.characters}</mo>\
+</math>\
+</div>`);
+              var div = document.body.lastElementChild;
+              var mos = div.getElementsByTagName("mo");
+              mo = mos[0].getBoundingClientRect()
+              moRef = mos[1].getBoundingClientRect()
+              assert_approx_equals(mo.height, moRef.height, epsilon, `Largeop property for ${key} should be '${defaultValue}'`);
+              div.style.display = "none";
+          });
+
+          if (entry.horizontal) {
+              tests["stretchy"].step(function() {
+                  // FIXME: Should really detect stretchy support...
+                  assert_true(MathMLFeatureDetection.has_munder());
+                  var defaultValue = defaultPropertyValue(entry, "stretchy");
+                  document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <munder>\
+    <mn>&nbsp;&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+  </munder>\
+</math>\
+ VS \
+<math>\
+  <munder>\
+    <mn>&nbsp;&nbsp;</mn>\
+    <mo form="${parsedKey.form}" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+  </munder>\
+</math>\
+</div>`);
+                  var div = document.body.lastElementChild;
+                  var mos = div.getElementsByTagName("mo");
+                  mo = mos[0].getBoundingClientRect()
+                  moRef = mos[1].getBoundingClientRect()
+                  assert_approx_equals(mo.width, moRef.width, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+                  div.style.display = "none";
+              });
+          } else {
+              tests["stretchy"].step(function() {
+                  // FIXME: Should really detect stretchy support...
+                  assert_true(MathMLFeatureDetection.has_mspace());
+                  var defaultValue = defaultPropertyValue(entry, "stretchy");
+                  document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" symmetric="false">${parsedKey.characters}</mo>\
+    <mspace height="2em"></mspace>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" symmetric="false" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+    <mspace height="2em"></mspace>\
+  </mrow>\
+</math>\
+</div>`);
+                  var div = document.body.lastElementChild;
+                  var mos = div.getElementsByTagName("mo");
+                  mo = mos[0].getBoundingClientRect()
+                  moRef = mos[1].getBoundingClientRect()
+                  assert_approx_equals(mo.height, moRef.height, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+                  div.style.display = "none";
+              });
+              tests["symmetric"].step(function() {
+                  // FIXME: Should really detect symmetric support...
+                  assert_true(MathMLFeatureDetection.has_mspace());
+                  var defaultValue = defaultPropertyValue(entry, "symmetric");
+                  document.body.insertAdjacentHTML("beforeend", `<div>\
+symmetric for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" stretchy="true">${parsedKey.characters}</mo>\
+    <mspace height="1.5em"></mspace>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" stretchy="true" symmetric="${defaultValue}">${parsedKey.characters}</mo>\
+    <mspace height="1.5em"></mspace>\
+  </mrow>\
+</math>\
+</div>`);
+                  var div = document.body.lastElementChild;
+                  var mos = div.getElementsByTagName("mo");
+                  mo = mos[0].getBoundingClientRect()
+                  moRef = mos[1].getBoundingClientRect()
+                  assert_approx_equals(mo.height, moRef.height, epsilon, `Symmetric property for ${key} should be '${defaultValue}'`);
+                  div.style.display = "none";
+              });
+          }
+
+          tests["accent"].step(function() {
+              // FIXME: Should really detect accent support...
+              assert_true(MathMLFeatureDetection.has_mover());
+              var defaultValue = defaultPropertyValue(entry, "accent");
+              document.body.insertAdjacentHTML("beforeend", `<div>\
+accent for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mover>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+  </mover>\
+</math>\
+ VS \
+<math>\
+  <mover>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}" accent="${defaultValue}">${parsedKey.characters}</mo>\
+  </mover>\
+</math>\
+</div>`);
+              var div = document.body.lastElementChild;
+              var movers = div.getElementsByTagName("mover");
+              function gapBetweenBaseAndScript(mover) {
+                  return mover.children[0].getBoundingClientRect().top -
+                      mover.children[1].getBoundingClientRect().bottom;
+              }
+              var gap = gapBetweenBaseAndScript(movers[0])
+              var gapRef = gapBetweenBaseAndScript(movers[1])
+              assert_approx_equals(gap, gapRef, epsilon, `Accent property for ${key} should be '${defaultValue}'`);
+              div.style.display = "none";
+          });
+
+          counter++;
+      }
+
+      // Complete current async tests.
+      for (name in tests) {
+          if (tests[name]) tests[name].done();
+      }
+
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
--- a/testing/web-platform/tests/mathml/relations/css-styling/ignored-properties-001.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/ignored-properties-001.html
@@ -52,18 +52,16 @@
               });
 
               var referenceContainer = div.lastElementChild;
               var referenceContainerWidth = referenceContainer.getBoundingClientRect().width;
               var reference = FragmentHelper.element(referenceContainer);
               if (!FragmentHelper.isEmpty(tag))
                   FragmentHelper.forceNonEmptyDescendants(reference);
 
-              var epsilon = 1;
-
               test(function() {
                   assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
                   assert_approx_equals(elementContainerWidth, referenceContainerWidth, epsilon);
               }, `${tag} preferred width calculation is not affected by ${ignoredStyle}`);
 
               test(function() {
                   assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
                   compareLayout(element, reference, epsilon);
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant auto</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#italic-mappings">
 <link rel="match" href="mathvariant-auto-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mi> is equivalent to an <mi> with the transformed italic unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-italic.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-fraktur.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-fraktur.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant bold-fraktur</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-fraktur-mappings">
 <link rel="match" href="mathvariant-bold-fraktur-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a bold-fraktur mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-fraktur.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-italic.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-italic.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant bold-italic</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-italic-mappings">
 <link rel="match" href="mathvariant-bold-italic-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a bold-italic mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-italic.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-sans-serif.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-sans-serif.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant bold-sans-serif</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-sans-serif-mappings">
 <link rel="match" href="mathvariant-bold-sans-serif-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a bold-sans-serif mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-sans-serif.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-script.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold-script.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant bold-script</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-script-mappings">
 <link rel="match" href="mathvariant-bold-script-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a bold-script mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold-script.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-bold.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant bold</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#bold-mappings">
 <link rel="match" href="mathvariant-bold-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a bold mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-bold.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-double-struck.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-double-struck.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant double-struck</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#double-struck-mappings">
 <link rel="match" href="mathvariant-double-struck-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a double-struck mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-double-struck.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-fraktur.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-fraktur.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant fraktur</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#fraktur-mappings">
 <link rel="match" href="mathvariant-fraktur-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a fraktur mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-fraktur.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-initial.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-initial.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/>
 <title>mathvariant initial</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-mathvariant-attribute">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#initial-mappings">
 <link rel="match" href="mathvariant-initial-ref.html"/>
 <meta name="assert" content="Verify that a single-char <mtext> with a initial mathvariant is equivalent to an <mtext> with the transformed unicode character.">
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/mathvariant-initial.woff");
   }
   body > span {
--- a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-italic.html
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-italic.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8"/&g