Merge mozilla-inbound to mozilla-central. a=merge
authorDaniel Varga <dvarga@mozilla.com>
Tue, 04 Sep 2018 00:54:07 +0300
changeset 489649 d14aaf65a80b
parent 489622 42469f001fcb (current diff)
parent 489648 5a1f07f8ca7c (diff)
child 489650 17c09cfedb02
child 489679 1c08b566a5c5
push id9740
push userarchaeopteryx@coole-files.de
push dateTue, 04 Sep 2018 16:57:14 +0000
treeherdermozilla-beta@0311d9ebb702 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
d14aaf65a80b / 63.0a1 / 20180903220141 / files
nightly linux64
d14aaf65a80b / 63.0a1 / 20180903220141 / files
nightly mac
d14aaf65a80b / 63.0a1 / 20180903220141 / files
nightly win32
d14aaf65a80b / 63.0a1 / 20180903220141 / files
nightly win64
d14aaf65a80b / 63.0a1 / 20180903220141 / 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 mozilla-inbound to mozilla-central. a=merge
testing/web-platform/meta/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html.ini
testing/web-platform/meta/trusted-types/Window-trustedTypes.tentative.html.ini
testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html
testing/web-platform/tests/trusted-types/Window-trustedTypes.tentative.html
--- a/accessible/tests/browser/events/browser_test_textcaret.js
+++ b/accessible/tests/browser/events/browser_test_textcaret.js
@@ -9,38 +9,37 @@
 function caretMoveChecker(target, caretOffset) {
   return function(event) {
     let cmEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent);
     return cmEvent.accessible == getAccessible(target) && cmEvent.caretOffset == caretOffset;
   };
 }
 
 async function checkURLBarCaretEvents() {
-  let url = "about:mozilla";
+  const kURL = "about:mozilla";
+  let newWin = await BrowserTestUtils.openNewBrowserWindow();
+  newWin.gBrowser.selectedBrowser.loadURI(kURL);
 
-  let onDocLoad = waitForEvent(
+  await waitForEvent(
     EVENT_DOCUMENT_LOAD_COMPLETE,
     event => {
       try {
-        return event.accessible.QueryInterface(nsIAccessibleDocument).URL == url;
+        return event.accessible.QueryInterface(nsIAccessibleDocument).URL == kURL;
       } catch (e) {
         return false;
       }
     }
   );
-  let [ newWin ] = await Promise.all([
-    BrowserTestUtils.openNewBrowserWindow({ url }),
-    onDocLoad
-  ]);
+  info("Loaded " + kURL);
 
   let urlbarInputEl = newWin.document.getElementById("urlbar").inputField;
   let urlbarInput = getAccessible(urlbarInputEl, [ nsIAccessibleText ]);
 
   let onCaretMove = waitForEvents([
-    [ EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, url.length) ],
+    [ EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, kURL.length) ],
     [ EVENT_FOCUS, urlbarInput ]
   ]);
 
   urlbarInput.caretOffset = -1;
   await onCaretMove;
   ok(true, "Caret move in URL bar #1");
 
   onCaretMove = waitForEvent(
--- a/browser/actors/NetErrorChild.jsm
+++ b/browser/actors/NetErrorChild.jsm
@@ -119,17 +119,17 @@ class NetErrorChild extends ActorChild {
         // We only want to measure MitM rates for now. Treat it as unkown issuer.
         case MOZILLA_PKIX_ERROR_MITM_DETECTED:
         case SEC_ERROR_UNKNOWN_ISSUER:
           let brandName = gBrandBundle.GetStringFromName("brandShortName");
           if (newErrorPagesEnabled) {
             msg1 = "";
             msg1 += gPipNSSBundle.formatStringFromName("certErrorTrust_UnknownIssuer4", [hostString], 1);
             msg1 += "\n\n";
-            msg1 += gPipNSSBundle.formatStringFromName("certErrorTrust_UnknownIssuer5", [brandName, hostString], 2);
+            msg1 += gPipNSSBundle.formatStringFromName("certErrorTrust_UnknownIssuer6", [brandName, hostString], 2);
             msg1 += "\n\n";
           } else {
             msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer") + "\n";
             msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer2") + "\n";
             msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer3") + "\n";
           }
           break;
         case SEC_ERROR_CA_CERT_INVALID:
@@ -163,17 +163,17 @@ class NetErrorChild extends ActorChild {
       let subjectAltNames = input.data.certSubjectAltNames.split(",");
       let numSubjectAltNames = subjectAltNames.length;
       let msgPrefix = "";
       if (numSubjectAltNames != 0) {
         if (numSubjectAltNames == 1) {
           if (newErrorPagesEnabled) {
             technicalInfo.textContent = "";
             let brandName = gBrandBundle.GetStringFromName("brandShortName");
-            msgPrefix = gPipNSSBundle.formatStringFromName("certErrorMismatchSinglePrefix1", [brandName, hostString], 2) + " ";
+            msgPrefix = gPipNSSBundle.formatStringFromName("certErrorMismatchSinglePrefix2", [brandName, hostString], 2) + " ";
             msgPrefix += gPipNSSBundle.GetStringFromName("certErrorMismatchSinglePrefix");
           } else {
             msgPrefix = gPipNSSBundle.GetStringFromName("certErrorMismatchSinglePrefix");
           }
           // Let's check if we want to make this a link.
           let okHost = input.data.certSubjectAltNames;
           let href = "";
           let thisHost = doc.location.hostname;
@@ -237,34 +237,34 @@ class NetErrorChild extends ActorChild {
             technicalInfo.appendChild(fragment);
           }
           technicalInfo.append("\n");
         } else {
           let msg = "";
           if (newErrorPagesEnabled) {
             technicalInfo.textContent = "";
             let brandName = gBrandBundle.GetStringFromName("brandShortName");
-            msg = gPipNSSBundle.formatStringFromName("certErrorMismatchMultiple1", [brandName, hostString], 2) + " ";
+            msg = gPipNSSBundle.formatStringFromName("certErrorMismatchMultiple2", [brandName, hostString], 2) + " ";
           } else {
             msg = gPipNSSBundle.GetStringFromName("certErrorMismatchMultiple") + "\n";
           }
           for (let i = 0; i < numSubjectAltNames; i++) {
             msg += subjectAltNames[i];
             if (i != (numSubjectAltNames - 1)) {
               msg += ", ";
             }
           }
           technicalInfo.append(msg + "\n");
         }
       } else {
         let msg = "";
         if (newErrorPagesEnabled) {
           technicalInfo.textContent = "";
           let brandName = gBrandBundle.GetStringFromName("brandShortName");
-          msg = gPipNSSBundle.formatStringFromName("certErrorMismatch1", [brandName, hostString], 2) + " ";
+          msg = gPipNSSBundle.formatStringFromName("certErrorMismatch2", [brandName, hostString], 2) + " ";
         } else {
           msg = gPipNSSBundle.formatStringFromName("certErrorMismatch",
                                                      [hostString], 1);
         }
         technicalInfo.append(msg + "\n");
       }
     }
 
@@ -272,43 +272,43 @@ class NetErrorChild extends ActorChild {
       let nowTime = new Date().getTime() * 1000;
       let dateOptions = { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric" };
       let now = new Services.intl.DateTimeFormat(undefined, dateOptions).format(new Date());
       let msg = "";
       if (input.data.validity.notBefore) {
         if (nowTime > input.data.validity.notAfter) {
           if (newErrorPagesEnabled) {
             technicalInfo.textContent = "";
-            msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow1",
+            msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow2",
                                                     [hostString], 1);
             msg += "\n";
           } else {
             msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow",
                                                       [input.data.validity.notAfterLocalTime, now], 2);
             msg += "\n";
           }
         } else {
           // eslint-disable-next-line no-lonely-if
           if (newErrorPagesEnabled) {
             technicalInfo.textContent = "";
-            msg += gPipNSSBundle.formatStringFromName("certErrorNotYetValidNow1",
+            msg += gPipNSSBundle.formatStringFromName("certErrorNotYetValidNow2",
                                                       [hostString], 1);
             msg += "\n";
           } else {
             msg += gPipNSSBundle.formatStringFromName("certErrorNotYetValidNow",
                                                       [input.data.validity.notBeforeLocalTime, now], 2);
             msg += "\n";
           }
          }
         } else {
         // If something goes wrong, we assume the cert expired.
         // eslint-disable-next-line no-lonely-if
           if (newErrorPagesEnabled) {
             technicalInfo.textContent = "";
-            msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow1",
+            msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow2",
                                                       [hostString], 1);
             msg += "\n";
           } else {
             msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow",
                                                       ["", now], 2);
             msg += "\n";
           }
       }
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1459,18 +1459,18 @@ pref("media.autoplay.ask-permission", fa
 // 0 means to randomize (and persist) the experiment value in users' profiles,
 // -1 means no experiment is run and we use the preferred value for frecency (6h)
 pref("browser.cache.frecency_experiment", 0);
 
 pref("browser.translation.detectLanguage", false);
 pref("browser.translation.neverForLanguages", "");
 // Show the translation UI bits, like the info bar, notification icon and preferences.
 pref("browser.translation.ui.show", false);
-// Allows to define the translation engine. Bing is default, Yandex may optionally switched on.
-pref("browser.translation.engine", "bing");
+// Allows to define the translation engine. Google is default, Bing or Yandex are other options.
+pref("browser.translation.engine", "Google");
 
 // Telemetry settings.
 // Determines if Telemetry pings can be archived locally.
 pref("toolkit.telemetry.archive.enabled", true);
 // Enables sending the shutdown ping when Firefox shuts down.
 pref("toolkit.telemetry.shutdownPingSender.enabled", true);
 // Enables sending the shutdown ping using the pingsender from the first session.
 pref("toolkit.telemetry.shutdownPingSender.enabledFirstSession", false);
--- a/browser/base/content/browser-captivePortal.js
+++ b/browser/base/content/browser-captivePortal.js
@@ -108,16 +108,22 @@ var CaptivePortalWatcher = {
   },
 
   _captivePortalDetected() {
     if (this._delayedCaptivePortalDetectedInProgress) {
       return;
     }
 
     let win = BrowserWindowTracker.getTopWindow();
+    // Used by tests: ignore the main test window in order to enable testing of
+    // the case where we have no open windows.
+    if (win && win.document.documentElement.getAttribute("ignorecaptiveportal")) {
+      win = null;
+    }
+
     // If no browser window has focus, open and show the tab when we regain focus.
     // This is so that if a different application was focused, when the user
     // (re-)focuses a browser window, we open the tab immediately in that window
     // so they can log in before continuing to browse.
     if (win != Services.ww.activeWindow) {
       this._delayedCaptivePortalDetectedInProgress = true;
       Services.obs.addObserver(this, "xul-window-visible");
     }
@@ -131,16 +137,22 @@ var CaptivePortalWatcher = {
    * the tab if needed after a short delay to allow the recheck to complete.
    */
   _delayedCaptivePortalDetected() {
     if (!this._delayedCaptivePortalDetectedInProgress) {
       return;
     }
 
     let win = BrowserWindowTracker.getTopWindow();
+    // Used by tests: ignore the main test window in order to enable testing of
+    // the case where we have no open windows.
+    if (win && win.document.documentElement.getAttribute("ignorecaptiveportal")) {
+      win = null;
+    }
+
     if (win != Services.ww.activeWindow) {
       // The window that got focused was not a browser window.
       return;
     }
     Services.obs.removeObserver(this, "xul-window-visible");
     this._delayedCaptivePortalDetectedInProgress = false;
 
     if (win != window) {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4287,16 +4287,29 @@ function toOpenWindowByType(inType, uri,
   if (topWindow)
     topWindow.focus();
   else if (features)
     window.open(uri, "_blank", features);
   else
     window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
 }
 
+/**
+ * Open a new browser window.
+ *
+ * @param {Object} options
+ *        {
+ *          private: A boolean indicating if the window should be
+ *                   private
+ *          remote:  A boolean indicating if the window should run
+ *                   remote browser tabs or not. If omitted, the window
+ *                   will choose the profile default state.
+ *        }
+ * @return a reference to the new window.
+ */
 function OpenBrowserWindow(options) {
   var telemetryObj = {};
   TelemetryStopwatch.start("FX_NEW_WINDOW_MS", telemetryObj);
 
   var handler = Cc["@mozilla.org/browser/clh;1"]
                   .getService(Ci.nsIBrowserHandler);
   var defaultArgs = handler.defaultArgs;
   var wintype = document.documentElement.getAttribute("windowtype");
--- a/browser/base/content/test/captivePortal/head.js
+++ b/browser/base/content/test/captivePortal/head.js
@@ -15,32 +15,23 @@ const PORTAL_NOTIFICATION_VALUE = "capti
 async function setupPrefsAndRecentWindowBehavior() {
   await SpecialPowers.pushPrefEnv({
     set: [["captivedetect.canonicalURL", CANONICAL_URL],
           ["captivedetect.canonicalContent", CANONICAL_CONTENT]],
   });
   // We need to test behavior when a portal is detected when there is no browser
   // window, but we can't close the default window opened by the test harness.
   // Instead, we deactivate CaptivePortalWatcher in the default window and
-  // exclude it from BrowserWindowTracker.getTopWindow in an attempt to
-  // mask its presence.
+  // exclude it using an attribute to mask its presence.
   window.CaptivePortalWatcher.uninit();
-  let getTopWindowCopy = BrowserWindowTracker.getTopWindow;
-  let defaultWindow = window;
-  BrowserWindowTracker.getTopWindow = () => {
-    let win = getTopWindowCopy();
-    if (win == defaultWindow) {
-      return null;
-    }
-    return win;
-  };
+  window.document.documentElement.setAttribute("ignorecaptiveportal", "true");
 
   registerCleanupFunction(function cleanUp() {
-    BrowserWindowTracker.getTopWindow = getTopWindowCopy;
     window.CaptivePortalWatcher.init();
+    window.document.documentElement.removeAttribute("ignorecaptiveportal");
   });
 }
 
 async function portalDetected() {
   Services.obs.notifyObservers(null, "captive-portal-login");
   await BrowserTestUtils.waitForCondition(() => {
     return cps.state == cps.LOCKED_PORTAL;
   }, "Waiting for Captive Portal Service to update state after portal detected.");
--- a/browser/base/content/test/forms/browser_selectpopup.js
+++ b/browser/base/content/test/forms/browser_selectpopup.js
@@ -585,28 +585,34 @@ add_task(async function test_large_popup
 
   await performLargePopupTests(window);
 
   BrowserTestUtils.removeTab(tab);
 });
 
 // This test checks the same as the previous test but in a new smaller window.
 add_task(async function test_large_popup_in_small_window() {
-  let newwin = await BrowserTestUtils.openNewBrowserWindow({ width: 400, height: 400 });
+  let newWin = await BrowserTestUtils.openNewBrowserWindow();
+
+  let resizePromise = BrowserTestUtils.waitForEvent(newWin, "resize", false, e => {
+    return newWin.innerHeight <= 400 && newWin.innerWidth <= 400;
+  });
+  newWin.resizeTo(400, 400);
+  await resizePromise;
 
   const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
-  let browserLoadedPromise = BrowserTestUtils.browserLoaded(newwin.gBrowser.selectedBrowser);
-  await BrowserTestUtils.loadURI(newwin.gBrowser.selectedBrowser, pageUrl);
+  let browserLoadedPromise = BrowserTestUtils.browserLoaded(newWin.gBrowser.selectedBrowser);
+  await BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, pageUrl);
   await browserLoadedPromise;
 
-  newwin.gBrowser.selectedBrowser.focus();
+  newWin.gBrowser.selectedBrowser.focus();
 
-  await performLargePopupTests(newwin);
+  await performLargePopupTests(newWin);
 
-  await BrowserTestUtils.closeWindow(newwin);
+  await BrowserTestUtils.closeWindow(newWin);
 });
 
 async function performSelectSearchTests(win) {
   let browser = win.gBrowser.selectedBrowser;
   await ContentTask.spawn(browser, null, async function() {
     let doc = content.document;
     let select = doc.getElementById("one");
 
--- a/browser/base/content/test/plugins/browser_private_clicktoplay.js
+++ b/browser/base/content/test/plugins/browser_private_clicktoplay.js
@@ -21,17 +21,18 @@ function finishTest() {
 }
 
 let createPrivateWindow = async function createPrivateWindow(url) {
   gPrivateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
   ok(!!gPrivateWindow, "should have created a private window.");
   gPrivateBrowser = gPrivateWindow.getBrowser().selectedBrowser;
 
   BrowserTestUtils.loadURI(gPrivateBrowser, url);
-  await BrowserTestUtils.browserLoaded(gPrivateBrowser);
+  await BrowserTestUtils.browserLoaded(gPrivateBrowser, false, url);
+  info("loaded " + url);
 };
 
 add_task(async function test() {
   registerCleanupFunction(function() {
     clearAllPluginPermissions();
     getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
     getTestPlugin("Second Test Plug-in").enabledState = Ci.nsIPluginTag.STATE_ENABLED;
   });
--- a/browser/base/content/test/sidebar/browser_sidebar_adopt.js
+++ b/browser/base/content/test/sidebar/browser_sidebar_adopt.js
@@ -14,21 +14,21 @@ function failIfSidebarFocusedFires() {
 }
 
 add_task(async function testAdoptedTwoWindows() {
   // First open a new window, show the sidebar in that window, and close it.
   // Then, open another new window and confirm that the sidebar is closed since it is
   // being adopted from the main window which doesn't have a shown sidebar. See Bug 1407737.
   info("Ensure that sidebar state is adopted only from the opener");
 
-  let win1 = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let win1 = await BrowserTestUtils.openNewBrowserWindow();
   await win1.SidebarUI.show("viewBookmarksSidebar");
   await BrowserTestUtils.closeWindow(win1);
 
-  let win2 = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let win2 = await BrowserTestUtils.openNewBrowserWindow();
   ok(!win2.document.getElementById("sidebar-button").hasAttribute("checked"), "Sidebar button isn't checked");
   ok(!win2.SidebarUI.isOpen, "Sidebar is closed");
   await BrowserTestUtils.closeWindow(win2);
 });
 
 add_task(async function testEventsReceivedInMainWindow() {
   info("Opening the sidebar and expecting both SidebarShown and SidebarFocused events");
 
@@ -41,17 +41,17 @@ add_task(async function testEventsReceiv
 
   ok(true, "SidebarShown and SidebarFocused events fired on a new window");
 });
 
 add_task(async function testEventReceivedInNewWindow() {
   info("Opening a new window and expecting the SidebarFocused event to not fire");
 
   let promiseNewWindow = BrowserTestUtils.waitForNewWindow();
-  BrowserTestUtils.openNewBrowserWindow({opener: window});
+  BrowserTestUtils.openNewBrowserWindow();
   let win = await promiseNewWindow;
 
   let adoptedShown = BrowserTestUtils.waitForEvent(win, "SidebarShown");
   win.addEventListener("SidebarFocused", failIfSidebarFocusedFires);
 
   registerCleanupFunction(async function() {
     win.removeEventListener("SidebarFocused", failIfSidebarFocusedFires);
     await BrowserTestUtils.closeWindow(win);
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -113,16 +113,21 @@ var whitelist = [
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/win/intl.properties",
    platforms: ["linux", "macosx"]},
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/win/platformKeys.properties",
    platforms: ["linux", "macosx"]},
 
   // browser/extensions/pdfjs/content/web/viewer.js#7450
   {file: "resource://pdf.js/web/debugger.js"},
 
+  // resource://app/modules/translation/TranslationContentHandler.jsm
+  {file: "resource://app/modules/translation/BingTranslator.jsm"},
+  {file: "resource://app/modules/translation/GoogleTranslator.jsm"},
+  {file: "resource://app/modules/translation/YandexTranslator.jsm"},
+
   // Starting from here, files in the whitelist are bugs that need fixing.
   // Bug 1339424 (wontfix?)
   {file: "chrome://browser/locale/taskbar.properties",
    platforms: ["linux", "macosx"]},
   // Bug 1356031 (only used by devtools)
   {file: "chrome://global/skin/icons/error-16.png"},
   // Bug 1348362
   {file: "chrome://global/skin/icons/warning-64.png", platforms: ["linux"]},
--- a/browser/components/customizableui/test/browser_editcontrols_update.js
+++ b/browser/components/customizableui/test/browser_editcontrols_update.js
@@ -197,16 +197,21 @@ add_task(async function finish() {
 
 // Test updating in the initial state when the edit-controls are on the panel but
 // have not yet been created. This needs to be done in a new window to ensure that
 // other tests haven't opened the panel.
 add_task(async function test_initial_state() {
   let testWindow = await BrowserTestUtils.openNewBrowserWindow();
   await SimpleTest.promiseFocus(testWindow);
 
+  // For focusing the URL bar to have an effect, we need to ensure the URL bar isn't
+  // initially focused:
+  testWindow.gBrowser.selectedTab.focus();
+  await TestUtils.waitForCondition(() => !testWindow.gURLBar.focused);
+
   let overridePromise = expectCommandUpdate(isMac, testWindow);
 
   testWindow.gURLBar.focus();
   testWindow.gURLBar.value = "test";
 
   await overridePromise;
 
   // Commands won't update when no edit UI is present. They default to being
--- a/browser/components/customizableui/test/browser_sidebar_toggle.js
+++ b/browser/components/customizableui/test/browser_sidebar_toggle.js
@@ -37,15 +37,15 @@ add_task(async function() {
   is(SidebarUI.currentID, "viewBookmarksSidebar", "Default sidebar selected");
   await SidebarUI.show("viewHistorySidebar");
 
   await hideSidebar();
   await showSidebar();
   is(SidebarUI.currentID, "viewHistorySidebar", "Selected sidebar remembered");
 
   await hideSidebar();
-  let otherWin = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let otherWin = await BrowserTestUtils.openNewBrowserWindow();
   await showSidebar(otherWin);
   is(otherWin.SidebarUI.currentID, "viewHistorySidebar", "Selected sidebar remembered across windows");
   await hideSidebar(otherWin);
 
   await BrowserTestUtils.closeWindow(otherWin);
 });
--- a/browser/components/extensions/test/browser/browser_ext_sidebarAction_windows.js
+++ b/browser/components/extensions/test/browser/browser_ext_sidebarAction_windows.js
@@ -43,17 +43,17 @@ add_task(async function sidebar_windows(
   ok(elements.length > 0, "have a menuitem");
   let style = elements[0].getAttribute("style");
   ok(style.includes("webextension-menuitem-image"), "this menu has style");
 
   let secondSidebar = extension.awaitMessage("sidebar");
 
   // SidebarUI relies on window.opener being set, which is normal behavior when
   // using menu or key commands to open a new browser window.
-  let win = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let win = await BrowserTestUtils.openNewBrowserWindow();
 
   await secondSidebar;
   ok(!win.document.getElementById("sidebar-box").hidden, "sidebar box is visible in second window");
   // Check that the menuitem has our image styling.
   elements = win.document.getElementsByClassName("webextension-menuitem");
   ok(elements.length > 0, "have a menuitem");
   style = elements[0].getAttribute("style");
   ok(style.includes("webextension-menuitem-image"), "this menu has style");
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -423,17 +423,17 @@ var gMainPane = {
 
     // Show translation preferences if we may:
     const prefName = "browser.translation.ui.show";
     if (Services.prefs.getBoolPref(prefName)) {
       let row = document.getElementById("translationBox");
       row.removeAttribute("hidden");
       // Showing attribution only for Bing Translator.
       ChromeUtils.import("resource:///modules/translation/Translation.jsm");
-      if (Translation.translationEngine == "bing") {
+      if (Translation.translationEngine == "Bing") {
         document.getElementById("bingAttribution").removeAttribute("hidden");
       }
     }
 
     if (AppConstants.MOZ_DEV_EDITION) {
       let uAppData = OS.Constants.Path.userApplicationDataDir;
       let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
 
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -199,22 +199,23 @@ var gPrivacyPane = {
     let isLocked = TRACKING_PROTECTION_PREFS.some(
       pref => Services.prefs.prefIsLocked(pref));
 
     function setInputsDisabledState(isControlled) {
       let disabled = isLocked || isControlled;
       if (contentBlockingUiEnabled) {
         let tpCheckbox =
           document.getElementById("contentBlockingTrackingProtectionCheckbox");
-        if (!tpCheckbox.checked) {
-          disabled = true;
-        }
-        // Only enable the TP menu if content blocking is enabled.
+        // Only enable the TP menu if content blocking and Detect All Trackers
+        // are enabled.
         document.getElementById("trackingProtectionMenu").disabled = disabled ||
+          !tpCheckbox.checked ||
           !contentBlockingEnabled;
+        // Only enable the TP category checkbox if content blocking is enabled.
+        tpCheckbox.disabled = disabled || !contentBlockingEnabled;
       } else {
         document.querySelectorAll("#trackingProtectionRadioGroup > radio")
           .forEach((element) => {
             element.disabled = disabled;
           });
         document.querySelector("#trackingProtectionDesc > label")
           .disabled = disabled;
       }
@@ -524,20 +525,25 @@ var gPrivacyPane = {
     }
 
     // Reorder the privacy pane to put the Content Blocking section first and the
     // Cookies & Site Data section right after it.
     let trackingGroup = document.getElementById("trackingGroup");
     let siteDataGroup = document.getElementById("siteDataGroup");
     let browserPrivacyCategory = document.getElementById("browserPrivacyCategory");
 
-    browserPrivacyCategory.parentNode.insertBefore(siteDataGroup,
-                                                   browserPrivacyCategory.nextSibling);
-    browserPrivacyCategory.parentNode.insertBefore(trackingGroup,
-                                                   browserPrivacyCategory.nextSibling);
+    // If we do this without a timeout, trackingProtectionReadPrefs will set the checked
+    // attribute on our checkbox element before the XBL binding has had a chance to have
+    // been re-applied to it.
+    setTimeout(() => {
+      browserPrivacyCategory.parentNode.insertBefore(siteDataGroup,
+                                                     browserPrivacyCategory.nextSibling);
+      browserPrivacyCategory.parentNode.insertBefore(trackingGroup,
+                                                     browserPrivacyCategory.nextSibling);
+    }, 0);
   },
 
   /**
    * Resets all user-exposed content blocking preferences to their default values.
    */
   async restoreContentBlockingPrefs() {
     function clearIfNotLocked(pref) {
       if (!Services.prefs.prefIsLocked(pref)) {
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -374,17 +374,20 @@
                         aria-labelledby="trackingProtectionMenuDesc">
               <radio value="private"
                      data-l10n-id="content-blocking-tracking-protection-option-private"
                      flex="1" />
               <radio value="always"
                      data-l10n-id="content-blocking-tracking-protection-option-always"
                      flex="1" />
             </radiogroup>
-            <label id="changeBlockListLink" data-l10n-id="content-blocking-tracking-protection-change-block-list" class="text-link"/>
+            <label id="changeBlockListLink"
+                   data-l10n-id="content-blocking-tracking-protection-change-block-list"
+                   class="text-link"
+                   search-l10n-ids="blocklist-window.title, blocklist-desc, blocklist-button-cancel.label, blocklist-button-ok.label"/>
           </vbox>
         </hbox>
       </vbox>
       <hbox class="content-blocking-category reject-trackers-ui">
         <hbox flex="1">
           <vbox class="content-blocking-category-checkbox">
             <checkbox id="contentBlockingBlockCookiesCheckbox" class="content-blocking-checkbox" />
           </vbox>
--- a/browser/components/preferences/in-content/tests/browser_contentblocking.js
+++ b/browser/components/preferences/in-content/tests/browser_contentblocking.js
@@ -51,16 +51,77 @@ add_task(async function testContentBlock
   is(Services.prefs.getBoolPref(CB_PREF), false, "Content Blocking is off");
   ok(!contentBlockingCheckbox.checked, "Checkbox is not checked when CB is off");
   is(contentBlockingToggle.getAttribute("aria-pressed"), "false", "toggle button has correct aria attribute");
 
   Services.prefs.clearUserPref(CB_PREF);
   gBrowser.removeCurrentTab();
 });
 
+// Tests that the content blocking main category checkboxes have the correct default state.
+add_task(async function testContentBlockingMainCategory() {
+  SpecialPowers.pushPrefEnv({set: [
+    [CB_UI_PREF, true],
+    [CB_PREF, true],
+    [FB_PREF, true],
+    [TP_PREF, false],
+    [TP_PBM_PREF, true],
+    [NCB_PREF, Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
+  ]});
+
+  let checkboxes = [
+    "#contentBlockingFastBlockCheckbox",
+    "#contentBlockingTrackingProtectionCheckbox",
+    "#contentBlockingBlockCookiesCheckbox",
+  ];
+
+  await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
+  let doc = gBrowser.contentDocument;
+
+  for (let selector of checkboxes) {
+    let element = doc.querySelector(selector);
+    ok(element, "checkbox " + selector + " exists");
+    is(element.getAttribute("checked"), "true",
+       "checkbox " + selector + " is checked");
+  }
+
+  // Ensure the dependent controls of the tracking protection subsection behave properly.
+  let tpCheckbox = doc.querySelector(checkboxes[1]);
+
+  let dependentControls = [
+    "#trackingProtectionMenu",
+  ];
+  let alwaysEnabledControls = [
+    "#trackingProtectionMenuDesc",
+    ".content-blocking-category-name",
+    "#changeBlockListLink",
+  ];
+
+  tpCheckbox.checked = true;
+
+  // The first time, privacy-pane-tp-ui-updated won't be dispatched since the
+  // assignment above is a no-op.
+
+  // Ensure the dependent controls are enabled
+  checkControlStateWorker(doc, dependentControls, true);
+  checkControlStateWorker(doc, alwaysEnabledControls, true);
+
+  let promise = TestUtils.topicObserved("privacy-pane-tp-ui-updated");
+  EventUtils.synthesizeMouseAtCenter(tpCheckbox, {}, doc.defaultView);
+
+  await promise;
+  ok(!tpCheckbox.checked, "The checkbox should now be unchecked");
+
+  // Ensure the dependent controls are disabled
+  checkControlStateWorker(doc, dependentControls, false);
+  checkControlStateWorker(doc, alwaysEnabledControls, true);
+
+  gBrowser.removeCurrentTab();
+});
+
 // Tests that the content blocking "Restore Defaults" button does what it's supposed to.
 add_task(async function testContentBlockingRestoreDefaults() {
   SpecialPowers.pushPrefEnv({set: [
     [CB_UI_PREF, true],
   ]});
 
   let prefs = [
     CB_PREF,
@@ -135,16 +196,34 @@ add_task(async function testContentBlock
   for (let pref of resettable) {
     ok(Services.prefs.prefHasUserValue(pref), `modified the pref ${pref}`);
   }
 
   await extension.startup();
 
   await TestUtils.waitForCondition(() => Services.prefs.prefHasUserValue(TP_PREF));
 
+  let dependentControls = [
+    "#content-blocking-categories-label",
+    ".fast-block-ui .content-blocking-checkbox",
+    ".reject-trackers-ui .content-blocking-checkbox",
+    ".content-blocking-icon",
+    ".content-blocking-category-name",
+    "#changeBlockListLink",
+    "#contentBlockingChangeCookieSettings",
+    "#blockCookiesCB, #blockCookiesCB > radio",
+  ];
+  let alwaysDisabledControls = [
+    ".tracking-protection-ui .content-blocking-checkbox",
+    "#trackingProtectionMenu",
+    "[control=trackingProtectionMenu]",
+  ];
+
+  await doDependentControlChecks(dependentControls, alwaysDisabledControls);
+
   await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
   let doc = gBrowser.contentDocument;
 
   let contentBlockingRestoreDefaults = doc.getElementById("contentBlockingRestoreDefaults");
   contentBlockingRestoreDefaults.click();
 
   for (let pref of resettable) {
     ok(!Services.prefs.prefHasUserValue(pref), `reset the pref ${pref}`);
@@ -276,26 +355,23 @@ add_task(async function testContentBlock
     [CB_RT_UI_PREF, true],
     [TP_PREF, false],
     [TP_PBM_PREF, false],
     [NCB_PREF, Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
   ]});
 
   let dependentControls = [
     "#content-blocking-categories-label",
-    ".content-blocking-checkbox",
-    ".content-blocking-icon",
-    ".content-blocking-category-name",
+    "[control=trackingProtectionMenu]",
     "#changeBlockListLink",
     "#contentBlockingChangeCookieSettings",
     "#blockCookiesCB, #blockCookiesCB > radio",
   ];
   let alwaysDisabledControls = [
     "#trackingProtectionMenu",
-    "[control=trackingProtectionMenu]",
   ];
 
   await doDependentControlChecks(dependentControls, alwaysDisabledControls);
 });
 
 
 // Checks that the granular controls are disabled or enabled depending on the master pref for CB
 // when the Cookies and Site Data section is set to block either "All Cookies" or "Cookies from
--- a/browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_6.js
+++ b/browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_6.js
@@ -8,19 +8,31 @@ add_task(async function() {
     ["browser.preferences.search", true],
   ]});
 });
 
 /**
  * Test for searching for the "Block Lists" subdialog.
  */
 add_task(async function() {
-  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
-  await evaluateSearchResults("block Web elements", "trackingGroup");
-  BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  async function doTest() {
+    await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+    await evaluateSearchResults("block Web elements", "trackingGroup");
+    BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  }
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["browser.contentblocking.ui.enabled", true],
+  ]});
+  info("Run the test with Content Blocking UI enabled");
+  await doTest();
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["browser.contentblocking.ui.enabled", false],
+  ]});
+  info("Run the test with Content Blocking UI disabled");
+  await doTest();
 });
 
 /**
  * Test for searching for the "Allowed Sites - Pop-ups" subdialog.
  */
 add_task(async function() {
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   await evaluateSearchResults("open pop-up windows", "permissionsGroup");
--- a/browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_site_data.js
+++ b/browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_site_data.js
@@ -2,16 +2,21 @@
 * This file contains tests for the Preferences search bar.
 */
 
 // Enabling Searching functionatily. Will display search bar form this testcase forward.
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({"set": [["browser.preferences.search", true]]});
 });
 
+// First, run the tests without the Content Blocking UI.
+add_task(async function() {
+  await SpecialPowers.pushPrefEnv({"set": [["browser.contentblocking.ui.enabled", false]]});
+});
+
 /**
  * Test for searching for the "Settings - Site Data" subdialog.
  */
 add_task(async function() {
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   await evaluateSearchResults("cookies", ["siteDataGroup"]);
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
@@ -28,8 +33,40 @@ add_task(async function() {
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function() {
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   await evaluateSearchResults("third-party", "siteDataGroup");
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
+
+// Now, run the tests with the Content Blocking UI.
+add_task(async function() {
+  await SpecialPowers.pushPrefEnv({"set": [["browser.contentblocking.ui.enabled", true]]});
+});
+
+/**
+ * Test for searching for the "Settings - Site Data" subdialog.
+ */
+add_task(async function() {
+  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  await evaluateSearchResults("cookies", ["siteDataGroup", "trackingGroup"]);
+  BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(async function() {
+  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  await evaluateSearchResults("site data", ["siteDataGroup"]);
+  BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(async function() {
+  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  await evaluateSearchResults("cache", ["siteDataGroup"]);
+  BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(async function() {
+  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  await evaluateSearchResults("third-party", ["siteDataGroup", "trackingGroup"]);
+  BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
@@ -5,20 +5,21 @@
 const TP_PB_ENABLED_PREF = "privacy.trackingprotection.pbmode.enabled";
 const CB_ENABLED_PREF = "browser.contentblocking.enabled";
 const CB_UI_ENABLED_PREF = "browser.contentblocking.ui.enabled";
 
 /**
  * Opens a new private window and loads "about:privatebrowsing" there.
  */
 async function openAboutPrivateBrowsing() {
-  let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
+  let win = await BrowserTestUtils.openNewBrowserWindow({
+    private: true,
+    waitForTabURL: "about:privatebrowsing",
+  });
   let tab = win.gBrowser.selectedBrowser;
-  tab.loadURI("about:privatebrowsing");
-  await BrowserTestUtils.browserLoaded(tab);
   return { win, tab };
 }
 
 /**
  * Clicks the given link and checks this opens a new tab with the given URI.
  */
 async function testLinkOpensTab({ win, tab, elementId, expectedUrl }) {
   let newTabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, expectedUrl);
--- a/browser/components/sessionstore/test/browser_394759_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_394759_perwindowpb.js
@@ -12,18 +12,17 @@ const TESTS = [
     key: "bug 394759 PB",
     value: "uniq" + r() },
 ];
 
 function promiseTestOpenCloseWindow(aIsPrivate, aTest) {
   return (async function() {
     let win = await BrowserTestUtils.openNewBrowserWindow({ "private": aIsPrivate });
     win.gBrowser.selectedBrowser.loadURI(aTest.url);
-    await promiseBrowserLoaded(win.gBrowser.selectedBrowser);
-    await Promise.resolve();
+    await promiseBrowserLoaded(win.gBrowser.selectedBrowser, true, aTest.url);
     // Mark the window with some unique data to be restored later on.
     ss.setWindowValue(win, aTest.key, aTest.value);
     await TabStateFlusher.flushWindow(win);
     // Close.
     await BrowserTestUtils.closeWindow(win);
   })();
 }
 
copy from browser/components/translation/BingTranslator.jsm
copy to browser/components/translation/GoogleTranslator.jsm
--- a/browser/components/translation/BingTranslator.jsm
+++ b/browser/components/translation/GoogleTranslator.jsm
@@ -1,149 +1,128 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-var EXPORTED_SYMBOLS = [ "BingTranslator" ];
+var EXPORTED_SYMBOLS = [ "GoogleTranslator" ];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
-ChromeUtils.import("resource://services-common/async.js");
 ChromeUtils.import("resource://gre/modules/Http.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
+XPCOMUtils.defineLazyGlobalGetters(this, ["DOMParser"]);
 
-// The maximum amount of net data allowed per request on Bing's API.
-const MAX_REQUEST_DATA = 5000; // Documentation says 10000 but anywhere
-                               // close to that is refused by the service.
+// The maximum amount of net data allowed per request on Google's API.
+const MAX_REQUEST_DATA = 5000; // XXX This is the Bing value
 
 // The maximum number of chunks allowed to be translated in a single
 // request.
-const MAX_REQUEST_CHUNKS = 1000; // Documentation says 2000.
+const MAX_REQUEST_CHUNKS = 128; // Undocumented, but the de facto upper limit.
 
 // Self-imposed limit of 15 requests. This means that a page that would need
 // to be broken in more than 15 requests won't be fully translated.
 // The maximum amount of data that we will translate for a single page
 // is MAX_REQUESTS * MAX_REQUEST_DATA.
 const MAX_REQUESTS = 15;
 
+const URL = "https://translation.googleapis.com/language/translate/v2";
+
 /**
- * Translates a webpage using Bing's Translation API.
+ * Translates a webpage using Google's Translation API.
  *
  * @param translationDocument  The TranslationDocument object that represents
  *                             the webpage to be translated
  * @param sourceLanguage       The source language of the document
  * @param targetLanguage       The target language for the translation
  *
  * @returns {Promise}          A promise that will resolve when the translation
  *                             task is finished.
  */
-var BingTranslator = function(translationDocument, sourceLanguage, targetLanguage) {
+var GoogleTranslator = function(translationDocument, sourceLanguage, targetLanguage) {
   this.translationDocument = translationDocument;
   this.sourceLanguage = sourceLanguage;
   this.targetLanguage = targetLanguage;
   this._pendingRequests = 0;
   this._partialSuccess = false;
-  this._serviceUnavailable = false;
   this._translatedCharacterCount = 0;
 };
 
-this.BingTranslator.prototype = {
+this.GoogleTranslator.prototype = {
   /**
    * Performs the translation, splitting the document into several chunks
    * respecting the data limits of the API.
    *
    * @returns {Promise}          A promise that will resolve when the translation
    *                             task is finished.
    */
-  translate() {
-    return (async () => {
-      let currentIndex = 0;
-      this._onFinishedDeferred = PromiseUtils.defer();
+  async translate() {
+    let currentIndex = 0;
+    this._onFinishedDeferred = PromiseUtils.defer();
 
-      // Let's split the document into various requests to be sent to
-      // Bing's Translation API.
-      for (let requestCount = 0; requestCount < MAX_REQUESTS; requestCount++) {
-        // Generating the text for each request can be expensive, so
-        // let's take the opportunity of the chunkification process to
-        // allow for the event loop to attend other pending events
-        // before we continue.
-        await Async.promiseYield();
+    // Let's split the document into various requests to be sent to
+    // Google's Translation API.
+    for (let requestCount = 0; requestCount < MAX_REQUESTS; requestCount++) {
+      // Generating the text for each request can be expensive, so
+      // let's take the opportunity of the chunkification process to
+      // allow for the event loop to attend other pending events
+      // before we continue.
+      await new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
 
-        // Determine the data for the next request.
-        let request = this._generateNextTranslationRequest(currentIndex);
+      // Determine the data for the next request.
+      let request = this._generateNextTranslationRequest(currentIndex);
 
-        // Create a real request to the server, and put it on the
-        // pending requests list.
-        let bingRequest = new BingRequest(request.data,
-                                          this.sourceLanguage,
-                                          this.targetLanguage);
-        this._pendingRequests++;
-        bingRequest.fireRequest().then(this._chunkCompleted.bind(this),
+      // Create a real request to the server, and put it on the
+      // pending requests list.
+      let googleRequest = new GoogleRequest(request.data,
+                                            this.sourceLanguage,
+                                            this.targetLanguage);
+      this._pendingRequests++;
+      googleRequest.fireRequest().then(this._chunkCompleted.bind(this),
                                        this._chunkFailed.bind(this));
 
-        currentIndex = request.lastIndex;
-        if (request.finished) {
-          break;
-        }
+      currentIndex = request.lastIndex;
+      if (request.finished) {
+        break;
       }
+    }
 
-      return this._onFinishedDeferred.promise;
-    })();
-  },
-
-  /**
-   * Resets the expiration time of the current token, in order to
-   * force the token manager to ask for a new token during the next request.
-   */
-  _resetToken() {
-    // Force the token manager to get update token
-    BingTokenManager._currentExpiryTime = 0;
+    return this._onFinishedDeferred.promise;
   },
 
   /**
    * Function called when a request sent to the server completed successfully.
    * This function handles calling the function to parse the result and the
    * function to resolve the promise returned by the public `translate()`
    * method when there's no pending request left.
    *
-   * @param   request   The BingRequest sent to the server.
+   * @param   request   The GoogleRequest sent to the server.
    */
-  _chunkCompleted(bingRequest) {
-    if (this._parseChunkResult(bingRequest)) {
+  _chunkCompleted(googleRequest) {
+    if (this._parseChunkResult(googleRequest)) {
       this._partialSuccess = true;
       // Count the number of characters successfully translated.
-      this._translatedCharacterCount += bingRequest.characterCount;
+      this._translatedCharacterCount += googleRequest.characterCount;
     }
 
     this._checkIfFinished();
   },
 
   /**
    * Function called when a request sent to the server has failed.
    * This function handles deciding if the error is transient or means the
    * service is unavailable (zero balance on the key or request credentials are
    * not in an active state) and calling the function to resolve the promise
    * returned by the public `translate()` method when there's no pending.
    * request left.
    *
    * @param   aError   [optional] The XHR object of the request that failed.
    */
   _chunkFailed(aError) {
-    if (aError instanceof XMLHttpRequest &&
-        [400, 401].includes(aError.status)) {
-      let body = aError.responseText;
-      if (body && body.includes("TranslateApiException") &&
-          (body.includes("balance") || body.includes("active state")))
-        this._serviceUnavailable = true;
-    }
-
     this._checkIfFinished();
   },
 
   /**
    * Function called when a request sent to the server has completed.
    * This function handles resolving the promise
    * returned by the public `translate()` method when all chunks are completed.
    */
@@ -155,61 +134,58 @@ this.BingTranslator.prototype = {
     // display the "Success" state for the infobar. Otherwise,
     // the "Error" state will appear.
     if (--this._pendingRequests == 0) {
       if (this._partialSuccess) {
         this._onFinishedDeferred.resolve({
           characterCount: this._translatedCharacterCount,
         });
       } else {
-        let error = this._serviceUnavailable ? "unavailable" : "failure";
-        this._onFinishedDeferred.reject(error);
+        this._onFinishedDeferred.reject("failure");
       }
     }
   },
 
   /**
    * This function parses the result returned by Bing's Http.svc API,
    * which is a XML file that contains a number of elements. To our
    * particular interest, the only part of the response that matters
    * are the <TranslatedText> nodes, which contains the resulting
    * items that were sent to be translated.
    *
    * @param   request      The request sent to the server.
    * @returns boolean      True if parsing of this chunk was successful.
    */
-  _parseChunkResult(bingRequest) {
+  _parseChunkResult(googleRequest) {
     let results;
     try {
-      let doc = bingRequest.networkRequest.responseXML;
-      results = doc.querySelectorAll("TranslatedText");
+      let response = googleRequest.networkRequest.response;
+      results = JSON.parse(response).data.translations;
     } catch (e) {
       return false;
     }
-
     let len = results.length;
-    if (len != bingRequest.translationData.length) {
+    if (len != googleRequest.translationData.length) {
       // This should never happen, but if the service returns a different number
       // of items (from the number of items submitted), we can't use this chunk
       // because all items would be paired incorrectly.
       return false;
     }
 
     let error = false;
     for (let i = 0; i < len; i++) {
       try {
-        let result = results[i].firstChild.nodeValue;
-        let root = bingRequest.translationData[i][0];
-
-        if (root.isSimpleRoot) {
-          // Workaround for Bing's service problem in which "&" chars in
-          // plain-text TranslationItems are double-escaped.
-          result = result.replace(/&amp;/g, "&");
+        let result = results[i].translatedText;
+        let root = googleRequest.translationData[i][0];
+        if (root.isSimpleRoot && result.includes("&")) {
+          // If the result contains HTML entities, we need to convert them as
+          // simple roots expect a plain text result.
+          let doc = (new DOMParser()).parseFromString(result, "text/html");
+          result = doc.body.firstChild.nodeValue;
         }
-
         root.parseResult(result);
       } catch (e) { error = true; }
     }
 
     return !error;
   },
 
   /**
@@ -227,17 +203,16 @@ this.BingTranslator.prototype = {
 
     for (let i = startIndex; i < rootsList.length; i++) {
       let root = rootsList[i];
       let text = this.translationDocument.generateTextForItem(root);
       if (!text) {
         continue;
       }
 
-      text = escapeXML(text);
       let newCurSize = currentDataSize + text.length;
       let newChunks = currentChunks + 1;
 
       if (newCurSize > MAX_REQUEST_DATA ||
           newChunks > MAX_REQUEST_CHUNKS) {
 
         // If we've reached the API limits, let's stop accumulating data
         // for this request and return. We return information useful for
@@ -259,189 +234,64 @@ this.BingTranslator.prototype = {
       data: output,
       finished: true,
       lastIndex: 0,
     };
   },
 };
 
 /**
- * Represents a request (for 1 chunk) sent off to Bing's service.
+ * Represents a request (for 1 chunk) sent off to Google's service.
  *
  * @params translationData  The data to be used for this translation,
  *                          generated by the generateNextTranslationRequest...
  *                          function.
  * @param sourceLanguage    The source language of the document.
  * @param targetLanguage    The target language for the translation.
  *
  */
-function BingRequest(translationData, sourceLanguage, targetLanguage) {
+function GoogleRequest(translationData, sourceLanguage, targetLanguage) {
   this.translationData = translationData;
   this.sourceLanguage = sourceLanguage;
   this.targetLanguage = targetLanguage;
   this.characterCount = 0;
 }
 
-BingRequest.prototype = {
+GoogleRequest.prototype = {
   /**
    * Initiates the request
    */
   fireRequest() {
-    return (async () => {
-      // Prepare authentication.
-      let token = await BingTokenManager.getToken();
-      let auth = "Bearer " + token;
-
-      // Prepare URL.
-      let url = getUrlParam("https://api.microsofttranslator.com/v2/Http.svc/TranslateArray",
-                            "browser.translation.bing.translateArrayURL");
-
-      // Prepare request headers.
-      let headers = [["Content-type", "text/xml"], ["Authorization", auth]];
-
-      // Prepare the request body.
-      let requestString =
-        "<TranslateArrayRequest>" +
-          "<AppId/>" +
-          "<From>" + this.sourceLanguage + "</From>" +
-          "<Options>" +
-            '<ContentType xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2">text/html</ContentType>' +
-            '<ReservedFlags xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2" />' +
-          "</Options>" +
-          '<Texts xmlns:s="http://schemas.microsoft.com/2003/10/Serialization/Arrays">';
-
-      for (let [, text] of this.translationData) {
-        requestString += "<s:string>" + text + "</s:string>";
-        this.characterCount += text.length;
-      }
-
-      requestString += "</Texts>" +
-          "<To>" + this.targetLanguage + "</To>" +
-        "</TranslateArrayRequest>";
+    let key = Services.cpmm.sharedData.get("translationKey") ||
+              Services.prefs.getStringPref("browser.translation.google.apiKey", "");
+    if (!key) {
+      return Promise.reject("no API key");
+    }
 
-      // Set up request options.
-      return new Promise((resolve, reject) => {
-        let options = {
-          onLoad: (responseText, xhr) => {
-            resolve(this);
-          },
-          onError(e, responseText, xhr) {
-            reject(xhr);
-          },
-          postData: requestString,
-          headers,
-        };
-
-        // Fire the request.
-        let request = httpRequest(url, options);
+    // Prepare the request body.
+    let postData = [
+      ["key", key],
+      ["source", this.sourceLanguage],
+      ["target", this.targetLanguage],
+    ];
 
-        // Override the response MIME type.
-        request.overrideMimeType("text/xml");
-        this.networkRequest = request;
-      });
-    })();
-  },
-};
-
-/**
- * Authentication Token manager for the API
- */
-var BingTokenManager = {
-  _currentToken: null,
-  _currentExpiryTime: 0,
-  _pendingRequest: null,
-
-  /**
-   * Get a valid, non-expired token to be used for the API calls.
-   *
-   * @returns {Promise}  A promise that resolves with the token
-   *                     string once it is obtained. The token returned
-   *                     can be the same one used in the past if it is still
-   *                     valid.
-   */
-  getToken() {
-    if (this._pendingRequest) {
-      return this._pendingRequest;
+    for (let [, text] of this.translationData) {
+      postData.push(["q", text]);
+      this.characterCount += text.length;
     }
 
-    let remainingMs = this._currentExpiryTime - new Date();
-    // Our existing token is still good for more than a minute, let's use it.
-    if (remainingMs > 60 * 1000) {
-      return Promise.resolve(this._currentToken);
-    }
-
-    return this._getNewToken();
-  },
-
-  /**
-   * Generates a new token from the server.
-   *
-   * @returns {Promise}  A promise that resolves with the token
-   *                     string once it is obtained.
-   */
-  _getNewToken() {
-    let url = getUrlParam("https://datamarket.accesscontrol.windows.net/v2/OAuth2-13",
-                          "browser.translation.bing.authURL");
-    let params = [
-      ["grant_type", "client_credentials"],
-      ["scope", "http://api.microsofttranslator.com"],
-      ["client_id",
-      getUrlParam("%BING_API_CLIENTID%", "browser.translation.bing.clientIdOverride")],
-      ["client_secret",
-      getUrlParam("%BING_API_KEY%", "browser.translation.bing.apiKeyOverride")],
-    ];
-
-    this._pendingRequest = new Promise((resolve, reject) => {
+    // Set up request options.
+    return new Promise((resolve, reject) => {
       let options = {
-        onLoad(responseText, xhr) {
-          BingTokenManager._pendingRequest = null;
-          try {
-            let json = JSON.parse(responseText);
-
-            if (json.error) {
-              reject(json.error);
-              return;
-            }
-
-            let token = json.access_token;
-            let expires_in = json.expires_in;
-            BingTokenManager._currentToken = token;
-            BingTokenManager._currentExpiryTime = new Date(Date.now() + expires_in * 1000);
-            resolve(token);
-          } catch (e) {
-            reject(e);
-          }
+        onLoad: (responseText, xhr) => {
+          resolve(this);
         },
         onError(e, responseText, xhr) {
-          BingTokenManager._pendingRequest = null;
-          reject(e);
+          reject(xhr);
         },
-        postData: params,
+        postData,
       };
 
-      httpRequest(url, options);
+      // Fire the request.
+      this.networkRequest = httpRequest(URL, options);
     });
-    return this._pendingRequest;
   },
 };
-
-/**
- * Escape a string to be valid XML content.
- */
-function escapeXML(aStr) {
-  return aStr.toString()
-             .replace(/&/g, "&amp;")
-             .replace(/\"/g, "&quot;")
-             .replace(/\'/g, "&apos;")
-             .replace(/</g, "&lt;")
-             .replace(/>/g, "&gt;");
-}
-
-/**
- * Fetch an auth token (clientID or client secret), which may be overridden by
- * a pref if it's set.
- */
-function getUrlParam(paramValue, prefName) {
-  if (Services.prefs.getPrefType(prefName))
-    paramValue = Services.prefs.getCharPref(prefName);
-  paramValue = Services.urlFormatter.formatURL(paramValue);
-  return paramValue;
-}
--- a/browser/components/translation/Translation.jsm
+++ b/browser/components/translation/Translation.jsm
@@ -77,26 +77,26 @@ var Translation = {
     ChromeUtils.import("resource:///modules/BrowserWindowTracker.jsm");
     BrowserWindowTracker.getTopWindow().openWebLinkIn(attribution, "tab");
   },
 
   /**
    * The list of translation engines and their attributions.
    */
   supportedEngines: {
-    "bing": "http://aka.ms/MicrosoftTranslatorAttribution",
-    "yandex": "http://translate.yandex.com/",
+    "Google": "",
+    "Bing": "http://aka.ms/MicrosoftTranslatorAttribution",
+    "Yandex": "http://translate.yandex.com/",
   },
 
   /**
-   * Fallback engine (currently Bing Translator) if the preferences seem
-   * confusing.
+   * Fallback engine (currently Google) if the preferences seem confusing.
    */
   get defaultEngine() {
-    return this.supportedEngines.keys[0];
+    return Object.keys(this.supportedEngines)[0];
   },
 
   /**
    * Returns the name of the preferred translation engine.
    */
   get translationEngine() {
     let engine = Services.prefs.getCharPref("browser.translation.engine");
     return !Object.keys(this.supportedEngines).includes(engine) ? this.defaultEngine : engine;
--- a/browser/components/translation/TranslationContentHandler.jsm
+++ b/browser/components/translation/TranslationContentHandler.jsm
@@ -59,19 +59,24 @@ TranslationContentHandler.prototype = {
 
   /* nsIWebProgressListener implementation */
   onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
     if (!aWebProgress.isTopLevel ||
         !(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) ||
         !this.global.content)
       return;
 
-    let url = aRequest.name;
-    if (!url.startsWith("http://") && !url.startsWith("https://"))
+    try {
+      let url = aRequest.name;
+      if (!url.startsWith("http://") && !url.startsWith("https://"))
+        return;
+    } catch (e) {
+      // nsIRequest.name throws NS_ERROR_NOT_IMPLEMENTED for view-source: tabs.
       return;
+    }
 
     let content = this.global.content;
     if (content.detectedLanguage)
       return;
 
     // Grab a 60k sample of text from the page.
     let encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
                     .createInstance(Ci.nsIDocumentEncoder);
@@ -115,29 +120,22 @@ TranslationContentHandler.prototype = {
 
         // If a TranslationDocument already exists for this document, it should
         // be used instead of creating a new one so that we can use the original
         // content of the page for the new translation instead of the newly
         // translated text.
         let translationDocument = this.global.content.translationDocument ||
                                   new TranslationDocument(this.global.content.document);
 
-        let preferredEngine = Services.prefs.getCharPref("browser.translation.engine");
-        let translator = null;
-        if (preferredEngine == "yandex") {
-          ChromeUtils.import("resource:///modules/translation/YandexTranslator.jsm");
-          translator = new YandexTranslator(translationDocument,
-                                            msg.data.from,
-                                            msg.data.to);
-        } else {
-          ChromeUtils.import("resource:///modules/translation/BingTranslator.jsm");
-          translator = new BingTranslator(translationDocument,
-                                          msg.data.from,
-                                          msg.data.to);
-        }
+        let engine = Services.prefs.getCharPref("browser.translation.engine");
+        let importScope =
+          ChromeUtils.import(`resource:///modules/translation/${engine}Translator.jsm`, {});
+        let translator = new importScope[engine + "Translator"](translationDocument,
+                                                                msg.data.from,
+                                                                msg.data.to);
 
         this.global.content.translationDocument = translationDocument;
         translationDocument.translatedFrom = msg.data.from;
         translationDocument.translatedTo = msg.data.to;
         translationDocument.translationError = false;
 
         translator.translate().then(
           result => {
--- a/browser/components/translation/moz.build
+++ b/browser/components/translation/moz.build
@@ -4,16 +4,17 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Firefox", "Translation")
 
 EXTRA_JS_MODULES.translation = [
     'BingTranslator.jsm',
     'cld2/cld-worker.js',
     'cld2/cld-worker.js.mem',
+    'GoogleTranslator.jsm',
     'LanguageDetector.jsm',
     'Translation.jsm',
     'TranslationContentHandler.jsm',
     'TranslationDocument.jsm',
     'YandexTranslator.jsm'
 ]
 
 JAR_MANIFESTS += ['jar.mn']
--- a/browser/components/translation/test/browser_translation_yandex.js
+++ b/browser/components/translation/test/browser_translation_yandex.js
@@ -16,17 +16,17 @@ PromiseTestUtils.whitelistRejectionsGlob
 
 const kEnginePref = "browser.translation.engine";
 const kApiKeyPref = "browser.translation.yandex.apiKeyOverride";
 const kShowUIPref = "browser.translation.ui.show";
 
 const {Translation} = ChromeUtils.import("resource:///modules/translation/Translation.jsm", {});
 
 add_task(async function setup() {
-  Services.prefs.setCharPref(kEnginePref, "yandex");
+  Services.prefs.setCharPref(kEnginePref, "Yandex");
   Services.prefs.setCharPref(kApiKeyPref, "yandexValidKey");
   Services.prefs.setBoolPref(kShowUIPref, true);
 
   registerCleanupFunction(function() {
     Services.prefs.clearUserPref(kEnginePref);
     Services.prefs.clearUserPref(kApiKeyPref);
     Services.prefs.clearUserPref(kShowUIPref);
   });
--- a/browser/components/translation/translation-infobar.xml
+++ b/browser/components/translation/translation-infobar.xml
@@ -212,18 +212,32 @@
               toLanguage.value = aTranslation.translatedTo;
 
             if (aTranslation.state)
               this.state = aTranslation.state;
 
             // Show attribution for the preferred translator.
             let engineIndex = Object.keys(Translation.supportedEngines)
               .indexOf(Translation.translationEngine);
+            // We currently only have attribution for the Bing and Yandex engines.
+            if (engineIndex >= 0) {
+              --engineIndex;
+            }
+            let attributionNode = this._getAnonElt("translationEngine");
             if (engineIndex != -1) {
-              this._getAnonElt("translationEngine").selectedIndex = engineIndex;
+              attributionNode.selectedIndex = engineIndex;
+            } else {
+              // Hide the attribution menuitem
+              let footer = attributionNode.parentNode;
+              footer.hidden = true;
+              // Make the 'Translation preferences' item the new footer.
+              footer = footer.previousSibling;
+              footer.setAttribute("class", "subviewbutton panel-subview-footer");
+              // And hide the menuseparator.
+              footer.previousSibling.hidden = true;
             }
 
             const kWelcomePref = "browser.translation.ui.welcomeMessageShown";
             if (Services.prefs.prefHasUserValue(kWelcomePref) ||
                 this.translation.browser != gBrowser.selectedBrowser)
               return;
 
             this.addEventListener("transitionend", function() {
--- a/devtools/.eslintrc.mochitests.js
+++ b/devtools/.eslintrc.mochitests.js
@@ -6,16 +6,17 @@ module.exports = {
   // All globals made available in the test environment.
   "globals": {
     "DevToolsUtils": true,
     "gDevTools": true,
     "once": true,
     "synthesizeKeyFromKeyTag": true,
     "TargetFactory": true,
     "waitForTick": true,
+    "waitUntilState": true,
   },
 
   "parserOptions": {
     "ecmaFeatures": {
       "jsx": true,
     }
   },
 
--- a/devtools/client/inspector/computed/computed.js
+++ b/devtools/client/inspector/computed/computed.js
@@ -1,20 +1,21 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
+const promise = require("promise");
+const flags = require("devtools/shared/flags");
 const ToolDefinitions = require("devtools/client/definitions").Tools;
 const CssLogic = require("devtools/shared/inspector/css-logic");
 const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
-const promise = require("promise");
 const OutputParser = require("devtools/client/shared/output-parser");
 const {PrefObserver} = require("devtools/client/shared/prefs");
 const {createChild} = require("devtools/client/inspector/shared/utils");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const {getCssProperties} = require("devtools/shared/fronts/css-properties");
 const {
   VIEW_NODE_SELECTOR_TYPE,
   VIEW_NODE_PROPERTY_TYPE,
@@ -178,24 +179,30 @@ function CssComputedView(inspector, docu
   this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
   this._onShortcut = this._onShortcut.bind(this);
   this.shortcuts.on("CmdOrCtrl+F", event => this._onShortcut("CmdOrCtrl+F", event));
   this.shortcuts.on("Escape", event => this._onShortcut("Escape", event));
   this.styleDocument.addEventListener("copy", this._onCopy);
   this.styleDocument.addEventListener("mousedown", this.focusWindow);
   this.element.addEventListener("click", this._onClick);
   this.element.addEventListener("contextmenu", this._onContextMenu);
-  this.element.addEventListener("mousemove", () => {
-    this.addHighlightersToView();
-  }, { once: true });
   this.searchField.addEventListener("input", this._onFilterStyles);
   this.searchClearButton.addEventListener("click", this._onClearSearch);
   this.includeBrowserStylesCheckbox.addEventListener("input",
     this._onIncludeBrowserStyles);
 
+  if (flags.testing) {
+    // In tests, we start listening immediately to avoid having to simulate a mousemove.
+    this.highlighters.addToView(this);
+  } else {
+    this.element.addEventListener("mousemove", () => {
+      this.highlighters.addToView(this);
+    }, { once: true });
+  }
+
   this.searchClearButton.hidden = true;
 
   // No results text.
   this.noResults = this.styleDocument.getElementById("computed-no-results");
 
   // Refresh panel when color unit changed or pref for showing
   // original sources changes.
   this._handlePrefChange = this._handlePrefChange.bind(this);
@@ -728,24 +735,16 @@ CssComputedView.prototype = {
 
       clipboardHelper.copyString(text);
     } catch (e) {
       console.error(e);
     }
   },
 
   /**
-   * Adds the highlighters overlay to the computed view. This is called by the "mousemove"
-   * event handler and in shared-head.js when opening and selecting the computed view.
-   */
-  addHighlightersToView() {
-    this.highlighters.addToView(this);
-  },
-
-  /**
    * Destructor for CssComputedView.
    */
   destroy: function() {
     this._viewedElement = null;
     this._outputParser = null;
 
     this._prefObserver.off("devtools.defaultColorUnit", this._handlePrefChange);
     this._prefObserver.destroy();
--- a/devtools/client/inspector/flexbox/flexbox.js
+++ b/devtools/client/inspector/flexbox/flexbox.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { throttle } = require("devtools/client/inspector/shared/utils");
+const flags = require("devtools/shared/flags");
 
 const {
   clearFlexbox,
   toggleFlexItemShown,
   updateFlexbox,
   updateFlexboxColor,
   updateFlexboxHighlighted,
 } = require("./actions/flexbox");
@@ -57,20 +58,26 @@ class FlexboxInspector {
         "getCurrentFlexbox");
       this.layoutInspector = await this.walker.getLayoutInspector();
     } catch (e) {
       // These calls might fail if called asynchrously after the toolbox is finished
       // closing.
       return;
     }
 
-    this.document.addEventListener("mousemove", () => {
+    if (flags.testing) {
+      // In tests, we start listening immediately to avoid having to simulate a mousemove.
       this.highlighters.on("flexbox-highlighter-hidden", this.onHighlighterHidden);
       this.highlighters.on("flexbox-highlighter-shown", this.onHighlighterShown);
-    }, { once: true });
+    } else {
+      this.document.addEventListener("mousemove", () => {
+        this.highlighters.on("flexbox-highlighter-hidden", this.onHighlighterHidden);
+        this.highlighters.on("flexbox-highlighter-shown", this.onHighlighterShown);
+      }, { once: true });
+    }
 
     this.inspector.sidebar.on("select", this.onSidebarSelect);
 
     this.onSidebarSelect();
   }
 
   destroy() {
     if (this._highlighters) {
@@ -299,105 +306,83 @@ class FlexboxInspector {
    * with new flexbox data.
    *
    * @param  {FlexboxFront|Null} flexboxFront
    *         The FlexboxFront of the flex container for the current node selection.
    */
   async update(flexboxFront) {
     // Stop refreshing if the inspector or store is already destroyed or no node is
     // selected.
-    if (!this.inspector || !this.store || !this.inspector.selection.nodeFront) {
-      return;
-    }
-
-    // Fetch the current flexbox if no flexbox front was passed into this update.
-    if (!flexboxFront) {
-      try {
-        if (!this.hasGetCurrentFlexbox) {
-          return;
-        }
-
-        flexboxFront = await this.layoutInspector.getCurrentFlexbox(
-          this.inspector.selection.nodeFront);
-      } catch (e) {
-        // This call might fail if called asynchrously after the toolbox is finished
-        // closing.
-        return;
-      }
-    }
-
-    // Clear the flexbox panel if there is no flex container for the current node
-    // selection.
-    if (!flexboxFront) {
-      try {
-        this.store.dispatch(clearFlexbox());
-      } catch (e) {
-        // This call might fail if called asynchrously after the toolbox is finished
-        // closing.
-      }
+    if (!this.inspector ||
+        !this.store ||
+        !this.inspector.selection.nodeFront ||
+        !this.hasGetCurrentFlexbox) {
       return;
     }
 
-    let containerNodeFront = flexboxFront.containerNodeFront;
+    try {
+      // Fetch the current flexbox if no flexbox front was passed into this update.
+      if (!flexboxFront) {
+        flexboxFront = await this.layoutInspector.getCurrentFlexbox(
+          this.inspector.selection.nodeFront);
+      }
 
-    // If the FlexboxFront doesn't yet have access to the NodeFront for its container,
-    // then get it from the walker. This happens when the walker hasn't seen this
-    // particular DOM Node in the tree yet or when we are connected to an older server.
-    if (!containerNodeFront) {
-      try {
-        containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
-          ["containerEl"]);
-      } catch (e) {
-        // This call might fail if called asynchrously after the toolbox is finished
-        // closing.
+      // Clear the flexbox panel if there is no flex container for the current node
+      // selection.
+      if (!flexboxFront) {
+        this.store.dispatch(clearFlexbox());
         return;
       }
-    }
-
-    const highlighted = this._highlighters &&
-      containerNodeFront == this.highlighters.flexboxHighlighterShown;
 
-    // Fetch the flex items for the given flex container and the flex item NodeFronts.
-    const flexItems = [];
-    const flexItemFronts = await flexboxFront.getFlexItems();
+      // If the FlexboxFront doesn't yet have access to the NodeFront for its container,
+      // then get it from the walker. This happens when the walker hasn't seen this
+      // particular DOM Node in the tree yet or when we are connected to an older server.
+      let containerNodeFront = flexboxFront.containerNodeFront;
+      if (!containerNodeFront) {
+        containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
+          ["containerEl"]);
+      }
 
-    for (const flexItemFront of flexItemFronts) {
-      let itemNodeFront = flexItemFront.nodeFront;
+      // Fetch the flex items for the given flex container and the flex item NodeFronts.
+      const flexItems = [];
+      const flexItemFronts = await flexboxFront.getFlexItems();
 
-      if (!itemNodeFront) {
-        try {
+      for (const flexItemFront of flexItemFronts) {
+        let itemNodeFront = flexItemFront.nodeFront;
+        if (!itemNodeFront) {
           itemNodeFront = await this.walker.getNodeFromActor(flexItemFront.actorID,
             ["element"]);
-        } catch (e) {
-          // This call might fail if called asynchrously after the toolbox is finished
-          // closing.
-          return;
         }
+
+        flexItems.push({
+          actorID: flexItemFront.actorID,
+          shown: false,
+          flexItemSizing: flexItemFront.flexItemSizing,
+          nodeFront: itemNodeFront,
+          properties: flexItemFront.properties,
+        });
       }
 
-      flexItems.push({
-        actorID: flexItemFront.actorID,
-        shown: false,
-        flexItemSizing: flexItemFront.flexItemSizing,
-        nodeFront: itemNodeFront,
-        properties: flexItemFront.properties,
-      });
-    }
+      const highlighted = this._highlighters &&
+        containerNodeFront == this.highlighters.flexboxHighlighterShown;
+      const currentUrl = this.inspector.target.url;
+      // Get the hostname, if there is no hostname, fall back on protocol
+      // ex: `data:` uri, and `about:` pages
+      const hostname = parseURL(currentUrl).hostname || parseURL(currentUrl).protocol;
+      const customColors = await this.getCustomFlexboxColors();
+      const color = customColors[hostname] ? customColors[hostname] : FLEXBOX_COLOR;
 
-    const currentUrl = this.inspector.target.url;
-    // Get the hostname, if there is no hostname, fall back on protocol
-    // ex: `data:` uri, and `about:` pages
-    const hostname = parseURL(currentUrl).hostname || parseURL(currentUrl).protocol;
-    const customColors = await this.getCustomFlexboxColors();
-    const color = customColors[hostname] ? customColors[hostname] : FLEXBOX_COLOR;
-
-    this.store.dispatch(updateFlexbox({
-      actorID: flexboxFront.actorID,
-      color,
-      flexItems,
-      highlighted,
-      nodeFront: containerNodeFront,
-      properties: flexboxFront.properties,
-    }));
+      this.store.dispatch(updateFlexbox({
+        actorID: flexboxFront.actorID,
+        color,
+        flexItems,
+        highlighted,
+        nodeFront: containerNodeFront,
+        properties: flexboxFront.properties,
+      }));
+    } catch (e) {
+      // This call might fail if called asynchrously after the toolbox is finished
+      // closing.
+    }
   }
 }
 
 module.exports = FlexboxInspector;
--- a/devtools/client/inspector/grids/grid-inspector.js
+++ b/devtools/client/inspector/grids/grid-inspector.js
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Services = require("Services");
 const { throttle } = require("devtools/client/inspector/shared/utils");
+const flags = require("devtools/shared/flags");
 
 const {
   updateGridColor,
   updateGridHighlighted,
   updateGrids,
 } = require("./actions/grids");
 const {
   updateShowGridAreas,
@@ -92,20 +93,26 @@ class GridInspector {
     try {
       this.layoutInspector = await this.inspector.walker.getLayoutInspector();
     } catch (e) {
       // This call might fail if called asynchrously after the toolbox is finished
       // closing.
       return;
     }
 
-    this.document.addEventListener("mousemove", () => {
+    if (flags.testing) {
+      // In tests, we start listening immediately to avoid having to simulate a mousemove.
       this.highlighters.on("grid-highlighter-hidden", this.onHighlighterHidden);
       this.highlighters.on("grid-highlighter-shown", this.onHighlighterShown);
-    }, { once: true });
+    } else {
+      this.document.addEventListener("mousemove", () => {
+        this.highlighters.on("grid-highlighter-hidden", this.onHighlighterHidden);
+        this.highlighters.on("grid-highlighter-shown", this.onHighlighterShown);
+      }, { once: true });
+    }
 
     this.inspector.sidebar.on("select", this.onSidebarSelect);
     this.inspector.on("new-root", this.onNavigate);
 
     this.onSidebarSelect();
   }
 
   /**
--- a/devtools/client/inspector/grids/test/.eslintrc.js
+++ b/devtools/client/inspector/grids/test/.eslintrc.js
@@ -1,9 +1,6 @@
 "use strict";
 
 module.exports = {
   // Extend from the shared list of defined globals for mochitests.
   "extends": "../../../../.eslintrc.mochitests.js",
-  "globals": {
-    "waitUntilState": true
-  }
 };
--- a/devtools/client/inspector/markup/test/.eslintrc.js
+++ b/devtools/client/inspector/markup/test/.eslintrc.js
@@ -1,6 +1,6 @@
 "use strict";
 
 module.exports = {
   // Extend from the shared list of defined globals for mochitests.
-  "extends": "../../../../.eslintrc.mochitests.js"
+  "extends": "../../../../.eslintrc.mochitests.js",
 };
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -68,16 +68,17 @@ support-files =
   lib_react_dom_16.2.0_min.js
   lib_react_with_addons_15.3.1_min.js
   lib_react_with_addons_15.4.1.js
   react_external_listeners.js
   !/devtools/client/debugger/new/test/mochitest/helpers.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/shared-head.js
+  !/devtools/client/shared/test/shared-redux-head.js
   !/devtools/client/shared/test/telemetry-test-helpers.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_markup_accessibility_focus_blur.js]
 skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
 [browser_markup_accessibility_navigation.js]
 skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
@@ -125,16 +126,18 @@ skip-if = true # Bug 1177550
 [browser_markup_events_react_development_15.4.1.js]
 [browser_markup_events_react_development_15.4.1_jsx.js]
 [browser_markup_events_react_production_15.3.1.js]
 [browser_markup_events_react_production_15.3.1_jsx.js]
 [browser_markup_events_react_production_16.2.0.js]
 [browser_markup_events_react_production_16.2.0_jsx.js]
 [browser_markup_events_source_map.js]
 [browser_markup_events-windowed-host.js]
+[browser_markup_flex_display_badge.js]
+[browser_markup_grid_display_badge.js]
 [browser_markup_links_01.js]
 [browser_markup_links_02.js]
 [browser_markup_links_03.js]
 [browser_markup_links_04.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_markup_links_05.js]
 [browser_markup_links_06.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_flex_display_badge.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the flex display badge toggles on the flexbox highlighter.
+
+const TEST_URI = `
+  <style type="text/css">
+    #flex {
+      display: flex;
+    }
+  </style>
+  <div id="flex"></div>
+`;
+
+const HIGHLIGHTER_TYPE = "FlexboxHighlighter";
+
+add_task(async function() {
+  await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  const { inspector } = await openLayoutView();
+  const { highlighters, store } = inspector;
+
+  info("Check the flex display badge is shown and not active.");
+  await selectNode("#flex", inspector);
+  const flexContainer = await getContainerForSelector("#flex", inspector);
+  const flexDisplayBadge = flexContainer.elt.querySelector(".markup-badge[data-display]");
+  ok(!flexDisplayBadge.classList.contains("active"), "flex display badge is not active.");
+
+  info("Check the initial state of the flex highlighter.");
+  ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+    "No flexbox highlighter exists in the highlighters overlay.");
+  ok(!highlighters.flexboxHighlighterShown, "No flexbox highlighter is shown.");
+
+  info("Toggling ON the flexbox highlighter from the flex display badge.");
+  const onHighlighterShown = highlighters.once("flexbox-highlighter-shown");
+  let onCheckboxChange = waitUntilState(store, state => state.flexbox.highlighted);
+  flexDisplayBadge.click();
+  await onHighlighterShown;
+  await onCheckboxChange;
+
+  info("Check the flexbox highlighter is created and flex display badge state.");
+  ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+    "Flexbox highlighter is created in the highlighters overlay.");
+  ok(highlighters.flexboxHighlighterShown, "Flexbox highlighter is shown.");
+  ok(flexDisplayBadge.classList.contains("active"), "flex display badge is active.");
+
+  info("Toggling OFF the flexbox highlighter from the flex display badge.");
+  const onHighlighterHidden = highlighters.once("flexbox-highlighter-hidden");
+  onCheckboxChange = waitUntilState(store, state => !state.flexbox.highlighted);
+  flexDisplayBadge.click();
+  await onHighlighterHidden;
+  await onCheckboxChange;
+
+  ok(!flexDisplayBadge.classList.contains("active"), "flex display badge is not active.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_grid_display_badge.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid display badge toggles on the grid highlighter.
+
+const TEST_URI = `
+  <style type="text/css">
+    #grid {
+      display: grid;
+    }
+  </style>
+  <div id="grid"></div>
+`;
+
+const HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(async function() {
+  await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  const { inspector } = await openLayoutView();
+  const { highlighters, store } = inspector;
+
+  info("Check the grid display badge is shown and not active.");
+  await selectNode("#grid", inspector);
+  const gridContainer = await getContainerForSelector("#grid", inspector);
+  const gridDisplayBadge = gridContainer.elt.querySelector(".markup-badge[data-display]");
+  ok(!gridDisplayBadge.classList.contains("active"), "grid display badge is not active.");
+
+  info("Check the initial state of the grid highlighter.");
+  ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+    "No CSS grid highlighter exists in the highlighters overlay.");
+  ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+
+  info("Toggling ON the CSS grid highlighter from the grid display badge.");
+  const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+  let onCheckboxChange = waitUntilState(store, state =>
+    state.grids.length === 1 &&
+    state.grids[0].highlighted);
+  gridDisplayBadge.click();
+  await onHighlighterShown;
+  await onCheckboxChange;
+
+  info("Check the CSS grid highlighter is created and grid display badge state.");
+  ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+    "CSS grid highlighter is created in the highlighters overlay.");
+  ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+  ok(gridDisplayBadge.classList.contains("active"), "grid display badge is active.");
+
+  info("Toggling OFF the CSS grid highlighter from the grid display badge.");
+  const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+  onCheckboxChange = waitUntilState(store, state =>
+    state.grids.length == 1 &&
+    !state.grids[0].highlighted);
+  gridDisplayBadge.click();
+  await onHighlighterHidden;
+  await onCheckboxChange;
+
+  ok(!gridDisplayBadge.classList.contains("active"), "grid display badge is not active.");
+});
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -1,21 +1,25 @@
-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 /* eslint no-unused-vars: [2, {"vars": "local"}] */
 /* import-globals-from ../../test/head.js */
 "use strict";
 
 // Import the inspector's head.js first (which itself imports shared-head.js).
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
   this);
 
+// Load the shared Redux helpers into this compartment.
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/shared/test/shared-redux-head.js",
+  this);
+
 var {getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
 var clipboard = require("devtools/shared/platform/clipboard");
 
 // If a test times out we want to see the complete log and not just the last few
 // lines.
 SimpleTest.requestCompleteLog();
 
 // Toggle this pref on to see all DevTools event communication. This is hugely
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const promise = require("promise");
 const Services = require("Services");
+const flags = require("devtools/shared/flags");
 const {l10n} = require("devtools/shared/inspector/css-logic");
 const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
 const OutputParser = require("devtools/client/shared/output-parser");
 const {PrefObserver} = require("devtools/client/shared/prefs");
 const ElementStyle = require("devtools/client/inspector/rules/models/element-style");
 const Rule = require("devtools/client/inspector/rules/models/rule");
 const RuleEditor = require("devtools/client/inspector/rules/views/rule-editor");
 const {getCssProperties} = require("devtools/shared/fronts/css-properties");
@@ -146,28 +147,34 @@ function CssRuleView(inspector, document
   this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
   this._onShortcut = this._onShortcut.bind(this);
   this.shortcuts.on("Escape", event => this._onShortcut("Escape", event));
   this.shortcuts.on("Return", event => this._onShortcut("Return", event));
   this.shortcuts.on("Space", event => this._onShortcut("Space", event));
   this.shortcuts.on("CmdOrCtrl+F", event => this._onShortcut("CmdOrCtrl+F", event));
   this.element.addEventListener("copy", this._onCopy);
   this.element.addEventListener("contextmenu", this._onContextMenu);
-  this.element.addEventListener("mousemove", () => {
-    this.addHighlightersToView();
-  }, { once: true });
   this.addRuleButton.addEventListener("click", this._onAddRule);
   this.searchField.addEventListener("input", this._onFilterStyles);
   this.searchClearButton.addEventListener("click", this._onClearSearch);
   this.pseudoClassToggle.addEventListener("click", this._onTogglePseudoClassPanel);
   this.classToggle.addEventListener("click", this._onToggleClassPanel);
   this.hoverCheckbox.addEventListener("click", this._onTogglePseudoClass);
   this.activeCheckbox.addEventListener("click", this._onTogglePseudoClass);
   this.focusCheckbox.addEventListener("click", this._onTogglePseudoClass);
 
+  if (flags.testing) {
+    // In tests, we start listening immediately to avoid having to simulate a mousemove.
+    this.highlighters.addToView(this);
+  } else {
+    this.element.addEventListener("mousemove", () => {
+      this.highlighters.addToView(this);
+    }, { once: true });
+  }
+
   this._handlePrefChange = this._handlePrefChange.bind(this);
   this._handleUAStylePrefChange = this._handleUAStylePrefChange.bind(this);
   this._handleDefaultColorUnitPrefChange =
     this._handleDefaultColorUnitPrefChange.bind(this);
 
   this._prefObserver = new PrefObserver("devtools.");
   this._prefObserver.on(PREF_UA_STYLES, this._handleUAStylePrefChange);
   this._prefObserver.on(PREF_DEFAULT_COLOR_UNIT, this._handleDefaultColorUnitPrefChange);
@@ -1632,24 +1639,16 @@ CssRuleView.prototype = {
                event.target === this.searchField &&
                this._onClearSearch()) {
       // Handle the search box's keypress event. If the escape key is pressed,
       // clear the search box field.
       event.preventDefault();
       event.stopPropagation();
     }
   },
-
-  /**
-   * Adds the highlighters overlay to the rule view. This is called by the "mousemove"
-   * event handler and in shared-head.js when opening and selecting the rule view.
-   */
-  addHighlightersToView() {
-    this.highlighters.addToView(this);
-  },
 };
 
 /**
  * Helper functions
  */
 
 /**
  * Walk up the DOM from a given node until a parent property holder is found.
--- a/devtools/client/inspector/test/shared-head.js
+++ b/devtools/client/inspector/test/shared-head.js
@@ -86,19 +86,16 @@ var openInspectorSidebarTab = async func
 function openRuleView() {
   return openInspector().then(data => {
     const view = data.inspector.getPanel("ruleview").view;
 
     // Replace the view to use a custom debounce function that can be triggered manually
     // through an additional ".flush()" property.
     view.debounce = manualDebounce();
 
-    // Adds the highlighters overlay in the rule view.
-    view.addHighlightersToView();
-
     return {
       toolbox: data.toolbox,
       inspector: data.inspector,
       testActor: data.testActor,
       view,
     };
   });
 }
@@ -108,18 +105,16 @@ function openRuleView() {
  * sidebar tab selected.
  *
  * @return a promise that resolves when the inspector is ready and the computed
  * view is visible and ready
  */
 function openComputedView() {
   return openInspectorSidebarTab("computedview").then(data => {
     const view = data.inspector.getPanel("computedview").computedView;
-    // Adds the highlighters overlay in the computed view.
-    view.addHighlightersToView();
 
     return {
       toolbox: data.toolbox,
       inspector: data.inspector,
       testActor: data.testActor,
       view,
     };
   });
@@ -160,33 +155,29 @@ function openLayoutView() {
 /**
  * Select the rule view sidebar tab on an already opened inspector panel.
  *
  * @param {InspectorPanel} inspector
  *        The opened inspector panel
  * @return {CssRuleView} the rule view
  */
 function selectRuleView(inspector) {
-  const view = inspector.getPanel("ruleview").view;
-  view.addHighlightersToView();
-  return view;
+  return inspector.getPanel("ruleview").view;
 }
 
 /**
  * Select the computed view sidebar tab on an already opened inspector panel.
  *
  * @param {InspectorPanel} inspector
  *        The opened inspector panel
  * @return {CssComputedView} the computed view
  */
 function selectComputedView(inspector) {
   inspector.sidebar.select("computedview");
-  const view = inspector.getPanel("computedview").computedView;
-  view.addHighlightersToView();
-  return view;
+  return inspector.getPanel("computedview").computedView;
 }
 
 /**
  * Select the layout view sidebar tab on an already opened inspector panel.
  *
  * @param  {InspectorPanel} inspector
  * @return {BoxModel} the box model
  */
--- a/devtools/client/shared/redux/middleware/test/.eslintrc.js
+++ b/devtools/client/shared/redux/middleware/test/.eslintrc.js
@@ -3,15 +3,14 @@
 module.exports = {
   // Extend from the shared list of defined globals for mochitests.
   "extends": "../../../../../.eslintrc.mochitests.js",
   "globals": {
     "run_test": true,
     "run_next_test": true,
     "equal": true,
     "do_print": true,
-    "waitUntilState": true
   },
   "rules": {
     // Stop giving errors for run_test
     "camelcase": "off"
   }
 };
--- a/dom/tests/browser/browser_bug1236512.js
+++ b/dom/tests/browser/browser_bug1236512.js
@@ -38,22 +38,26 @@ async function waitContentVisibilityChan
 /**
  * This test is to test the visibility state will change to "hidden" when browser
  * window is fully covered by another non-translucent application. Note that we
  * only support this on Mac for now, other platforms don't support reporting
  * occlusion state.
  */
 add_task(async function() {
   info("creating test window");
+  let winTest = await BrowserTestUtils.openNewBrowserWindow();
   // Specify the width, height, left and top, so that the new window can be
   // fully covered by "window".
-  let winTest = await BrowserTestUtils.openNewBrowserWindow({ width: 500,
-                                                              height: 500,
-                                                              left: 200,
-                                                              top: 200 });
+  let resizePromise = BrowserTestUtils.waitForEvent(winTest, "resize", false, e => {
+    return winTest.innerHeight <= 500 && winTest.innerWidth <= 500;
+  });
+  winTest.moveTo(200, 200);
+  winTest.resizeTo(500, 500);
+  await resizePromise;
+
   let browserTest = winTest.gBrowser;
 
   info(`loading test page: ${testPageURL}`);
   browserTest.selectedBrowser.loadURI(testPageURL);
   await BrowserTestUtils.browserLoaded(browserTest.selectedBrowser);
 
   info("test init visibility state");
   await testContentVisibilityState(false /* isHidden */, browserTest);
--- a/gfx/2d/SourceSurfaceD2D1.cpp
+++ b/gfx/2d/SourceSurfaceD2D1.cpp
@@ -141,16 +141,18 @@ SourceSurfaceD2D1::DrawTargetWillChange(
 
   D2D1_POINT_2U point = D2D1::Point2U(0, 0);
   D2D1_RECT_U rect = D2D1::RectU(0, 0, mSize.width, mSize.height);
   mRealizedBitmap->CopyFromBitmap(&point, oldBitmap, &rect);
   mImage = mRealizedBitmap;
 
   DrawTargetD2D1::mVRAMUsageSS += mSize.width * mSize.height * BytesPerPixel(mFormat);
 
+  // Ensure the object stays alive for the duration of MarkIndependent.
+  RefPtr<SourceSurfaceD2D1> deathGrip = this;
   // We now no longer depend on the source surface content remaining the same.
   MarkIndependent();
 }
 
 void
 SourceSurfaceD2D1::MarkIndependent()
 {
   if (mDrawTarget) {
--- a/netwerk/test/httpserver/README
+++ b/netwerk/test/httpserver/README
@@ -19,20 +19,20 @@ in the Mozilla SDK for the environment i
 <http://developer.mozilla.org/en/docs/XPIDL:xpidl> for further details on how to
 do this.
 
 Next, register httpd.js and nsIHttpServer.xpt in your Mozilla application.  In
 Firefox, these simply need to be added to the /components directory of your XPI.
 Other applications may require use of regxpcom or other techniques; consult the
 applicable documentation for further details.
 
-Finally, create an instance of the server using the following command:
+Finally, load httpd.js into the current file, and create an instance of the
+server using the following command:
 
-  var server = Components.classes["@mozilla.org/server/jshttp;1"]
-                         .createInstance(Components.interfaces.nsIHttpServer);
+  var server = new nsHttpServer();
 
 At this point you'll want to initialize the server, since by default it doesn't
 serve many useful paths.  For more information on this, see the IDL docs for the
 nsIHttpServer interface in nsIHttpServer.idl, particularly for
 registerDirectory (useful for mapping the contents of directories onto request
 paths), registerPathHandler (for setting a custom handler for a specific path on
 the server, such as CGI functionality), and registerFile (for mapping a file to
 a specific path).
--- a/netwerk/test/httpserver/httpd.js
+++ b/netwerk/test/httpserver/httpd.js
@@ -33,18 +33,16 @@ var EXPORTED_SYMBOLS = [
   "HTTP_502",
   "HTTP_503",
   "HTTP_504",
   "HTTP_505",
   "HttpError",
   "HttpServer",
 ];
 
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
 const CC = Components.Constructor;
 
 const PR_UINT32_MAX = Math.pow(2, 32) - 1;
 
 /** True if debugging output is enabled, false otherwise. */
 var DEBUG = false; // non-const *only* so tweakable in server tests
 
 /** True if debugging output should be timestamped. */
@@ -385,18 +383,16 @@ function nsHttpServer()
   /**
    * Hash of all open connections, indexed by connection number at time of
    * creation.
    */
   this._connections = {};
 }
 nsHttpServer.prototype =
 {
-  classID: Components.ID("{54ef6f81-30af-4b1d-ac55-8ba811293e41}"),
-
   // NSISERVERSOCKETLISTENER
 
   /**
    * Processes an incoming request coming in on the given socket and contained
    * in the given transport.
    *
    * @param socket : nsIServerSocket
    *   the socket through which the request was served
@@ -5324,21 +5320,16 @@ Request.prototype =
   /** Ensures a property bag has been created for ad-hoc behaviors. */
   _ensurePropertyBag: function()
   {
     if (!this._bag)
       this._bag = new WritablePropertyBag();
   }
 };
 
-
-// XPCOM trappings
-
-var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsHttpServer]);
-
 /**
  * Creates a new HTTP server listening for loopback traffic on the given port,
  * starts it, and runs the server until the server processes a shutdown request,
  * spinning an event loop so that events posted by the server's socket are
  * processed.
  *
  * This method is primarily intended for use in running this script from within
  * xpcshell and running a functional HTTP server without having to deal with
--- a/netwerk/test/httpserver/httpd.manifest
+++ b/netwerk/test/httpserver/httpd.manifest
@@ -1,3 +1,1 @@
-component {54ef6f81-30af-4b1d-ac55-8ba811293e41} httpd.js
-contract @mozilla.org/server/jshttp;1 {54ef6f81-30af-4b1d-ac55-8ba811293e41}
 interfaces test_necko.xpt
--- a/netwerk/test/httpserver/test/head_utils.js
+++ b/netwerk/test/httpserver/test/head_utils.js
@@ -6,16 +6,17 @@
 
 var _HTTPD_JS_PATH = __LOCATION__.parent;
 _HTTPD_JS_PATH.append("httpd.js");
 load(_HTTPD_JS_PATH.path);
 
 // if these tests fail, we'll want the debug output
 DEBUG = true;
 
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
 
 /**
  * Constructs a new nsHttpServer instance.  This function is intended to
  * encapsulate construction of a server so that at some point in the future it
  * is possible to run these tests (with at most slight modifications) against
  * the server when used as an XPCOM component (not as an inline script).
  */
--- a/security/manager/locales/en-US/chrome/pipnss/pipnss.properties
+++ b/security/manager/locales/en-US/chrome/pipnss/pipnss.properties
@@ -274,44 +274,44 @@ SSLConnectionErrorPrefix2=An error occur
 
 certErrorIntro=%S uses an invalid security certificate.
 
 certErrorTrust_SelfSigned=The certificate is not trusted because it is self-signed.
 certErrorTrust_UnknownIssuer=The certificate is not trusted because the issuer certificate is unknown.
 certErrorTrust_UnknownIssuer2=The server might not be sending the appropriate intermediate certificates.
 certErrorTrust_UnknownIssuer3=An additional root certificate may need to be imported.
 certErrorTrust_UnknownIssuer4=Someone could be trying to impersonate the site and you should not continue.
-# LOCALIZATION NOTE (certErrorTrust_UnknownIssuer5): %1$S is replaced by the brand name, %2$S is replaced by host name.
-certErrorTrust_UnknownIssuer5=Websites prove their identity via security certificates. %1$S does not trust %2$S because its security certificate issuer is unknown, the certificate is self-signed, or the server is not sending the correct intermediate certificates.
+# LOCALIZATION NOTE (certErrorTrust_UnknownIssuer6): %1$S is replaced by the brand name, %2$S is replaced by host name.
+certErrorTrust_UnknownIssuer6=Websites prove their identity via certificates. %1$S does not trust %2$S because its security certificate issuer is unknown, the certificate is self-signed, or the server is not sending the correct intermediate certificates.
 certErrorTrust_CaInvalid=The certificate is not trusted because it was issued by an invalid CA certificate.
 certErrorTrust_Issuer=The certificate is not trusted because the issuer certificate is not trusted.
 certErrorTrust_SignatureAlgorithmDisabled=The certificate is not trusted because it was signed using a signature algorithm that was disabled because that algorithm is not secure.
 certErrorTrust_ExpiredIssuer=The certificate is not trusted because the issuer certificate has expired.
 certErrorTrust_Untrusted=The certificate does not come from a trusted source.
 certErrorTrust_MitM=Your connection is being intercepted by a TLS proxy. Uninstall it if possible or configure your device to trust its root certificate.
 # LOCALIZATION NOTE (certErrorTrust_Symantec): %S is replaced by the domain for which the certificate is valid
 certErrorTrust_Symantec=The security certificate for %S is not trustworthy because the issuing organization failed to follow security practices. Certificates issued by Symantec, including the Thawte, GeoTrust, and RapidSSL brands, are not considered safe.
 
 certErrorMismatch=The certificate is not valid for the name %S.
-# LOCALIZATION NOTE (certErrorMismatch1, certErrorMismatchSinglePrefix1, certErrorMismatchMultiple1): %1$S is replaced by the brand name, %2$S is replaced by host name.
-certErrorMismatch1=Websites prove their identity via security certificates. %1$S does not trust %2$S because it uses a security certificate that is not valid for %2$S.
+# LOCALIZATION NOTE (certErrorMismatch2, certErrorMismatchSinglePrefix2, certErrorMismatchMultiple2): %1$S is replaced by the brand name, %2$S is replaced by host name.
+certErrorMismatch2=Websites prove their identity via certificates. %1$S does not trust %2$S because it uses a security certificate that is not valid for %2$S.
 # LOCALIZATION NOTE (certErrorMismatchSinglePrefix): %S is replaced by the domain for which the certificate is valid
 certErrorMismatchSinglePrefix=The certificate is only valid for %S.
-# LOCALIZATION NOTE (certErrorMismatchSinglePrefix1): %3$S is replaced by the domain for which the certificate is valid
-certErrorMismatchSinglePrefix1=Websites prove their identity via security certificates. %1$S does not trust %2$S because it uses a security certificate that is not valid for %2$S.
+# LOCALIZATION NOTE (certErrorMismatchSinglePrefix2): %3$S is replaced by the domain for which the certificate is valid
+certErrorMismatchSinglePrefix2=Websites prove their identity via certificates. %1$S does not trust %2$S because it uses a security certificate that is not valid for %2$S.
 certErrorMismatchMultiple=The certificate is only valid for the following names:
-certErrorMismatchMultiple1=Websites prove their identity via security certificates. %1$S does not trust %2$S because it uses a security certificate that is not valid for %2$S. The certificate is only valid for the following names:
+certErrorMismatchMultiple2=Websites prove their identity via certificates. %1$S does not trust %2$S because it uses a security certificate that is not valid for %2$S. The certificate is only valid for the following names:
 
 # LOCALIZATION NOTE (certErrorExpiredNow): Do not translate %1$S (date+time of expired certificate) or %2$S (current date+time)
 certErrorExpiredNow=The certificate expired on %1$S. The current time is %2$S.
-certErrorExpiredNow1=Websites prove their identity via security certificates, which are valid for a set time period. The security certificate for %S appears to be expired.
+certErrorExpiredNow2=Websites prove their identity via certificates, which are valid for a set time period. The security certificate for %S appears to be expired.
 
 # LOCALIZATION NOTE (certErrorNotYetValidNow): Do not translate %1$S (date+time certificate will become valid) or %2$S (current date+time)
 certErrorNotYetValidNow=The certificate will not be valid until %1$S. The current time is %2$S.
-certErrorNotYetValidNow1=Websites prove their identity via security certificates, which are valid for a set time period. The security certificate for %S appears to be not yet valid.
+certErrorNotYetValidNow2=Websites prove their identity via certificates, which are valid for a set time period. The security certificate for %S appears to be not yet valid.
 
 # LOCALIZATION NOTE (certErrorSymantecDistrustDescription): %S will be replaced by the domain for which the certificate is valid.
 certErrorSymantecDistrustDescription=Websites prove their identity via certificates, which are issued by certificate authorities. Most browsers will no longer trust Symantec, the certificate authority for %S.
 certErrorSymantecDistrustAdministrator=You may notify the website’s administrator about this problem.
 
 # LOCALIZATION NOTE (certErrorCodePrefix3): %S is replaced by the error code.
 certErrorCodePrefix3=Error code: %S
 
--- a/taskcluster/ci/test/web-platform.yml
+++ b/taskcluster/ci/test/web-platform.yml
@@ -138,16 +138,20 @@ web-platform-tests-wdspec:
         by-test-platform:
             linux64-qr/.*: ['release', 'try']  # skip on integration branches due to high load
             default: built-projects
     tier:
         by-test-platform:
             linux64-asan/opt: 2
             linux64-qr/.*: 2  # can't be tier-1 if it's not running on integration branches
             default: default
+    chunks:
+        by-test-platform:
+            linux64-ccov/.*: 2
+            default: 1
 
 web-platform-tests-wdspec-headless:
     description: "Web platform webdriver-spec headless run"
     suite: web-platform-tests-wdspec
     treeherder-symbol: W(WdH)
     run-on-projects: []  # disabled pending releng approval
     mozharness:
         extra-options:
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -20,16 +20,19 @@ var EXPORTED_SYMBOLS = [
 ];
 
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 ChromeUtils.import("resource://testing-common/ContentTask.jsm");
 
+ChromeUtils.defineModuleGetter(this, "BrowserWindowTracker",
+  "resource:///modules/BrowserWindowTracker.jsm");
+
 Services
   .mm
   .loadFrameScript(
     "chrome://mochikit/content/tests/BrowserTestUtils/content-utils.js", true);
 
 ChromeUtils.defineModuleGetter(this, "E10SUtils",
   "resource://gre/modules/E10SUtils.jsm");
 
@@ -696,80 +699,46 @@ var BrowserTestUtils = {
           resolve(subject.QueryInterface(Ci.nsIDOMWindow));
         }
       }
       Services.ww.registerNotification(observer);
     });
   },
 
   /**
-   * @param {Object} options
-   *        {
-   *          private: A boolean indicating if the window should be
-   *                   private
-   *          remote:  A boolean indicating if the window should run
-   *                   remote browser tabs or not. If omitted, the window
-   *                   will choose the profile default state.
-   *          width: Desired width of window
-   *          height: Desired height of window
-   *        }
+   * Open a new browser window from an existing one.
+   * This relies on OpenBrowserWindow in browser.js, and waits for the window
+   * to be completely loaded before resolving.
+   *
+   * @param {Object}
+   *        Options to pass to OpenBrowserWindow. Additionally, supports:
+   *        - waitForTabURL
+   *          Forces the initial browserLoaded check to wait for the tab to
+   *          load the given URL (instead of about:blank)
+   *
    * @return {Promise}
    *         Resolves with the new window once it is loaded.
    */
   async openNewBrowserWindow(options = {}) {
-    let argString = Cc["@mozilla.org/supports-string;1"].
-                    createInstance(Ci.nsISupportsString);
-    argString.data = "";
-    let features = "chrome,dialog=no,all";
-    let opener = null;
-
-    if (options.opener) {
-      opener = options.opener;
-    }
-
-    if (options.private) {
-      features += ",private";
-    }
-
-    if (options.width) {
-      features += ",width=" + options.width;
-    }
-    if (options.height) {
-      features += ",height=" + options.height;
+    let currentWin = BrowserWindowTracker.getTopWindow({private: false});
+    if (!currentWin) {
+      throw new Error("Can't open a new browser window from this helper if no non-private window is open.");
     }
-
-    if (options.left) {
-      features += ",left=" + options.left;
-    }
-
-    if (options.top) {
-      features += ",top=" + options.top;
-    }
-
-    if (options.hasOwnProperty("remote")) {
-      let remoteState = options.remote ? "remote" : "non-remote";
-      features += `,${remoteState}`;
-    }
-
-    if (options.url) {
-      argString.data = options.url;
-    }
-
-    let win = Services.ww.openWindow(
-      opener, AppConstants.BROWSER_CHROME_URL, "_blank",
-      features, argString);
+    let win = currentWin.OpenBrowserWindow(options);
 
     // Wait for browser-delayed-startup-finished notification, it indicates
     // that the window has loaded completely and is ready to be used for
     // testing.
     let startupPromise =
       TestUtils.topicObserved("browser-delayed-startup-finished",
                               subject => subject == win).then(() => win);
 
-    let loadPromise = this.firstBrowserLoaded(win);
+    let loadPromise = this.firstBrowserLoaded(win, !options.waitForTabURL, browser => {
+      return !options.waitForTabURL || options.waitForTabURL == browser.currentURI.spec;
+    });
 
     await startupPromise;
     await loadPromise;
 
     return win;
   },
 
   /**
--- a/testing/profiles/unittest/user.js
+++ b/testing/profiles/unittest/user.js
@@ -58,17 +58,17 @@ user_pref("browser.tabs.delayHidingAudio
 // Don't allow background tabs to be zombified, otherwise for tests that
 // open additional tabs, the test harness tab itself might get unloaded.
 user_pref("browser.tabs.disableBackgroundZombification", true);
 // Don't use auto-enabled e10s
 user_pref("browser.tabs.remote.autostart", false);
 // Make sure Translation won't hit the network.
 user_pref("browser.translation.bing.authURL", "http://{server}/browser/browser/components/translation/test/bing.sjs");
 user_pref("browser.translation.bing.translateArrayURL", "http://{server}/browser/browser/components/translation/test/bing.sjs");
-user_pref("browser.translation.engine", "bing");
+user_pref("browser.translation.engine", "Bing");
 user_pref("browser.translation.yandex.translateURLOverride", "http://{server}/browser/browser/components/translation/test/yandex.sjs");
 user_pref("browser.ui.layout.tablet", 0); // force tablet UI off
 // Ensure UITour won't hit the network
 user_pref("browser.uitour.pinnedTabUrl", "http://{server}/uitour-dummy/pinnedTab");
 user_pref("browser.uitour.url", "http://{server}/uitour-dummy/tour");
 user_pref("browser.urlbar.speculativeConnect.enabled", false);
 // Turn off search suggestions in the location bar so as not to trigger network
 // connections.
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -185102,16 +185102,28 @@
       [
        "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-vertical-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering.html": [
+    [
+     "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering.html",
+     [
+      [
+       "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-float.html": [
     [
      "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-float.html",
      [
       [
        "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-float-ref.html",
        "=="
       ]
@@ -285834,16 +285846,21 @@
      {}
     ]
    ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-vertical-ref.html": [
     [
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering-ref.html": [
+    [
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-dynamic-update.html": [
     [
      {}
     ]
    ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-float-ref.html": [
     [
      {}
@@ -356679,16 +356696,22 @@
     ]
    ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-formatting-context.html": [
     [
      "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-formatting-context.html",
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none.html": [
+    [
+     "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none.html",
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display.html": [
     [
      "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display.html",
      {}
     ]
    ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-float-abspos.html": [
     [
@@ -365851,16 +365874,22 @@
     ]
    ],
    "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html": [
     [
      "/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html",
      {}
     ]
    ],
+   "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js": [
+    [
+     "/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.html",
+     {}
+    ]
+   ],
    "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js": [
     [
      "/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.html",
      {}
     ]
    ],
    "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js": [
     [
@@ -394103,34 +394132,40 @@
     ]
    ],
    "trusted-types/Range-createContextualFragment.tentative.html": [
     [
      "/trusted-types/Range-createContextualFragment.tentative.html",
      {}
     ]
    ],
-   "trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html": [
-    [
-     "/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html",
+   "trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html": [
+    [
+     "/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html",
+     {}
+    ]
+   ],
+   "trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html": [
+    [
+     "/trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html",
+     {}
+    ]
+   ],
+   "trusted-types/Window-TrustedTypes.tentative.html": [
+    [
+     "/trusted-types/Window-TrustedTypes.tentative.html",
      {}
     ]
    ],
    "trusted-types/Window-open.tentative.html": [
     [
      "/trusted-types/Window-open.tentative.html",
      {}
     ]
    ],
-   "trusted-types/Window-trustedTypes.tentative.html": [
-    [
-     "/trusted-types/Window-trustedTypes.tentative.html",
-     {}
-    ]
-   ],
    "trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html": [
     [
      "/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html",
      {}
     ]
    ],
    "trusted-types/block-string-assignment-to-Document-write.tentative.html": [
     [
@@ -599448,16 +599483,28 @@
   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-align.html": [
    "f7511c9e4c91dbd2cb11db502789d8792f038a29",
    "testharness"
   ],
   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-formatting-context.html": [
    "4e9539179739a3690aab276f2ba98c25bd4dfe9b",
    "testharness"
   ],
+  "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering-ref.html": [
+   "e6eff47e53c7a40e973b7f9dc298af2343f59941",
+   "support"
+  ],
+  "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering.html": [
+   "abf3c45df71ee6617ddb8b6d402a103f54624820",
+   "reftest"
+  ],
+  "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none.html": [
+   "689454ac493a05b28658edf549d71c6aa1c7be0e",
+   "testharness"
+  ],
   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display.html": [
    "914547fc6cdde3e464b28eb7cc9737d17305f9af",
    "testharness"
   ],
   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-dynamic-update.html": [
    "5dc68244fe0f896388ce7a0ff9d8f49397395078",
    "support"
   ],
@@ -608316,16 +608363,20 @@
   "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html": [
    "118be71af19c88d5fed0a1efe010bbd6868eae9c",
    "testharness"
   ],
   "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html": [
    "5e5ca80781809cc509a8eade7ea91e74de92f9a8",
    "testharness"
   ],
+  "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js": [
+   "0ff0bb99443677b8f8844c8ecedef22c408f2bac",
+   "testharness"
+  ],
   "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js": [
    "d6ff9dc7a45425cb688ed4b6c9ea2ab5c1c3ae5c",
    "testharness"
   ],
   "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html": [
    "d5535630be05ddb466814c503ab086d7176ecbda",
    "support"
   ],
@@ -620537,21 +620588,21 @@
    "b100058cf9237e64d9e4319e3d639c00cf07633e",
    "testharness"
   ],
   "payment-request/allowpaymentrequest/basic.https.html": [
    "80a6a2279d72452611d0a009d017e6b24c6acbbe",
    "testharness"
   ],
   "payment-request/allowpaymentrequest/common.sub.js": [
-   "85a08461fcb0197ed2259d77035e696c1c69d6d8",
+   "a94bac064c9432980d437a98b72d4843f1b40bbe",
    "support"
   ],
   "payment-request/allowpaymentrequest/echo-PaymentRequest.html": [
-   "f18b16ee31bf7e3eb868d073ab5e0fb0061bbd88",
+   "5211c7e5ce78c0621036578fef79aeb2c98f2a27",
    "support"
   ],
   "payment-request/allowpaymentrequest/no-attribute-cross-origin-bc-containers.https.html": [
    "6919a54e2d2fabdb771a728e636ecdf673862145",
    "testharness"
   ],
   "payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https.html": [
    "ea3773ba7b6fc07d874d16355989833ffd2c66c7",
@@ -646973,109 +647024,113 @@
    "f4bc0467db8a215fa85fb7e1c483b3d99a458ef7",
    "support"
   ],
   "touch-events/touch-touchevent-constructor.html": [
    "15b2db735fd0d7a01d9e9bd3a1f3719f790d62e5",
    "testharness"
   ],
   "trusted-types/DOMParser-parseFromString.tentative.html": [
-   "2fe9b31b787e1fb458a3ed8996b2d79f7e14aa35",
+   "2dfc37686bca15431c216a50d29f9f9eed2782e0",
    "testharness"
   ],
   "trusted-types/Document-write.tentative.html": [
-   "3a63e923543b999b05d1fab926ad33d7d2719dfa",
+   "79247fb4d68e6724b98c62d3b62a0e6b20784f4d",
    "testharness"
   ],
   "trusted-types/Element-insertAdjacentHTML.tentative.html": [
-   "599ade44ec117ecb429659a9f969a2767bd95cbb",
+   "d5db7936b1f98012ee3750f6d3056f4a5b172615",
    "testharness"
   ],
   "trusted-types/Element-outerHTML.tentative.html": [
-   "a0bb6c1a5e3fef47e4351353befbfc8eb105652f",
+   "c8daddfe9955196bf0b69410263cb7c01e473e5e",
    "testharness"
   ],
   "trusted-types/HTMLElement-generic.tentative.html": [
-   "cea32a5a2df1d9b255f5aaf85ac5a694fdb3a618",
+   "08d165a75d4185a61374128be8046384cc701b4e",
    "testharness"
   ],
   "trusted-types/Location-assign.tentative.html": [
-   "13cca5679488d0b3e12631d5f70408565ea1b065",
+   "62f98e96d7febe6c744b882f8d196d1686fe9166",
    "testharness"
   ],
   "trusted-types/Location-href.tentative.html": [
-   "d759d28593e67f25d8bc28d36cf0ff4912460dc0",
+   "bacadf6a91b1c0bc5c76293aab38f9d503cfa2b7",
    "testharness"
   ],
   "trusted-types/Location-replace.tentative.html": [
-   "7d84905d19878d57634a8497b81ef86d8114b72e",
+   "4fb53d0260973ed5d714540a448909488b6e2465",
    "testharness"
   ],
   "trusted-types/META.yml": [
    "d0743949b6a122d8bd0adf7b1ed0181f0c51429d",
    "support"
   ],
   "trusted-types/Range-createContextualFragment.tentative.html": [
-   "3d45b33486d3971c0c58180fa4034dbfae18f135",
-   "testharness"
-  ],
-  "trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html": [
-   "76e6d130b05dfba00911ad42eb7a162cd29b222e",
+   "3a880a53778acb165fd5d957eeaca22685baf2b5",
+   "testharness"
+  ],
+  "trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html": [
+   "b20fcf2436eac17f9f558cab0c80d1eced6bb1be",
+   "testharness"
+  ],
+  "trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html": [
+   "6d43e0bafc61f34c17d7d7b751bf69f12d035adf",
+   "testharness"
+  ],
+  "trusted-types/Window-TrustedTypes.tentative.html": [
+   "8e20e492e6a8484e386d1a08f854bd9b162bd6be",
    "testharness"
   ],
   "trusted-types/Window-open.tentative.html": [
-   "c005fbba143f66a9540deebba7988fdea9661558",
-   "testharness"
-  ],
-  "trusted-types/Window-trustedTypes.tentative.html": [
-   "ef4487749dd0c12a00bd3ab42c1353467a6eeb8f",
+   "172d566e57fc635b551b5d355661db690869b220",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html": [
-   "cc575dc0085bce3aa1370fb528e28003ad3c1c2b",
+   "e5959a425a2feafc95deb4f6b8b1372ad5ad1497",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Document-write.tentative.html": [
-   "28813d72e0e1833e25658e2210abb9b0a30b2137",
+   "06532c3b47948c22c5debfae511c5fbd414c64de",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html": [
-   "ad94b44e8fb7621ba4693ad65377872281f3e9a6",
+   "1fb3bbd994a4a6904cfc4609430f9188692eda40",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html": [
-   "47f1165b1a69366848dd5dd21a2ad2199b9c2e81",
+   "abb595222ba5e609cff02adc27a8a7239d44103e",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html": [
-   "eae52626190746ad0a8b436f74981009e400232b",
+   "7b1a5795d7c04448cd204391ba75030a87131150",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Location-assign.tentative.html": [
-   "8079335bc5861fa723691a0f884cf249e6f63e24",
+   "cd375b9d016365f01d8e6f95b50d928520c82afa",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Location-href.tentative.html": [
-   "4e393f92506e00276a4440e1023ac23e7a6138e8",
+   "14fbcb2fb3cdc6f51e957bbb047ba8900f0d0865",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Location-replace.tentative.html": [
-   "872f14e144830ed87b51e352f93c32ce85438bfe",
+   "9d00fcdeb35d36b05adeb7b67f3816169f3ad036",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html": [
-   "2afa2572c350071b791ee280bce0a1e5135dc2aa",
+   "ff9be06251dc7965ad1d765d49e45b4ef9f8d728",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Window-open.tentative.html": [
-   "f5712295d30d7b1d680ad6753dd401d21c0409f9",
+   "ae4b038dc0c67ab828c3531b3ac01e819114f1ed",
    "testharness"
   ],
   "trusted-types/support/helper.sub.js": [
-   "b5435917bec607c97eaa5d75ee7fa2752999cb0a",
+   "617e02aa6badddd36f01f88241ac8ce7d5670597",
    "support"
   ],
   "uievents/META.yml": [
    "2f1ec58efec10e0dd6374aac05cb926c8cffa3f1",
    "support"
   ],
   "uievents/README.md": [
    "065c0c78848af60244a860c2d785fa48c66e5ef5",
@@ -659865,17 +659920,17 @@
    "c23c99788e46dae24009b3c5092efeb5f93b8e1f",
    "testharness"
   ],
   "xhr/timeout-cors-async.htm": [
    "35e2a30ba2f51aaa6b3ba21603869db156decd5b",
    "testharness"
   ],
   "xhr/timeout-multiple-fetches.html": [
-   "30d6b736c56d5576483c12a7413dd809d27d89e8",
+   "4f4998c4285222bf4bdf41c3e0c1c27e913d2149",
    "testharness"
   ],
   "xhr/timeout-sync.htm": [
    "9815532c70ff347199a998f02bf4b11f15c7bcee",
    "testharness"
   ],
   "xhr/xmlhttprequest-basic.htm": [
    "c48b610ff6627af704810740a2dcab23d085764b",
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js.ini
@@ -0,0 +1,13 @@
+[quirks.window.html]
+  [document.open() sets document to no-quirks mode (write no doctype)]
+    expected: FAIL
+
+  [document.open() sets document to no-quirks mode (write old doctype)]
+    expected: FAIL
+
+  [document.open() sets document to no-quirks mode (write new doctype)]
+    expected: FAIL
+
+  [document.open() sets document to no-quirks mode, not limited-quirks mode]
+    expected: FAIL
+
--- a/testing/web-platform/meta/mozilla-sync
+++ b/testing/web-platform/meta/mozilla-sync
@@ -1,2 +1,2 @@
-local: a3acca752946dcc6b1196f588815e8d89dd2a047
-upstream: 3d172bc612e03a896b5611d9e9652f860995feef
+local: c6fdb0456dcc9f12ac413c063f48f36493401dbd
+upstream: 128c48e50cea769df396af8c90c38bc49b620939
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html.ini
@@ -0,0 +1,124 @@
+[TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html]
+  [script = identity function]
+    expected: FAIL
+
+  [html = callback that throws]
+    expected: FAIL
+
+  [script_url - calling undefined callback]
+    expected: FAIL
+
+  [script_url = identity function]
+    expected: FAIL
+
+  [script = identity function, global string changed]
+    expected: FAIL
+
+  [url = this without bind]
+    expected: FAIL
+
+  [script = this without bind]
+    expected: FAIL
+
+  [html = this bound to an object]
+    expected: FAIL
+
+  [url = identity function, global string changed]
+    expected: FAIL
+
+  [url = this bound to an object]
+    expected: FAIL
+
+  [url = identity function]
+    expected: FAIL
+
+  [script_url = identity function, global string changed]
+    expected: FAIL
+
+  [script_url = this bound to an object]
+    expected: FAIL
+
+  [script_url = this without bind]
+    expected: FAIL
+
+  [html = identity function, global string changed]
+    expected: FAIL
+
+  [url = callback that throws]
+    expected: FAIL
+
+  [html = string + global string]
+    expected: FAIL
+
+  [script = this bound to an object]
+    expected: FAIL
+
+  [html = identity function]
+    expected: FAIL
+
+  [script = callback that throws]
+    expected: FAIL
+
+  [html - calling undefined callback]
+    expected: FAIL
+
+  [url - calling undefined callback]
+    expected: FAIL
+
+  [script_url = callback that throws]
+    expected: FAIL
+
+  [script - calling undefined callback]
+    expected: FAIL
+
+  [html = this without bind]
+    expected: FAIL
+
+  [script_url = string + global string]
+    expected: FAIL
+
+  [script = null]
+    expected: FAIL
+
+  [script_url = null]
+    expected: FAIL
+
+  [html = null]
+    expected: FAIL
+
+  [script = string + global string]
+    expected: FAIL
+
+  [url = string + global string]
+    expected: FAIL
+
+  [url = null]
+    expected: FAIL
+
+  [script_url - calling undefined callback throws]
+    expected: FAIL
+
+  [url - calling undefined callback throws]
+    expected: FAIL
+
+  [script - calling undefined callback throws]
+    expected: FAIL
+
+  [policy has createScript, throws when called with createHTML]
+    expected: FAIL
+
+  [html - calling undefined callback throws]
+    expected: FAIL
+
+  [createScript defined - calling undefined callbacks throws]
+    expected: FAIL
+
+  [createScriptURL defined - calling undefined callbacks throws]
+    expected: FAIL
+
+  [createHTML defined - calling undefined callbacks throws]
+    expected: FAIL
+
+  [createURL defined - calling undefined callbacks throws]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html.ini
@@ -0,0 +1,7 @@
+[TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html]
+  [Retrieving policy names]
+    expected: FAIL
+
+  [policy.name = name]
+    expected: FAIL
+
deleted file mode 100644
--- a/testing/web-platform/meta/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html.ini
+++ /dev/null
@@ -1,103 +0,0 @@
-[TrustedTypePolicyFactory-createPolicy.tentative.html]
-  [policy.name = name]
-    expected: FAIL
-
-  [TrustedTypePolicyFactory-createPolicy]
-    expected: FAIL
-
-  [html = callback that throws]
-    expected: FAIL
-
-  [script_url - calling undefined callback]
-    expected: FAIL
-
-  [html - calling undefined callback]
-    expected: FAIL
-
-  [script_url = identity function]
-    expected: FAIL
-
-  [url = this without bind]
-    expected: FAIL
-
-  [html = this bound to an object]
-    expected: FAIL
-
-  [url = identity function, global string changed]
-    expected: FAIL
-
-  [url = this bound to an object]
-    expected: FAIL
-
-  [script_url = identity function, global string changed]
-    expected: FAIL
-
-  [script_url = this bound to an object]
-    expected: FAIL
-
-  [html = identity function, global string changed]
-    expected: FAIL
-
-  [url = callback that throws]
-    expected: FAIL
-
-  [url = identity function]
-    expected: FAIL
-
-  [html = identity function]
-    expected: FAIL
-
-  [script_url = this without bind]
-    expected: FAIL
-
-  [url - calling undefined callback]
-    expected: FAIL
-
-  [script_url = callback that throws]
-    expected: FAIL
-
-  [html = this without bind]
-    expected: FAIL
-
-  [html = string + global string]
-    expected: FAIL
-
-  [script_url = string + global string]
-    expected: FAIL
-
-  [script_url = null]
-    expected: FAIL
-
-  [html = null]
-    expected: FAIL
-
-  [url = string + global string]
-    expected: FAIL
-
-  [url = null]
-    expected: FAIL
-
-  [script = identity function]
-    expected: FAIL
-
-  [script = identity function, global string changed]
-    expected: FAIL
-
-  [script = this without bind]
-    expected: FAIL
-
-  [script = this bound to an object]
-    expected: FAIL
-
-  [script = callback that throws]
-    expected: FAIL
-
-  [script - calling undefined callback]
-    expected: FAIL
-
-  [script = null]
-    expected: FAIL
-
-  [script = string + global string]
-    expected: FAIL
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/trusted-types/Window-TrustedTypes.tentative.html.ini
@@ -0,0 +1,4 @@
+[Window-TrustedTypes.tentative.html]
+  [factory = window.TrustedTypes]
+    expected: FAIL
+
deleted file mode 100644
--- a/testing/web-platform/meta/trusted-types/Window-trustedTypes.tentative.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[Window-trustedTypes.tentative.html]
-  [factory = window.trustedTypes]
-    expected: FAIL
-
-  [Window-trustedTypes]
-    expected: FAIL
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>Reference for Rendering of display: none legend</title>
+<style>
+ div { border: 2em solid lime; width: 0; }
+</style>
+<p>There should be a green box below.</p>
+<div></div>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>Rendering of display: none legend</title>
+<link rel=match href=legend-display-none-rendering-ref.html>
+<style>
+ fieldset { border: 2em solid lime; width: 0; margin: 0; padding: 0; }
+ legend { display: none; background: red; }
+</style>
+<p>There should be a green box below.</p>
+<fieldset>
+ <legend>FAIL</legend>
+</fieldset>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>legend display: none</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<style>
+ legend { display: none; }
+</style>
+<fieldset>
+ <legend>Foo</legend>
+</fieldset>
+<script>
+ test(() => {
+   const display = getComputedStyle(document.querySelector('legend')).display;
+   assert_equals(display, 'none');
+ });
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js
@@ -0,0 +1,74 @@
+test(t => {
+  const frame = document.body.appendChild(document.createElement("iframe"));
+  t.add_cleanup(() => frame.contentDocument.close());
+  assert_equals(frame.contentDocument.compatMode, "BackCompat");
+  frame.contentDocument.open();
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+  frame.contentDocument.close();
+  assert_equals(frame.contentDocument.compatMode, "BackCompat");
+}, "document.open() sets document to no-quirks mode (write no doctype)");
+
+test(t => {
+  const frame = document.body.appendChild(document.createElement("iframe"));
+  t.add_cleanup(() => frame.contentDocument.close());
+  assert_equals(frame.contentDocument.compatMode, "BackCompat");
+  frame.contentDocument.open();
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+  frame.contentDocument.write("<!doctype html public");
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+  frame.contentDocument.write(" \"-//IETF//DTD HTML 3//\"");
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+  frame.contentDocument.write(">");
+  assert_equals(frame.contentDocument.compatMode, "BackCompat");
+  frame.contentDocument.close();
+  assert_equals(frame.contentDocument.compatMode, "BackCompat");
+}, "document.open() sets document to no-quirks mode (write old doctype)");
+
+test(t => {
+  const frame = document.body.appendChild(document.createElement("iframe"));
+  t.add_cleanup(() => frame.contentDocument.close());
+  assert_equals(frame.contentDocument.compatMode, "BackCompat");
+  frame.contentDocument.open();
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+  frame.contentDocument.write("<!doctype html");
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+  frame.contentDocument.write(">");
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+  frame.contentDocument.close();
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+}, "document.open() sets document to no-quirks mode (write new doctype)");
+
+// This tests the document.open() call in fact sets the document to no-quirks
+// mode, not limited-quirks mode. It is derived from
+// quirks/blocks-ignore-line-height.html in WPT, as there is no direct way to
+// distinguish between a no-quirks document and a limited-quirks document. It
+// assumes that the user agent passes the linked test, which at the time of
+// writing is all major web browsers.
+test(t => {
+  const frame = document.body.appendChild(document.createElement("iframe"));
+  t.add_cleanup(() => frame.contentDocument.close());
+  assert_equals(frame.contentDocument.compatMode, "BackCompat");
+  frame.contentDocument.open();
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+
+  // Create the DOM tree manually rather than going through document.write() to
+  // bypass the parser, which resets the document mode.
+  const html = frame.contentDocument.appendChild(frame.contentDocument.createElement("html"));
+  const body = html.appendChild(frame.contentDocument.createElement("body"));
+  assert_equals(frame.contentDocument.body, body);
+  body.innerHTML = `
+    <style>#ref { display:block }</style>
+    <div id=test><font size=1>x</font></div>
+    <font id=ref size=1>x</font>
+    <div id=s_ref>x</div>
+  `;
+  assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+
+  const idTest = frame.contentDocument.getElementById("test");
+  const idRef = frame.contentDocument.getElementById("ref");
+  const idSRef = frame.contentDocument.getElementById("s_ref");
+  assert_equals(frame.contentWindow.getComputedStyle(idTest).height,
+                frame.contentWindow.getComputedStyle(idSRef).height);
+  assert_not_equals(frame.contentWindow.getComputedStyle(idTest).height,
+                    frame.contentWindow.getComputedStyle(idRef).height);
+}, "document.open() sets document to no-quirks mode, not limited-quirks mode");
--- a/testing/web-platform/tests/payment-request/allowpaymentrequest/common.sub.js
+++ b/testing/web-platform/tests/payment-request/allowpaymentrequest/common.sub.js
@@ -1,45 +1,61 @@
 // Test should set these:
 // const expectSuccess = {'iframe': bool, 'frame': bool, 'object': bool, 'embed': bool};
 // const setAllowPaymentRequest = bool;
 // const testCrossOrigin = bool;
 
 const tests = {};
 
-window.onmessage = (e) => {
+window.onmessage = e => {
   const result = e.data;
   const tagName = result.urlQuery;
   const t = tests[tagName];
   t.step(() => {
     if (expectSuccess[tagName]) {
-      assert_equals(result.message, 'Success');
+      assert_equals(result.message, "Success");
+      if (result.message === "Exception") {
+        const [, code, name, stack] = result.details;
+        assert_unreached(`Unexpected exception "${name}" (${code}) ${stack}`);
+      }
     } else {
-      assert_equals(result.message, 'Exception');
-      assert_array_equals(result.details, [true /*ex instanceof DOMException*/,
-                                           DOMException.SECURITY_ERR /*ex.code*/,
-                                           'SecurityError' /*ex.name*/]);
+      assert_equals(result.message, "Exception");
+      const detailsArray = result.details.slice(0,3);
+      assert_array_equals(detailsArray, [
+        true /*ex instanceof DOMException*/,
+        DOMException.SECURITY_ERR /*ex.code*/,
+        "SecurityError" /*ex.name*/,
+      ]);
     }
     t.done();
   });
 };
 
-['iframe', 'frame', 'object', 'embed'].forEach((tagName, i) => {
-  tests[tagName] = async_test((t) => {
+["iframe", "frame", "object", "embed"].forEach((tagName, i) => {
+  tests[tagName] = async_test(t => {
     const elm = document.createElement(tagName);
     if (setAllowPaymentRequest) {
-      elm.setAttribute('allowpaymentrequest', '');
+      elm.setAttribute("allowpaymentrequest", "");
     }
-    const path = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
-    const url = (testCrossOrigin ? "https://{{domains[www1]}}:{{ports[https][0]}}" : "") +
-                path + "echo-PaymentRequest.html?" + tagName;
-    if (tagName === 'object') {
+    const path = location.pathname.substring(
+      0,
+      location.pathname.lastIndexOf("/") + 1
+    );
+    const url =
+      (testCrossOrigin ? "https://{{domains[www1]}}:{{ports[https][0]}}" : "") +
+      path +
+      "echo-PaymentRequest.html?" +
+      tagName;
+    if (tagName === "object") {
       elm.data = url;
     } else {
       elm.src = url;
     }
     elm.onload = t.step_func(() => {
-      window[i].postMessage('What is the result of new PaymentRequest(...)?', '*');
+      window[i].postMessage(
+        "What is the result of new PaymentRequest(...)?",
+        "*"
+      );
     });
-    elm.onerror = t.unreached_func('elm.onerror');
+    elm.onerror = t.unreached_func("elm.onerror");
     document.body.appendChild(elm);
   }, tagName);
 });
--- a/testing/web-platform/tests/payment-request/allowpaymentrequest/echo-PaymentRequest.html
+++ b/testing/web-platform/tests/payment-request/allowpaymentrequest/echo-PaymentRequest.html
@@ -6,17 +6,19 @@ window.onmessage = (e) => {
   if (e.data === 'What is the result of new PaymentRequest(...)?') {
     const result = {urlQuery: location.search.substring(1)}; // Used to distinguish subtests
     try {
       new PaymentRequest(...paymentArgs);
       result.message = 'Success';
       e.source.postMessage(result, '*');
     } catch(ex) {
       result.message = 'Exception';
-      result.details = [ex instanceof DOMException, ex.code, ex.name];
+      const isDomException = ex instanceof DOMException;
+      const stack = "stack" in ex ? ex.stack : "";
+      result.details = [ isDomException, ex.code, ex.name, stack ];
       e.source.postMessage(result, '*');
     }
   } else {
     result.message = 'Incorrect message';
     e.source.postMessage(result, '*');
   }
 }
 </script>
--- a/testing/web-platform/tests/trusted-types/DOMParser-parseFromString.tentative.html
+++ b/testing/web-platform/tests/trusted-types/DOMParser-parseFromString.tentative.html
@@ -1,22 +1,20 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <script>
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
-        let parser = new DOMParser();
-        let doc = parser.parseFromString(html, "text/html");
-        assert_equals(doc.body.innerText, RESULTS.HTML);
-    }));
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
+    let parser = new DOMParser();
+    let doc = parser.parseFromString(html, "text/html");
+    assert_equals(doc.body.innerText, RESULTS.HTML);
   }, "document.innerText assigned via policy (successful HTML transformation).");
 
   test(t => {
     var parser = new DOMParser();
     var doc = parser.parseFromString(null, "text/html");
     assert_equals(doc.body.innerText, "null");
   }, "document.innerText = null.");
 </script>
--- a/testing/web-platform/tests/trusted-types/Document-write.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Document-write.tentative.html
@@ -1,15 +1,13 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <script>
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
-        document.write(html);
-        assert_equals(document.body.innerText, RESULTS.HTML);
-    }));
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
+    document.write(html);
+    assert_equals(document.body.innerText, RESULTS.HTML);
   }, "document.write with html assigned via policy (successful URL transformation).");
 </script>
--- a/testing/web-platform/tests/trusted-types/Element-insertAdjacentHTML.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Element-insertAdjacentHTML.tentative.html
@@ -2,37 +2,35 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <div id="container"></div>
 <script>
   var container = document.querySelector('#container');
 
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
 
-        var d = document.createElement('div');
-        container.appendChild(d);
+    var d = document.createElement('div');
+    container.appendChild(d);
 
-        d.insertAdjacentHTML('beforebegin', html);
-        assert_equals(d.previousSibling.nodeType, Node.TEXT_NODE);
-        assert_equals(d.previousSibling.data, RESULTS.HTML);
+    d.insertAdjacentHTML('beforebegin', html);
+    assert_equals(d.previousSibling.nodeType, Node.TEXT_NODE);
+    assert_equals(d.previousSibling.data, RESULTS.HTML);
 
-        d.insertAdjacentHTML('afterbegin', html);
-        assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
-        assert_equals(d.firstChild.data, RESULTS.HTML);
-
-        d.insertAdjacentHTML('beforeend', html);
-        assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
-        assert_equals(d.lastChild.data, RESULTS.HTML);
+    d.insertAdjacentHTML('afterbegin', html);
+    assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
+    assert_equals(d.firstChild.data, RESULTS.HTML);
 
-        d.insertAdjacentHTML('afterend', html);
-        assert_equals(d.nextSibling.nodeType, Node.TEXT_NODE);
-        assert_equals(d.nextSibling.data, RESULTS.HTML);
+    d.insertAdjacentHTML('beforeend', html);
+    assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
+    assert_equals(d.lastChild.data, RESULTS.HTML);
 
-        while (container.firstChild)
-          container.firstChild.remove();
-    }));
+    d.insertAdjacentHTML('afterend', html);
+    assert_equals(d.nextSibling.nodeType, Node.TEXT_NODE);
+    assert_equals(d.nextSibling.data, RESULTS.HTML);
+
+    while (container.firstChild)
+      container.firstChild.remove();
   }, "insertAdjacentHTML with html assigned via policy (successful HTML transformation).");
 </script>
--- a/testing/web-platform/tests/trusted-types/Element-outerHTML.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Element-outerHTML.tentative.html
@@ -1,24 +1,22 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <div id="container"></div>
 <script>
-  var container = document.querySelector('#container')
+  var container = document.querySelector('#container');
 
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
 
-        var d = document.createElement('div');
-        document.querySelector('#container').appendChild(d);
-        d.outerHTML = html;
-        assert_equals(container.innerText, RESULTS.HTML);
+    var d = document.createElement('div');
+    document.querySelector('#container').appendChild(d);
+    d.outerHTML = html;
+    assert_equals(container.innerText, RESULTS.HTML);
 
-        while (container.firstChild)
-          container.firstChild.remove();
-    }));
+    while (container.firstChild)
+      container.firstChild.remove();
   }, "outerHTML with html assigned via policy (successful HTML transformation).");
 </script>
--- a/testing/web-platform/tests/trusted-types/HTMLElement-generic.tentative.html
+++ b/testing/web-platform/tests/trusted-types/HTMLElement-generic.tentative.html
@@ -19,37 +19,37 @@
     [ 'video', 'src' ],
     [ 'object', 'data' ],
     [ 'object', 'codeBase' ],
     [ 'source', 'src' ],
     [ 'track', 'src' ]
   ];
 
   testCases.forEach(c => {
-    async_test(t => {
-      assert_element_accepts_trusted_url(window, t, c[0], c[1], RESULTS.URL);
+    test(t => {
+      assert_element_accepts_trusted_url(window, c, t, c[0], c[1], RESULTS.URL);
     }, c[0] + "." + c[1] + " assigned via policy (successful URL transformation)");
   });
 
   // TrustedScriptURL Assignments
   let scriptTestCases = [
     [ 'embed', 'src' ],
     [ 'script', 'src' ]
   ];
 
   scriptTestCases.forEach(c => {
-    async_test(t => {
-      assert_element_accepts_trusted_script_url(window, t, c[0], c[1], RESULTS.SCRIPTURL);
+    test(t => {
+      assert_element_accepts_trusted_script_url(window, c, t, c[0], c[1], RESULTS.SCRIPTURL);
     }, c[0] + "." + c[1] + " assigned via policy (successful ScriptURL transformation)");
   });
 
   // TrustedHTML Assignments
   let HTMLTestCases = [
     [ 'div', 'innerHTML' ],
     [ 'iframe', 'srcdoc' ]
   ];
 
   HTMLTestCases.forEach(c => {
-    async_test(t => {
-      assert_element_accepts_trusted_html(window, t, c[0], c[1], RESULTS.HTML);
+    test(t => {
+      assert_element_accepts_trusted_html(window, c, t, c[0], c[1], RESULTS.HTML);
     }, c[0] + "." + c[1] + " assigned via policy (successful HTML transformation)");
   });
 </script>
--- a/testing/web-platform/tests/trusted-types/Location-assign.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Location-assign.tentative.html
@@ -1,15 +1,13 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <script>
-  async_test(t => {
-    createURL_policy(window)
-        .then(t.step_func_done(p => {
-          let url = p.createURL(location.href + "#xxx");
-          location.assign(url);
-          assert_equals("" + url, location.href, "location href");
-    }));
+  test(t => {
+    let p = createURL_policy(window, 1);
+    let url = p.createURL(location.href + "#xxx");
+    location.assign(url);
+    assert_equals("" + url, location.href, "location href");
   }, "location.assign via policy (successful URL transformation).");
 </script>
--- a/testing/web-platform/tests/trusted-types/Location-href.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Location-href.tentative.html
@@ -1,15 +1,13 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <script>
-  async_test(t => {
-    createURL_policy(window)
-      .then(t.step_func_done(p => {
-        let url = p.createURL(location.href + "#xxx");
-        location.href = url;
-        assert_equals("" + url, location.href, "location href");
-    }));
+  test(t => {
+    let p = createURL_policy(window, 1);
+    let url = p.createURL(location.href + "#xxx");
+    location.href = url;
+    assert_equals("" + url, location.href, "location href");
   }, "location.href assigned via policy (successful URL transformation).");
 </script>
--- a/testing/web-platform/tests/trusted-types/Location-replace.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Location-replace.tentative.html
@@ -1,15 +1,13 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <script>
-  async_test(t => {
-    createURL_policy(window)
-        .then(t.step_func_done(p => {
-          let url = p.createURL(location.href + "#xxx");
-          location.replace(url);
-          assert_equals("" + url, location.href, "location href");
-    }));
+  test(t => {
+    let p = createURL_policy(window, 1);
+    let url = p.createURL(location.href + "#xxx");
+    location.replace(url);
+    assert_equals("" + url, location.href, "location href");
   }, "location.replace via policy (successful URL transformation).");
 </script>
--- a/testing/web-platform/tests/trusted-types/Range-createContextualFragment.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Range-createContextualFragment.tentative.html
@@ -1,17 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <script>
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
-        var range = document.createRange();
-        range.selectNodeContents(document.documentElement);
-        var result = range.createContextualFragment(html);
-        assert_equals(result.textContent, RESULTS.HTML);
-    }));
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
+    var range = document.createRange();
+    range.selectNodeContents(document.documentElement);
+    var result = range.createContextualFragment(html);
+    assert_equals(result.textContent, RESULTS.HTML);
   }, "range.createContextualFragment assigned via policy (successful HTML transformation).");
 </script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html
@@ -0,0 +1,294 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js" ></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+<body>
+<script>
+  //HTML tests
+  function createHTMLTest(policyName, policy, expectedHTML, t) {
+    let p = window.TrustedTypes.createPolicy(policyName, policy);
+    assert_true(p.createHTML('whatever') instanceof TrustedHTML);
+    assert_equals(p.createHTML('whatever') + "", expectedHTML);
+  }
+
+  test(t => {
+    createHTMLTest('TestPolicyHTML1', { createHTML: s => s }, 'whatever', t);
+  }, "html = identity function");
+
+  test(t => {
+    createHTMLTest('TestPolicyHTML2', { createHTML: s => null }, "null", t);
+  }, "html = null");
+
+  var HTMLstr = 'well, ';
+  test(t => {
+    createHTMLTest('TestPolicyHTML3', { createHTML: s => HTMLstr + s }, HTMLstr + 'whatever', t);
+  }, "html = string + global string");
+
+  var HTMLx = 'global';
+  test(t => {
+    createHTMLTest('TestPolicyHTML4', { createHTML: s => { HTMLx = s; return s; } }, 'whatever', t);
+    assert_equals(HTMLx, 'whatever');
+  }, "html = identity function, global string changed");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyHTML5', { createHTML: s => { throw new Error(); }});
+    assert_throws(new Error(), _ => {
+      p.createHTML('whatever');
+    });
+  }, "html = callback that throws");
+
+  var obj = {
+    "foo": "well,"
+  }
+
+  function getHTML(s) {
+    return this.foo + " " + s;
+  }
+
+  test(t => {
+    createHTMLTest('TestPolicyHTML6', { createHTML: getHTML.bind(obj) }, 'well, whatever', t);
+  }, "html = this bound to an object");
+
+  var foo = "well,";
+  test(t => {
+    createHTMLTest('TestPolicyHTML7', { createHTML: s => getHTML(s) }, 'well, whatever', t);
+  }, "html = this without bind");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyHTML8', null);
+    assert_throws(new TypeError(), _ => {
+      p.createHTML('whatever');
+    });
+  }, "html - calling undefined callback throws");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyHTML9', { createHTML: createHTMLJS });
+    assert_throws(new TypeError(), _ => {
+      p.createScript(INPUTS.SCRIPT);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createScriptURL(INPUTS.SCRIPTURL);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createURL(INPUTS.URL);
+    });
+  }, "createHTML defined - calling undefined callbacks throws");
+
+  //Script tests
+  function createScriptTest(policyName, policy, expectedScript, t) {
+    let p = window.TrustedTypes.createPolicy(policyName, policy);
+    assert_true(p.createScript('whatever') instanceof TrustedScript);
+    assert_equals(p.createScript('whatever') + "", expectedScript);
+  }
+
+  test(t => {
+    createScriptTest('TestPolicyScript1', { createScript: s => s }, 'whatever', t);
+  }, "script = identity function");
+
+  test(t => {
+    createScriptTest('TestPolicyScript2', { createScript: s => null }, "null", t);
+  }, "script = null");
+
+  var Scriptstr = 'well, ';
+  test(t => {
+    createScriptTest('TestPolicyScript3', { createScript: s => Scriptstr + s }, Scriptstr + 'whatever', t);
+  }, "script = string + global string");
+
+  var Scriptx = 'global';
+  test(t => {
+    createScriptTest('TestPolicyScript4', { createScript: s => { Scriptx = s; return s; } }, 'whatever', t);
+    assert_equals(Scriptx, 'whatever');
+  }, "script = identity function, global string changed");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyScript5', {
+      createScript: s => { throw new Error(); }
+    });
+    assert_throws(new Error(), _ => {
+      p.createScript('whatever');
+    });
+  }, "script = callback that throws");
+
+  var obj = {
+    "foo": "well,"
+  }
+
+  function getScript(s) {
+    return this.foo + " " + s;
+  }
+
+  test(t => {
+    createScriptTest('TestPolicyScript6', { createScript: getScript.bind(obj) }, 'well, whatever', t);
+  }, "script = this bound to an object");
+
+  var foo = "well,";
+  test(t => {
+    createScriptTest('TestPolicyScript7', { createScript: s => getScript(s) }, 'well, whatever', t);
+  }, "script = this without bind");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyScript8', null);
+    assert_throws(new TypeError(), _ => {
+      p.createScript('whatever');
+    });
+  }, "script - calling undefined callback throws");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyScript9', { createScript: createScriptJS });
+    assert_throws(new TypeError(), _ => {
+      p.createHTML(INPUTS.HTML);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createScriptURL(INPUTS.SCRIPTURL);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createURL(INPUTS.URL);
+    });
+  }, "createScript defined - calling undefined callbacks throws");
+
+
+  //ScriptURL tests
+  function createScriptURLTest(policyName, policy, expectedScriptURL, t) {
+    let p = window.TrustedTypes.createPolicy(policyName, policy);
+    assert_true(p.createScriptURL(INPUTS.SCRIPTURL) instanceof TrustedScriptURL);
+    assert_equals(p.createScriptURL(INPUTS.SCRIPTURL) + "", expectedScriptURL);
+  }
+
+  test(t => {
+    createScriptURLTest('TestPolicyScriptURL1', { createScriptURL: s => s }, INPUTS.SCRIPTURL, t);
+  }, "script_url = identity function");
+
+  test(t => {
+    createScriptURLTest('TestPolicyScriptURL2', { createScriptURL: s => null }, "", t);
+  }, "script_url = null");
+
+  var scriptURLstr = '#duck';
+  test(t => {
+    createScriptURLTest('TestPolicyScriptURL3', { createScriptURL: s => s + scriptURLstr }, INPUTS.SCRIPTURL + scriptURLstr, t);
+  }, "script_url = string + global string");
+
+  var scriptURLx = 'global';
+  test(t => {
+    createScriptURLTest('TestPolicyScriptURL4', { createScriptURL: s => { ScriptURLx = s; return s; } }, INPUTS.SCRIPTURL, t);
+    assert_equals(ScriptURLx, INPUTS.SCRIPTURL);
+  }, "script_url = identity function, global string changed");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyScriptURL5', {
+      createScriptURL: s => { throw new Error(); }
+    });
+    assert_throws(new Error(), _ => {
+      p.createScriptURL(INPUTS.SCRIPTURL);
+    });
+  }, "script_url = callback that throws");
+
+  function getScriptURL(s) {
+    return s + this.baz;
+  }
+
+  var obj = {
+    "baz": "#duck"
+  }
+
+  test(t => {
+    createScriptURLTest('TestPolicyScriptURL6', { createScriptURL: getScriptURL.bind(obj) }, INPUTS.SCRIPTURL + "#duck", t);
+  }, "script_url = this bound to an object");
+
+  var baz = "#duck";
+  test(t => {
+    createScriptURLTest('TestPolicyScriptURL7', { createScriptURL: s => getScriptURL(s) }, INPUTS.SCRIPTURL + baz, t);
+  }, "script_url = this without bind");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyScriptURL8', null);
+    assert_throws(new TypeError(), _ => {
+      p.createScriptURL(INPUTS.SCRIPTURL);
+    });
+  }, "script_url - calling undefined callback throws");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyScriptURL9', { createScriptURL: createScriptURLJS });
+    assert_throws(new TypeError(), _ => {
+      p.createHTML(INPUTS.HTML);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createScript(INPUTS.SCRIPT);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createURL(INPUTS.URL);
+    });
+  }, "createScriptURL defined - calling undefined callbacks throws");
+
+
+  //URL tests
+  function createURLTest(policyName, policy, expectedURL, t) {
+    let p = window.TrustedTypes.createPolicy(policyName, policy);
+    assert_true(p.createURL(INPUTS.URL) instanceof TrustedURL);
+    assert_equals(p.createURL(INPUTS.URL) + "", expectedURL);
+  }
+
+  test(t => {
+    createURLTest('TestPolicyURL1', { createURL: s => s }, INPUTS.URL, t);
+  }, "url = identity function");
+
+  test(t => {
+    createURLTest('TestPolicyURL2', { createURL: s => null }, "", t);
+  }, "url = null");
+
+  var URLstr = '#x';
+  test(t => {
+    createURLTest('TestPolicyURL3', { createURL: s => s + URLstr }, INPUTS.URL + URLstr, t);
+  }, "url = string + global string");
+
+  var URLx = 'global';
+  test(t => {
+    createURLTest('TestPolicyURL4', { createURL: s => { URLx = s; return s; } }, INPUTS.URL, t);
+    assert_equals(URLx, INPUTS.URL);
+  }, "url = identity function, global string changed");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyURL5', {
+      createURL: s => { throw new Error(); }
+    });
+    assert_throws(new Error(), _ => {
+      p.createURL(INPUTS.URL);
+    });
+  }, "url = callback that throws");
+
+  function getURL(s) {
+    return s + this.bar;
+  }
+
+  var obj = {
+    "bar": "#x"
+  }
+
+  test(t => {
+    createURLTest('TestPolicyURL6', { createURL: getURL.bind(obj) }, INPUTS.URL + "#x", t);
+  }, "url = this bound to an object");
+
+  var bar = "#x";
+  test(t => {
+    createURLTest('TestPolicyURL7', { createURL: s => getURL(s) }, INPUTS.URL + bar, t);
+  }, "url = this without bind");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyURL8', null);
+    assert_throws(new TypeError(), _ => {
+      p.createURL(INPUTS.URL);
+    });
+  }, "url - calling undefined callback throws");
+
+  test(t => {
+    let p = window.TrustedTypes.createPolicy('TestPolicyURL9', { createURL: createURLJS });
+    assert_throws(new TypeError(), _ => {
+      p.createHTML(INPUTS.HTML);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createScript(INPUTS.SCRIPT);
+    });
+    assert_throws(new TypeError(), _ => {
+      p.createScriptURL(INPUTS.SCRIPTURL);
+    });
+  }, "createURL defined - calling undefined callbacks throws");
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js" ></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+<body>
+<script>
+  //Policy name test
+  test(t => {
+    let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } );
+    assert_true(policy instanceof TrustedTypePolicy);
+    assert_equals(policy.name, 'SomeName');
+  }, "policy.name = name");
+
+  //Duplicate names test
+  test(t => {
+    assert_throws(new TypeError(), _ => {
+     window.TrustedTypes.createPolicy('SomeName', { createURL: s => s } );
+    });
+  }, "duplicate policy name attempt throws");
+
+  //Retrieve policy names tests
+  test(t => {
+    let policy = window.TrustedTypes.createPolicy('SomeOtherName', { createURL: s => s } );
+    let names = window.TrustedTypes.getPolicyNames();
+    assert_true(names.includes('SomeName'));
+    assert_true(names.includes('SomeOtherName'));
+  }, "Retrieving policy names");
+</script>
deleted file mode 100644
--- a/testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html
+++ /dev/null
@@ -1,299 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js" ></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support/helper.sub.js"></script>
-<body>
-<script>
-  //Policy name test
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } )
-        .then(t.step_func_done(policy => {
-            assert_true(policy instanceof TrustedTypePolicy);
-            assert_equals(policy.name, 'SomeName');
-    }));
-  }, "policy.name = name");
-
-  //HTML tests
-  function createHTMLTest(policy, expectedHTML, t) {
-    window.trustedTypes.createPolicy('SomeName', policy)
-        .then(t.step_func_done(p => {
-            assert_true(p.createHTML('whatever') instanceof TrustedHTML);
-            assert_equals(p.createHTML('whatever') + "", expectedHTML);
-    }));
-  }
-
-  async_test(t => {
-    createHTMLTest( { createHTML: s => s }, 'whatever', t);
-  }, "html = identity function");
-
-  async_test(t => {
-    createHTMLTest( { createHTML: s => null }, "null", t);
-  }, "html = null");
-
-  var HTMLstr = 'well, ';
-  async_test(t => {
-    createHTMLTest( { createHTML: s => HTMLstr + s }, HTMLstr + 'whatever', t);
-  }, "html = string + global string");
-
-  var HTMLx = 'global';
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', {
-        createHTML: s => { HTMLx = s; return s; }
-      })
-      .then(t.step_func_done(p => {
-        assert_true(p.createHTML('whatever') instanceof TrustedHTML);
-        assert_equals(p.createHTML('whatever') + "", 'whatever');
-        assert_equals(HTMLx, 'whatever');
-    }));
-  }, "html = identity function, global string changed");
-
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', {
-        createHTML: s => { throw new Error(); }
-      })
-      .then(t.step_func_done(p => {
-        assert_throws(new Error(), _ => {
-          p.createHTML('whatever');
-        });
-    }));
-  }, "html = callback that throws");
-
-  var obj = {
-    "foo": "well,"
-  }
-
-  function getHTML(s) {
-    return this.foo + " " + s;
-  }
-
-  async_test(t => {
-    createHTMLTest( {
-      createHTML: getHTML.bind(obj)},
-      'well, whatever', t);
-  }, "html = this bound to an object");
-
-  var foo = "well,";
-  async_test(t => {
-    createHTMLTest( { createHTML: s => getHTML(s) }, 'well, whatever', t);
-  }, "html = this without bind");
-
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', null)
-        .then(t.step_func_done(p => {
-            assert_equals(p.createHTML('whatever'), null);
-    }));
-  }, "html - calling undefined callback");
-
-  //Script tests
-  function createScriptTest(policy, expectedScript, t) {
-    let p = window.trustedTypes.createPolicy('SomeName', policy)
-        .then(t.step_func_done(p => {
-            assert_true(p.createScript('whatever') instanceof TrustedScript);
-            assert_equals(p.createScript('whatever') + "", expectedScript);
-    }));
-  }
-
-  async_test(t => {
-    createScriptTest( { createScript: s => s }, 'whatever', t);
-  }, "script = identity function");
-
-  async_test(t => {
-    createScriptTest( { createScript: s => null }, "null", t);
-  }, "script = null");
-
-  var Scriptstr = 'well, ';
-  async_test(t => {
-    createScriptTest( { createScript: s => Scriptstr + s }, Scriptstr + 'whatever', t);
-  }, "script = string + global string");
-
-  var Scriptx = 'global';
-  async_test(t => {
-    let p = window.trustedTypes.createPolicy('SomeName', {
-        createScript: s => { Scriptx = s; return s; }
-      })
-      .then(t.step_func_done(p => {
-        assert_true(p.createScript('whatever') instanceof TrustedScript);
-        assert_equals(p.createScript('whatever') + "", 'whatever');
-        assert_equals(Scriptx, 'whatever');
-    }));
-  }, "script = identity function, global string changed");
-
-  async_test(t => {
-    let p = window.trustedTypes.createPolicy('SomeName', {
-        createScript: s => { throw new Error(); }
-      })
-      .then(t.step_func_done(p => {
-        assert_throws(new Error(), _ => {
-          p.createScript('whatever');
-        });
-    }));
-  }, "script = callback that throws");
-
-  var obj = {
-    "foo": "well,"
-  }
-
-  function getScript(s) {
-    return this.foo + " " + s;
-  }
-
-  async_test(t => {
-    createScriptTest( {
-      createScript: getScript.bind(obj)},
-      'well, whatever', t);
-  }, "script = this bound to an object");
-
-  var foo = "well,";
-  async_test(t => {
-    createScriptTest( { createScript: s => getScript(s) }, 'well, whatever', t);
-  }, "script = this without bind");
-
-  async_test(t => {
-    let p = window.trustedTypes.createPolicy('SomeName', null)
-        .then(t.step_func_done(p => {
-            assert_equals(p.createScript('whatever'), null);
-    }));
-  }, "script - calling undefined callback");
-
-  //ScriptURL tests
-  function createScriptURLTest(policy, expectedScriptURL, t) {
-    window.trustedTypes.createPolicy('SomeName', policy)
-        .then(t.step_func_done(p => {
-            assert_true(p.createScriptURL(INPUTS.SCRIPTURL) instanceof TrustedScriptURL);
-            assert_equals(p.createScriptURL(INPUTS.SCRIPTURL) + "", expectedScriptURL);
-    }));
-  }
-
-  async_test(t => {
-    createScriptURLTest( { createScriptURL: s => s }, INPUTS.SCRIPTURL, t);
-  }, "script_url = identity function");
-
-  async_test(t => {
-    createScriptURLTest( { createScriptURL: s => null }, "", t);
-  }, "script_url = null");
-
-  var scriptURLstr = '#duck';
-  async_test(t => {
-    createScriptURLTest( { createScriptURL: s => s + scriptURLstr }, INPUTS.SCRIPTURL + scriptURLstr, t);
-  }, "script_url = string + global string");
-
-  var scriptURLx = 'global';
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', {
-        createScriptURL: s => { ScriptURLx = s; return s; }
-      })
-      .then(t.step_func_done(p => {
-        assert_true(p.createScriptURL(INPUTS.SCRIPTURL) instanceof TrustedScriptURL);
-        assert_equals(p.createScriptURL(INPUTS.SCRIPTURL) + "", INPUTS.SCRIPTURL);
-        assert_equals(ScriptURLx, INPUTS.SCRIPTURL);
-    }));
-  }, "script_url = identity function, global string changed");
-
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', {
-        createScriptURL: s => { throw new Error(); }
-      })
-      .then(t.step_func_done(p => {
-        assert_throws(new Error(), _ => {
-          p.createScriptURL(INPUTS.SCRIPTURL);
-        });
-    }));
-  }, "script_url = callback that throws");
-
-  function getScriptURL(s) {
-    return s + this.baz;
-  }
-
-  var obj = {
-    "baz": "#duck"
-  }
-
-  async_test(t => {
-    createScriptURLTest( {
-      createScriptURL: getScriptURL.bind(obj)},
-      INPUTS.SCRIPTURL + "#duck", t);
-  }, "script_url = this bound to an object");
-
-  var baz = "#duck";
-  async_test(t => {
-    createScriptURLTest( { createScriptURL: s => getScriptURL(s) }, INPUTS.SCRIPTURL + baz, t);
-  }, "script_url = this without bind");
-
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', null)
-        .then(t.step_func_done(p => {
-            assert_equals(p.createScriptURL(INPUTS.SCRIPTURL), null);
-    }));
-  }, "script_url - calling undefined callback");
-
-  //URL tests
-  function createURLTest(policy, expectedURL, t) {
-    window.trustedTypes.createPolicy('SomeName', policy)
-        .then(t.step_func_done(p => {
-            assert_true(p.createURL(INPUTS.URL) instanceof TrustedURL);
-            assert_equals(p.createURL(INPUTS.URL) + "", expectedURL);
-    }));
-  }
-
-  async_test(t => {
-    createURLTest( { createURL: s => s }, INPUTS.URL, t);
-  }, "url = identity function");
-
-  async_test(t => {
-    createURLTest( { createURL: s => null }, "", t);
-  }, "url = null");
-
-  var URLstr = '#x';
-  async_test(t => {
-    createURLTest( { createURL: s => s + URLstr }, INPUTS.URL + URLstr, t);
-  }, "url = string + global string");
-
-  var URLx = 'global';
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', {
-        createURL: s => { URLx = s; return s; }
-      })
-      .then(t.step_func_done(p => {
-        assert_true(p.createURL(INPUTS.URL) instanceof TrustedURL);
-        assert_equals(p.createURL(INPUTS.URL) + "", INPUTS.URL);
-        assert_equals(URLx, INPUTS.URL);
-    }));
-  }, "url = identity function, global string changed");
-
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', {
-        createURL: s => { throw new Error(); }
-      })
-      .then(t.step_func_done(p => {
-        assert_throws(new Error(), _ => {
-          p.createURL(INPUTS.URL);
-        });
-    }));
-  }, "url = callback that throws");
-
-  function getURL(s) {
-    return s + this.bar;
-  }
-
-  var obj = {
-    "bar": "#x"
-  }
-
-  async_test(t => {
-    createURLTest( {
-      createURL: getURL.bind(obj)},
-      INPUTS.URL + "#x", t);
-  }, "url = this bound to an object");
-
-  var bar = "#x";
-  async_test(t => {
-    createURLTest( { createURL: s => getURL(s) }, INPUTS.URL + bar, t);
-  }, "url = this without bind");
-
-  async_test(t => {
-    window.trustedTypes.createPolicy('SomeName', null)
-        .then(t.step_func_done(p => {
-            assert_equals(p.createURL(INPUTS.URL), null);
-    }));
-  }, "url - calling undefined callback");
-</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/trusted-types/Window-TrustedTypes.tentative.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+<body>
+<script>
+  test(t => {
+    let factory = window.TrustedTypes;
+    assert_true(factory instanceof TrustedTypePolicyFactory);
+  }, "factory = window.TrustedTypes");
+</script>
--- a/testing/web-platform/tests/trusted-types/Window-open.tentative.html
+++ b/testing/web-platform/tests/trusted-types/Window-open.tentative.html
@@ -1,27 +1,25 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 <body>
 <script>
   // helper functions for the tests
-  function testWindowOpen(t, win) {
-    createURL_policy(window)
-        .then(t.step_func_done(p => {
-            let url = p.createURL(INPUTS.URL);
-            let child_window = win.open(url, "", "");
-            child_window.onload = t.step_func_done(_ => {
-              assert_equals(child_window.location.href, "" + url);
-              child_window.close();
-            });
-        }));
+  function testWindowOpen(t, win, testNumber) {
+    let p = createURL_policy(window, testNumber);
+    let url = p.createURL(INPUTS.URL);
+    let child_window = win.open(url, "", "");
+    child_window.onload = t.step_func_done(_ => {
+      assert_equals(child_window.location.href, "" + url);
+      child_window.close();
+    });
   }
 
-  async_test(t => {
-    testWindowOpen(t, window);
+  test(t => {
+    testWindowOpen(t, window, 1);
   }, "window.open via policy (successful URL transformation).");
 
-  async_test(t => {
-    testWindowOpen(t, document);
+  test(t => {
+    testWindowOpen(t, document, 2);
   }, "document.open via policy (successful URL transformation).");
 </script>
deleted file mode 100644
--- a/testing/web-platform/tests/trusted-types/Window-trustedTypes.tentative.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support/helper.sub.js"></script>
-<body>
-<script>
-  test(t => {
-    let factory = window.trustedTypes;
-    assert_true(factory instanceof TrustedTypePolicyFactory);
-  }, "factory = window.trustedTypes");
-</script>
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html
@@ -2,24 +2,22 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 
 <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 <body>
 <script>
   // Trusted HTML assignments do not throw.
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
-        let parser = new DOMParser();
-        let doc = parser.parseFromString(html, "text/html");
-        assert_equals(doc.body.innerText, RESULTS.HTML);
-    }));
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
+    let parser = new DOMParser();
+    let doc = parser.parseFromString(html, "text/html");
+    assert_equals(doc.body.innerText, RESULTS.HTML);
   }, "document.innerText assigned via policy (successful HTML transformation).");
 
   // String assignments throw.
   test(t => {
     var parser = new DOMParser();
     assert_throws(new TypeError(), _ => {
       var doc = parser.parseFromString("Fail", "text/html");
     });
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Document-write.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Document-write.tentative.html
@@ -5,23 +5,21 @@
   <script src="/resources/testharnessreport.js"></script>
   <script src="support/helper.sub.js"></script>
 
   <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 </head>
 <body>
 <script>
   // TrustedURL assignments do not throw.
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
-        document.write(html);
-        assert_equals(document.body.innerText, RESULTS.HTML);
-    }));
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
+    document.write(html);
+    assert_equals(document.body.innerText, RESULTS.HTML);
   }, "document.write with html assigned via policy (successful URL transformation).");
 
   // String assignments throw.
   test(t => {
     assert_throws(new TypeError(), _ => {
       document.write('A string');
     });
   }, "`document.write(string)` throws");
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html
@@ -8,43 +8,41 @@
   <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 </head>
 <body>
 <div id="container"></div>
 <script>
   var container = document.querySelector('#container');
 
   // Trusted HTML assignments do not throw.
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
 
-        var d = document.createElement('div');
-        container.appendChild(d);
+    var d = document.createElement('div');
+    container.appendChild(d);
 
-        d.insertAdjacentHTML('beforebegin', html);
-        assert_equals(d.previousSibling.nodeType, Node.TEXT_NODE);
-        assert_equals(d.previousSibling.data, RESULTS.HTML);
+    d.insertAdjacentHTML('beforebegin', html);
+    assert_equals(d.previousSibling.nodeType, Node.TEXT_NODE);
+    assert_equals(d.previousSibling.data, RESULTS.HTML);
 
-        d.insertAdjacentHTML('afterbegin', html);
-        assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
-        assert_equals(d.firstChild.data, RESULTS.HTML);
-
-        d.insertAdjacentHTML('beforeend', html);
-        assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
-        assert_equals(d.lastChild.data, RESULTS.HTML);
+    d.insertAdjacentHTML('afterbegin', html);
+    assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
+    assert_equals(d.firstChild.data, RESULTS.HTML);
 
-        d.insertAdjacentHTML('afterend', html);
-        assert_equals(d.nextSibling.nodeType, Node.TEXT_NODE);
-        assert_equals(d.nextSibling.data, RESULTS.HTML);
+    d.insertAdjacentHTML('beforeend', html);
+    assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
+    assert_equals(d.lastChild.data, RESULTS.HTML);
 
-        while (container.firstChild)
-          container.firstChild.remove();
-    }));
+    d.insertAdjacentHTML('afterend', html);
+    assert_equals(d.nextSibling.nodeType, Node.TEXT_NODE);
+    assert_equals(d.nextSibling.data, RESULTS.HTML);
+
+    while (container.firstChild)
+      container.firstChild.remove();
   }, "insertAdjacentHTML with html assigned via policy (successful HTML transformation).");
 
   // String assignments throw.
   test(t => {
     var d = document.createElement('div');
     container.appendChild(d);
 
     assert_throws(new TypeError(), _ => {
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html
@@ -8,29 +8,27 @@
   <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 </head>
 <body>
 <div id="container"></div>
 <script>
   var container = document.querySelector('#container')
 
   // TrustedHTML assignments do not throw.
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
 
-        var d = document.createElement('div');
-        document.querySelector('#container').appendChild(d);
-        d.outerHTML = html;
-        assert_equals(container.innerText, RESULTS.HTML);
+    var d = document.createElement('div');
+    document.querySelector('#container').appendChild(d);
+    d.outerHTML = html;
+    assert_equals(container.innerText, RESULTS.HTML);
 
-        while (container.firstChild)
-          container.firstChild.remove();
-    }));
+    while (container.firstChild)
+      container.firstChild.remove();
   }, "outerHTML with html assigned via policy (successful HTML transformation).");
 
   // String assignments throw.
   test(t => {
     var d = document.createElement('div');
     container.appendChild(d);
     assert_throws(new TypeError(), _ => {
       d.outerHTML = "Fail.";
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html
@@ -22,43 +22,43 @@
     [ 'video', 'src' ],
     [ 'object', 'data' ],
     [ 'object', 'codeBase' ],
     [ 'source', 'src' ],
     [ 'track', 'src' ]
   ];
 
   testCases.forEach(c => {
-    async_test(t => {
-      assert_element_accepts_trusted_url(window, t, c[0], c[1], RESULTS.URL);
+    test(t => {
+      assert_element_accepts_trusted_url(window, c, t, c[0], c[1], RESULTS.URL);
       assert_throws_no_trusted_type(c[0], c[1], 'A string');
       assert_throws_no_trusted_type(c[0], c[1], null);
     }, c[0] + "." + c[1] + " accepts only TrustedURL");
   });
 
   // TrustedScriptURL Assignments
   let scriptTestCases = [
     [ 'embed', 'src' ],
     [ 'script', 'src' ]
   ];
 
   scriptTestCases.forEach(c => {
-    async_test(t => {
-      assert_element_accepts_trusted_script_url(window, t, c[0], c[1], RESULTS.SCRIPTURL);
+    test(t => {
+      assert_element_accepts_trusted_script_url(window, c, t, c[0], c[1], RESULTS.SCRIPTURL);
       assert_throws_no_trusted_type(c[0], c[1], 'A string');
       assert_throws_no_trusted_type(c[0], c[1], null);
     }, c[0] + "." + c[1] + " accepts only TrustedScriptURL");
   });
 
   // TrustedHTML Assignments
   let HTMLTestCases = [
     [ 'div', 'innerHTML' ],
     [ 'iframe', 'srcdoc' ]
   ];
 
   HTMLTestCases.forEach(c => {
-    async_test(t => {
-      assert_element_accepts_trusted_html(window, t, c[0], c[1], RESULTS.HTML);
+    test(t => {
+      assert_element_accepts_trusted_html(window, c, t, c[0], c[1], RESULTS.HTML);
       assert_throws_no_trusted_type(c[0], c[1], 'A string');
       assert_throws_no_trusted_type(c[0], c[1], null);
     }, c[0] + "." + c[1] + " accepts only TrustedHTML");
   });
 </script>
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Location-assign.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Location-assign.tentative.html
@@ -5,23 +5,21 @@
   <script src="/resources/testharnessreport.js"></script>
   <script src="support/helper.sub.js"></script>
 
   <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 </head>
 <body>
 <script>
   // TrustedURL assignments do not throw.
-  async_test(t => {
-    createURL_policy(window)
-        .then(t.step_func_done(p => {
-          let url = p.createURL(location.href + "#xxx");
-          location.assign(url);
-          assert_equals("" + url, location.href, "location href");
-    }));
+  test(t => {
+    let p = createURL_policy(window, 1);
+    let url = p.createURL(location.href + "#xxx");
+    location.assign(url);
+    assert_equals("" + url, location.href, "location href");
   }, "location.assign via policy (successful URL transformation).");
 
   // String assignments throw.
   test(t => {
     assert_throws(new TypeError(), _ => {
       location.assign("A string");
     });
   }, "`location.assign = string` throws");
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Location-href.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Location-href.tentative.html
@@ -5,23 +5,21 @@
   <script src="/resources/testharnessreport.js"></script>
   <script src="support/helper.sub.js"></script>
 
   <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 </head>
 <body>
 <script>
   // TrustedURL assignments do not throw.
-  async_test(t => {
-    createURL_policy(window)
-      .then(t.step_func_done(p => {
-        let url = p.createURL(location.href + "#xxx");
-        location.href = url;
-        assert_equals("" + url, location.href, "location href");
-    }));
+  test(t => {
+    let p = createURL_policy(window, 1);
+    let url = p.createURL(location.href + "#xxx");
+    location.href = url;
+    assert_equals("" + url, location.href, "location href");
   }, "location.href assigned via policy (successful URL transformation).");
 
   // String assignments throw.
   test(t => {
     assert_throws(new TypeError(), _ => {
       location.href = 'A string';
     });
   }, "`location.href = string` throws");
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Location-replace.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Location-replace.tentative.html
@@ -5,23 +5,21 @@
   <script src="/resources/testharnessreport.js"></script>
   <script src="support/helper.sub.js"></script>
 
   <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 </head>
 <body>
 <script>
   // TrustedURL replacements do not throw.
-  async_test(t => {
-    createURL_policy(window)
-        .then(t.step_func_done(p => {
-          let url = p.createURL(location.href + "#xxx");
-          location.replace(url);
-          assert_equals("" + url, location.href, "location href");
-    }));
+  test(t => {
+    let p = createURL_policy(window, 1);
+    let url = p.createURL(location.href + "#xxx");
+    location.replace(url);
+    assert_equals("" + url, location.href, "location href");
   }, "location.replace via policy (successful URL transformation).");
 
   // String replacements throw.
   test(t => {
     assert_throws(new TypeError(), _ => {
       location.replace("A string");
     });
   }, "`location.replace = string` throws");
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html
@@ -2,25 +2,23 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/helper.sub.js"></script>
 
 <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 <body>
 <script>
   // TrustedHTML assignments do not throw.
-  async_test(t => {
-    createHTML_policy(window)
-      .then(t.step_func_done(p => {
-        let html = p.createHTML(INPUTS.HTML);
-        var range = document.createRange();
-        range.selectNodeContents(document.documentElement);
-        var result = range.createContextualFragment(html);
-        assert_equals(result.textContent, RESULTS.HTML);
-    }));
+  test(t => {
+    let p = createHTML_policy(window, 1);
+    let html = p.createHTML(INPUTS.HTML);
+    var range = document.createRange();
+    range.selectNodeContents(document.documentElement);
+    var result = range.createContextualFragment(html);
+    assert_equals(result.textContent, RESULTS.HTML);
   }, "range.createContextualFragment assigned via policy (successful HTML transformation).");
 
   // String assignments throw.
   test(t => {
     var range = document.createRange();
     range.selectNodeContents(document.documentElement);
     assert_throws(new TypeError(), _ => {
       var result = range.createContextualFragment("A string");
--- a/testing/web-platform/tests/trusted-types/block-string-assignment-to-Window-open.tentative.html
+++ b/testing/web-platform/tests/trusted-types/block-string-assignment-to-Window-open.tentative.html
@@ -4,60 +4,57 @@
   <script src="/resources/testharness.js"></script>
   <script src="/resources/testharnessreport.js"></script>
   <script src="support/helper.sub.js"></script>
 
   <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
 </head>
 <body>
 <script>
+  var testnb = 0;
   // helper functions for the tests
-  function testWindowOpen(t, win) {
-    createURL_policy(window)
-        .then(t.step_func_done(p => {
-            let url = p.createURL(INPUTS.URL);
-            let child_window = win.open(url, "", "");
-            child_window.onload = t.step_func_done(_ => {
-              assert_equals(child_window.location.href, "" + url);
-              child_window.close();
-            });
-        }));
+  function testWindowOpen(t, win, nb) {
+    let p = createURL_policy(window, nb);
+    let url = p.createURL(INPUTS.URL);
+    let child_window = win.open(url, "", "");
+    child_window.onload = t.step_func_done(_ => {
+      assert_equals(child_window.location.href, "" + url);
+      child_window.close();
+    });
   }
 
-  function testWindowThrows(t, url, win) {
-    createURL_policy(window)
-        .then(t.step_func_done(p => {
-            assert_throws(new TypeError(), _ => {
-              let child_window = win.open(url, "", "");
-              child_window.close();
-            });
-        }));
+  function testWindowThrows(t, url, win, nb) {
+    let p = createURL_policy(window, nb);
+    assert_throws(new TypeError(), _ => {
+      let child_window = win.open(url, "", "");
+      child_window.close();
+    });
   }
 
   // TrustedURL assignments do not throw.
-  async_test(t => {
-    testWindowOpen(t, window);
+  test(t => {
+    testWindowOpen(t, window, ++testnb);
   }, "window.open via policy (successful URL transformation).");
 
-  async_test(t => {
-    testWindowOpen(t, document);
+  test(t => {
+    testWindowOpen(t, document, ++testnb);
   }, "document.open via policy (successful URL transformation).");
 
   // String assignments throw.
-  async_test(t => {
-    testWindowThrows(t, 'A string', window);
+  test(t => {
+    testWindowThrows(t, 'A string', window, ++testnb);
   }, "`window.open(string)` throws.");
 
-  async_test(t => {
-    testWindowThrows(t, 'A string', document);
+  test(t => {
+    testWindowThrows(t, 'A string', document, ++testnb);
   }, "`document.open(string)` throws.");
 
   // Null assignment throws.
-  async_test(t => {
-    testWindowThrows(t, null, window);
+  test(t => {
+    testWindowThrows(t, null, window, ++testnb);
   }, "`window.open(null)` throws.");
 
-  async_test(t => {
-    testWindowThrows(t, null, document);
+  test(t => {
+    testWindowThrows(t, null, document, ++testnb);
   }, "`document.open(null)` throws.");
 </script>
 </body>
 </html>
--- a/testing/web-platform/tests/trusted-types/support/helper.sub.js
+++ b/testing/web-platform/tests/trusted-types/support/helper.sub.js
@@ -26,62 +26,54 @@ function createScriptURLJS(scripturl) {
   return scripturl.replace("scripturl", "successful");
 }
 
 function createURLJS(url) {
   return url.replace("hello", "hooray")
       .replace("an.url", "successfully.transformed");
 }
 
-function createHTML_policy(win) {
-  return win.trustedTypes.createPolicy('SomeName', { createHTML: createHTMLJS });
+function createHTML_policy(win, c) {
+  return win.TrustedTypes.createPolicy('SomeHTMLPolicyName' + c, { createHTML: createHTMLJS });
 }
 
-function createScript_policy(win) {
-  return win.trustedTypes.createPolicy('SomeName', { createScript: createScriptJS });
+function createScript_policy(win, c) {
+  return win.TrustedTypes.createPolicy('SomeScriptPolicyName' + c, { createScript: createScriptJS });
 }
 
-function createScriptURL_policy(win) {
-  return win.trustedTypes.createPolicy('SomeName', { createScriptURL: createScriptURLJS });
+function createScriptURL_policy(win, c) {
+  return win.TrustedTypes.createPolicy('SomeScriptURLPolicyName' + c, { createScriptURL: createScriptURLJS });
 }
 
-function createURL_policy(win) {
-  return win.trustedTypes.createPolicy('SomeName', { createURL: createURLJS });
+function createURL_policy(win, c) {
+  return win.TrustedTypes.createPolicy('SomeURLPolicyName' + c, { createURL: createURLJS });
 }
 
-function assert_element_accepts_trusted_html(win, t, tag, attribute, expected) {
-  createHTML_policy(win)
-      .then(t.step_func_done(p => {
-          let html = p.createHTML(INPUTS.HTML);
-          assert_element_accepts_trusted_type(tag, attribute, html, expected);
-      }));
+function assert_element_accepts_trusted_html(win, c, t, tag, attribute, expected) {
+  let p = createHTML_policy(win, c);
+  let html = p.createHTML(INPUTS.HTML);
+  assert_element_accepts_trusted_type(tag, attribute, html, expected);
 }
 
-function assert_element_accepts_trusted_script(win, t, tag, attribute, expected) {
-  createScript_policy(win)
-      .then(t.step_func_done(p => {
-          let script = p.createScript(INPUTS.SCRIPT);
-          assert_element_accepts_trusted_type(tag, attribute, script, expected);
-      }));
+function assert_element_accepts_trusted_script(win, c, t, tag, attribute, expected) {
+  let p = createScript_policy(win, c);
+  let script = p.createScript(INPUTS.SCRIPT);
+  assert_element_accepts_trusted_type(tag, attribute, script, expected);
 }
 
-function assert_element_accepts_trusted_script_url(win, t, tag, attribute, expected) {
-  createScriptURL_policy(win)
-      .then(t.step_func_done(p => {
-          let scripturl = p.createScriptURL(INPUTS.SCRIPTURL);
-          assert_element_accepts_trusted_type(tag, attribute, scripturl, expected);
-      }));
+function assert_element_accepts_trusted_script_url(win, c, t, tag, attribute, expected) {
+  let p = createScriptURL_policy(win, c);
+  let scripturl = p.createScriptURL(INPUTS.SCRIPTURL);
+  assert_element_accepts_trusted_type(tag, attribute, scripturl, expected);
 }
 
-function assert_element_accepts_trusted_url(win, t, tag, attribute, expected) {
-  createURL_policy(win)
-      .then(t.step_func_done(p => {
-          let url = p.createURL(INPUTS.URL);
-          assert_element_accepts_trusted_type(tag, attribute, url, expected);
-      }));
+function assert_element_accepts_trusted_url(win, c, t, tag, attribute, expected) {
+  let p = createURL_policy(win, c);
+  let url = p.createURL(INPUTS.URL);
+  assert_element_accepts_trusted_type(tag, attribute, url, expected);
 }
 
 function assert_element_accepts_trusted_type(tag, attribute, value, expected) {
   let elem = document.createElement(tag);
   elem[attribute] = value;
   assert_equals(elem[attribute] + "", expected);
 }
 
--- a/testing/web-platform/tests/xhr/timeout-multiple-fetches.html
+++ b/testing/web-platform/tests/xhr/timeout-multiple-fetches.html
@@ -1,29 +1,32 @@
 <!doctype html>
 <title>XMLHttpRequest: timeout, redirects, and CORS preflights</title>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/common/get-host-info.sub.js></script>
+<script src=/common/utils.js></script>
 <div id=log></div>
 <script>
 async_test(t => {
   const client = new XMLHttpRequest
   client.open("GET", "resources/redirect.py?delay=500&location=delay.py") // 500 + 500 = 1000
-  client.timeout = 1000
+  client.timeout = 750
   client.send()
   client.ontimeout = t.step_func_done(() => {
     assert_equals(client.readyState, 4)
   })
   client.onload = t.unreached_func("load event fired")
 }, "Redirects should not reset the timer")
 
 async_test(t => {
+  // Use a unique ID to prevent caching of the preflight making the test flaky.
+  const uuid = token();
   const client = new XMLHttpRequest
-  client.open("YO", get_host_info().HTTP_REMOTE_ORIGIN + "/xhr/resources/delay.py")
-  client.timeout = 1000
+  client.open("YO", get_host_info().HTTP_REMOTE_ORIGIN + "/xhr/resources/delay.py?uuid=" + uuid)
+  client.timeout = 750
   client.send()
   client.ontimeout = t.step_func_done(() => {
     assert_equals(client.readyState, 4)
   })
   client.onload = t.unreached_func("load event fired")
 }, "CORS preflights should not reset the timer")
 </script>
--- a/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
@@ -58,36 +58,37 @@ skip-if = os == "android" # checking for
 [test_ext_idle.js]
 [test_ext_legacy_extension_context.js]
 [test_ext_legacy_extension_embedding.js]
 [test_ext_localStorage.js]
 [test_ext_management.js]
 skip-if = (os == "win" && !debug) #Bug 1419183 disable on Windows
 [test_ext_management_uninstall_self.js]
 [test_ext_messaging_startup.js]
-skip-if = appname == "thunderbird"
+skip-if = appname == "thunderbird" || (os == "android" && debug)
 [test_ext_onmessage_removelistener.js]
 skip-if = true # This test no longer tests what it is meant to test.
 [test_ext_permission_xhr.js]
 [test_ext_persistent_events.js]
 [test_ext_privacy.js]
-skip-if = appname == "thunderbird"
+skip-if = appname == "thunderbird" || (os == "android" && debug)
 [test_ext_privacy_disable.js]
 skip-if = appname == "thunderbird"
 [test_ext_privacy_update.js]
 [test_ext_proxy_auth.js]
 [test_ext_proxy_config.js]
 skip-if = appname == "thunderbird"
 [test_ext_proxy_onauthrequired.js]
 [test_ext_proxy_settings.js]
 skip-if = appname == "thunderbird" || os == "android" # proxy settings are not supported on android
 [test_ext_proxy_socks.js]
 [test_ext_proxy_speculative.js]
 [test_ext_proxy_startup.js]
 [test_ext_redirects.js]
+skip-if = os == "android" && debug
 [test_ext_runtime_connect_no_receiver.js]
 [test_ext_runtime_getBrowserInfo.js]
 [test_ext_runtime_getPlatformInfo.js]
 [test_ext_runtime_id.js]
 [test_ext_runtime_onInstalled_and_onStartup.js]
 skip-if = true # bug 1315829
 [test_ext_runtime_sendMessage.js]
 [test_ext_runtime_sendMessage_errors.js]
@@ -98,18 +99,21 @@ skip-if = true # bug 1315829
 [test_ext_schema.js]
 [test_ext_shutdown_cleanup.js]
 [test_ext_simple.js]
 [test_ext_startupData.js]
 [test_ext_startup_cache.js]
 skip-if = os == "android"
 [test_ext_startup_perf.js]
 [test_ext_storage.js]
+skip-if = os == "android" && debug
 [test_ext_storage_idb_data_migration.js]
+skip-if = os == "android" && debug
 [test_ext_storage_content.js]
+skip-if = os == "android" && debug
 [test_ext_storage_managed.js]
 skip-if = os == "android"
 [test_ext_storage_sync.js]
 head = head.js head_sync.js
 skip-if = appname == "thunderbird" || os == "android"
 [test_ext_storage_sync_crypto.js]
 skip-if = appname == "thunderbird" || os == "android"
 [test_ext_storage_tab.js]
@@ -119,22 +123,27 @@ skip-if = os == "android" # checking for
 skip-if = os == 'android' # Bug 1258975 on android.
 [test_ext_telemetry.js]
 [test_ext_trustworthy_origin.js]
 [test_ext_topSites.js]
 skip-if = os == "android"
 [test_ext_unload_frame.js]
 skip-if = true # Too frequent intermittent failures
 [test_ext_webRequest_auth.js]
+skip-if = os == "android" && debug
 [test_ext_webRequest_filterResponseData.js]
+skip-if = os == "android" && debug
 [test_ext_webRequest_permission.js]
+skip-if = os == "android" && debug
 [test_ext_webRequest_responseBody.js]
+skip-if = os == "android" && debug
 [test_ext_webRequest_set_cookie.js]
-skip-if = appname == "thunderbird"
+skip-if = appname == "thunderbird" || (os == "android" && debug)
 [test_ext_webRequest_startup.js]
+skip-if = os == "android" && debug
 [test_ext_webRequest_suspend.js]
 [test_ext_webRequest_webSocket.js]
 skip-if = appname == "thunderbird"
 [test_ext_xhr_capabilities.js]
 [test_native_manifests.js]
 subprocess = true
 skip-if = os == "android"
 [test_ext_permissions.js]