Backed out 4 changesets (bug 1588193) for bc failures at browser_mixedcontent_aboutblocked.js. CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Wed, 06 Nov 2019 02:39:32 +0200
changeset 500748 5eaefee2f30d79446a86a325d51095fa6e022399
parent 500747 063086c09dc6b15acc643d85fa7cc8c30d4a5e0e
child 500749 fb5acb145e6a25da801d0fef0ad58361cc5b8ac5
push id99809
push usercbrindusan@mozilla.com
push dateWed, 06 Nov 2019 00:43:56 +0000
treeherderautoland@fb5acb145e6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1588193
milestone72.0a1
backs out0bbb1f92bb4721a0bc090a10d2c34ded75f8e01c
074bb8a6fd6851f9ebfc68e7505d6e30b4342bdb
b10ec4058ec3aee7c9cde560a6afeeaca7bce2c9
c90bab12f4cb6fc5baaa43d3f3e14c681b9cd390
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 4 changesets (bug 1588193) for bc failures at browser_mixedcontent_aboutblocked.js. CLOSED TREE Backed out changeset 0bbb1f92bb47 (bug 1588193) Backed out changeset 074bb8a6fd68 (bug 1588193) Backed out changeset b10ec4058ec3 (bug 1588193) Backed out changeset c90bab12f4cb (bug 1588193)
browser/base/content/aboutNetError.js
browser/base/content/test/general/browser_bug567306.js
browser/base/content/test/general/browser_search_discovery.js
browser/base/content/test/performance/browser_startup_content.js
browser/base/content/test/plugins/browser_bug744745.js
dom/indexedDB/test/head.js
dom/quota/test/head.js
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
testing/mochitest/BrowserTestUtils/ContentEventListenerChild.jsm
testing/mochitest/BrowserTestUtils/ContentEventListenerParent.jsm
toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
toolkit/mozapps/extensions/test/browser/browser_history_navigation.js
--- a/browser/base/content/aboutNetError.js
+++ b/browser/base/content/aboutNetError.js
@@ -260,16 +260,20 @@ function initPage() {
   }
 
   if (err == "cspBlocked" || err == "xfoBlocked") {
     // Remove the "Try again" button for XFO and CSP violations,
     // since it's almost certainly useless. (Bug 553180)
     document.getElementById("netErrorButtonContainer").style.display = "none";
   }
 
+  // Dispatch this event only for tests.
+  let event = new CustomEvent("AboutNetErrorLoad", { bubbles: true });
+  document.dispatchEvent(event);
+
   setNetErrorMessageFromCode();
   let learnMoreLink = document.getElementById("learnMoreLink");
   let baseURL = RPMGetFormatURLPref("app.support.baseURL");
   learnMoreLink.setAttribute("href", baseURL + "connection-not-secure");
 
   // Pinning errors are of type nssFailure2
   if (err == "nssFailure2") {
     setupErrorUI();
@@ -316,21 +320,16 @@ function initPage() {
     // again won't help.
     document.getElementById("netErrorButtonContainer").style.display = "none";
 
     var container = document.getElementById("errorLongDesc");
     for (var span of container.querySelectorAll("span.hostname")) {
       span.textContent = document.location.hostname;
     }
   }
-
-  // Dispatch this event only for tests. This should only be sent after we're
-  // done initializing the error page.
-  let event = new CustomEvent("AboutNetErrorLoad", { bubbles: true });
-  document.dispatchEvent(event);
 }
 
 function setupErrorUI() {
   document.getElementById("learnMoreContainer").style.display = "block";
 
   let checkbox = document.getElementById("automaticallyReportInFuture");
   checkbox.addEventListener("change", function({ target: { checked } }) {
     onSetAutomatic(checked);
--- a/browser/base/content/test/general/browser_bug567306.js
+++ b/browser/base/content/test/general/browser_bug567306.js
@@ -9,17 +9,17 @@ add_task(async function() {
 
   let selectedBrowser = newwindow.gBrowser.selectedBrowser;
   await new Promise((resolve, reject) => {
     BrowserTestUtils.waitForContentEvent(
       selectedBrowser,
       "pageshow",
       true,
       event => {
-        return event.target.location != "about:blank";
+        return content.location.href != "about:blank";
       }
     ).then(function pageshowListener() {
       ok(
         true,
         "pageshow listener called: " + newwindow.gBrowser.currentURI.spec
       );
       resolve();
     });
--- a/browser/base/content/test/general/browser_search_discovery.js
+++ b/browser/base/content/test/general/browser_search_discovery.js
@@ -1,19 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* eslint-disable mozilla/no-arbitrary-setTimeout */
-
-// Bug 1588193 - BrowserTestUtils.waitForContentEvent now resolves slightly
-// earlier than before, so it no longer suffices to only wait for a single event
-// tick before checking if browser.engines has been updated. Instead we use a 1s
-// timeout, which may cause the test to take more time.
-requestLongerTimeout(2);
-
 add_task(async function() {
   let url =
     "http://mochi.test:8888/browser/browser/base/content/test/general/discovery.html";
   info("Test search discovery");
   await BrowserTestUtils.withNewTab(url, searchDiscovery);
 });
 
 let searchDiscoveryTests = [
@@ -76,17 +68,17 @@ async function searchDiscovery() {
       link.rel = test.rel || "search";
       link.href = test.href || "http://so.not.here.mozilla.com/search.xml";
       link.type = test.type || "application/opensearchdescription+xml";
       link.title = test.title;
       head.appendChild(link);
     });
 
     await promiseLinkAdded;
-    await new Promise(resolve => setTimeout(resolve, 1000));
+    await new Promise(resolve => executeSoon(resolve));
 
     if (browser.engines) {
       info(`Found ${browser.engines.length} engines`);
       info(`First engine title: ${browser.engines[0].title}`);
       let hasEngine = testCase.count
         ? browser.engines[0].title == testCase.title &&
           browser.engines.length == testCase.count
         : browser.engines[0].title == testCase.title;
@@ -115,17 +107,17 @@ async function searchDiscovery() {
     link.title = "Test Engine";
     let link2 = link.cloneNode(false);
     link2.href = "http://second.mozilla.com/search.xml";
     head.appendChild(link);
     head.appendChild(link2);
   });
 
   await promiseLinkAdded;
-  await new Promise(resolve => setTimeout(resolve, 1000));
+  await new Promise(resolve => executeSoon(resolve));
 
   ok(browser.engines, "has engines");
   is(browser.engines.length, 1, "only one engine");
   is(
     browser.engines[0].uri,
     "http://first.mozilla.com/search.xml",
     "first engine wins"
   );
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -93,17 +93,16 @@ const intermittently_loaded_whitelist = 
     "resource://specialpowers/WrapPrivileged.jsm",
 
     // Webcompat about:config front-end. This is presently nightly-only and
     // part of a system add-on which may not load early enough for the test.
     "resource://webcompat/AboutCompat.jsm",
 
     // Test related
     "resource://testing-common/BrowserTestUtilsChild.jsm",
-    "resource://testing-common/ContentEventListenerChild.jsm",
   ]),
   frameScripts: new Set([]),
   processScripts: new Set([
     // Webcompat about:config front-end. This is presently nightly-only and
     // part of a system add-on which may not load early enough for the test.
     "resource://webcompat/aboutPageProcessScript.js",
   ]),
 };
--- a/browser/base/content/test/plugins/browser_bug744745.js
+++ b/browser/base/content/test/plugins/browser_bug744745.js
@@ -1,16 +1,30 @@
 var gTestRoot = getRootDirectory(gTestPath).replace(
   "chrome://mochitests/content/",
   "http://127.0.0.1:8888/"
 );
 var gTestBrowser = null;
+var gNumPluginBindingsAttached = 0;
+
+function pluginBindingAttached() {
+  gNumPluginBindingsAttached++;
+  if (gNumPluginBindingsAttached != 1) {
+    ok(false, "if we've gotten here, something is quite wrong");
+  }
+}
 
 add_task(async function() {
   registerCleanupFunction(function() {
+    gTestBrowser.removeEventListener(
+      "PluginBindingAttached",
+      pluginBindingAttached,
+      true,
+      true
+    );
     clearAllPluginPermissions();
     setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
     setTestPluginEnabledState(
       Ci.nsIPluginTag.STATE_ENABLED,
       "Second Test Plug-in"
     );
     gBrowser.removeCurrentTab();
     window.focus();
@@ -19,30 +33,35 @@ add_task(async function() {
 });
 
 add_task(async function() {
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   gTestBrowser = gBrowser.selectedBrowser;
 
   setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
 
-  let promisePluginBindingAttached = BrowserTestUtils.waitForContentEvent(
+  BrowserTestUtils.addContentEventListener(
     gTestBrowser,
     "PluginBindingAttached",
-    true,
-    null,
-    true
+    pluginBindingAttached,
+    { capture: true, wantUntrusted: true }
   );
 
+  let testRoot = getRootDirectory(gTestPath).replace(
+    "chrome://mochitests/content/",
+    "http://127.0.0.1:8888/"
+  );
   await promiseTabLoadEvent(
     gBrowser.selectedTab,
-    gTestRoot + "plugin_bug744745.html"
+    testRoot + "plugin_bug744745.html"
   );
 
-  await promisePluginBindingAttached;
+  await promiseForCondition(function() {
+    return gNumPluginBindingsAttached == 1;
+  });
 
   await ContentTask.spawn(gTestBrowser, {}, async function() {
     let plugin = content.document.getElementById("test");
     if (!plugin) {
       Assert.ok(false, "plugin element not available.");
       return;
     }
     // We can't use MochiKit's routine
--- a/dom/indexedDB/test/head.js
+++ b/dom/indexedDB/test/head.js
@@ -80,37 +80,33 @@ function dismissNotification(popup) {
 
 function waitForMessage(aMessage, browser) {
   // We cannot capture aMessage inside the checkFn, so we override the
   // checkFn.toSource to tunnel aMessage instead.
   let checkFn = function() {};
   checkFn.toSource = function() {
     return `function checkFn(event) {
       let message = ${aMessage.toSource()};
+      is(event.data, message, "Received: " + message);
       if (event.data == message) {
         return true;
       }
       throw new Error(
        \`Unexpected result: \$\{event.data\}, expected \$\{message\}\`
       );
     }`;
   };
 
   return BrowserTestUtils.waitForContentEvent(
     browser.selectedBrowser,
     "message",
     /* capture */ true,
     checkFn,
     /* wantsUntrusted */ true
-  ).then(() => {
-    // An assertion in checkFn wouldn't be recorded as part of the test, so we
-    // use this assertion to confirm that we've successfully received the
-    // message (we'll only reach this point if that's the case).
-    ok(true, "Received message: " + aMessage);
-  });
+  );
 }
 
 function dispatchEvent(eventName) {
   info("dispatching event: " + eventName);
   let event = document.createEvent("Events");
   event.initEvent(eventName, false, false);
   gBrowser.selectedBrowser.contentWindow.dispatchEvent(event);
 }
--- a/dom/quota/test/head.js
+++ b/dom/quota/test/head.js
@@ -102,37 +102,33 @@ function dismissNotification(popup, win)
 
 function waitForMessage(aMessage, browser) {
   // We cannot capture aMessage inside the checkFn, so we override the
   // checkFn.toSource to tunnel aMessage instead.
   let checkFn = function() {};
   checkFn.toSource = function() {
     return `function checkFn(event) {
       let message = ${aMessage.toSource()};
+      is(event.data, message, "Received: " + message);
       if (event.data == message) {
         return true;
       }
       throw new Error(
        \`Unexpected result: \$\{event.data\}, expected \$\{message\}\`
       );
     }`;
   };
 
   return BrowserTestUtils.waitForContentEvent(
     browser.selectedBrowser,
     "message",
     /* capture */ true,
     checkFn,
     /* wantsUntrusted */ true
-  ).then(() => {
-    // An assertion in checkFn wouldn't be recorded as part of the test, so we
-    // use this assertion to confirm that we've successfully received the
-    // message (we'll only reach this point if that's the case).
-    ok(true, "Received message: " + aMessage);
-  });
+  );
 }
 
 function removePermission(url, permission) {
   let uri = Cc["@mozilla.org/network/io-service;1"]
     .getService(Ci.nsIIOService)
     .newURI(url);
   let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(
     Ci.nsIScriptSecurityManager
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -72,52 +72,56 @@ registrar.registerFactory(OUR_PROCESSSEL
 // For now, we'll allow tests to use CPOWs in this module for
 // some cases.
 Cu.permitCPOWsInScope(this);
 
 const kAboutPageRegistrationContentScript =
   "chrome://mochikit/content/tests/BrowserTestUtils/content-about-page-utils.js";
 
 /**
- * Create and register the BrowserTestUtils and ContentEventListener window
- * actors.
+ * Create and register BrowserTestUtils Window Actor.
  */
-function registerActors() {
-  ChromeUtils.registerWindowActor("BrowserTestUtils", {
+function registerActor() {
+  let actorOptions = {
     parent: {
       moduleURI: "resource://testing-common/BrowserTestUtilsParent.jsm",
     },
     child: {
       moduleURI: "resource://testing-common/BrowserTestUtilsChild.jsm",
       events: {
         DOMContentLoaded: { capture: true },
         load: { capture: true },
       },
     },
     allFrames: true,
     includeChrome: true,
-  });
+  };
+  ChromeUtils.registerWindowActor("BrowserTestUtils", actorOptions);
+}
 
-  ChromeUtils.registerWindowActor("ContentEventListener", {
+function registerContentEventListenerActor() {
+  let actorOptions = {
     parent: {
       moduleURI: "resource://testing-common/ContentEventListenerParent.jsm",
     },
+
     child: {
       moduleURI: "resource://testing-common/ContentEventListenerChild.jsm",
       events: {
         // We need to see the creation of all new windows, in case they have
-        // a browsing context we are interested in.
+        // a browsing context we are interesting in.
         DOMWindowCreated: { capture: true },
       },
     },
     allFrames: true,
-  });
+  };
+  ChromeUtils.registerWindowActor("ContentEventListener", actorOptions);
 }
 
-registerActors();
+registerActor();
 
 var BrowserTestUtils = {
   /**
    * Loads a page in a new tab, executes a Task and closes the tab.
    *
    * @param options
    *        An object  or string.
    *        If this is a string it is the url to open and will be opened in the
@@ -518,16 +522,18 @@ var BrowserTestUtils = {
   },
 
   _webProgressListeners: new Set(),
 
   _contentEventListenerSharedState: new Map(),
 
   _contentEventListeners: new Map(),
 
+  _contentEventListenerActorRegistered: false,
+
   /**
    * Waits for the web progress listener associated with this tab to fire a
    * STATE_STOP for the toplevel document.
    *
    * @param {xul:browser} browser
    *        A xul:browser.
    * @param {String} expectedURI (optional)
    *        A specific URL to check the channel load against
@@ -1146,47 +1152,70 @@ var BrowserTestUtils = {
    *        Name of the event to listen to.
    * @param {bool} capture [optional]
    *        Whether to use a capturing listener.
    * @param {function} checkFn [optional]
    *        Called with the Event object as argument, should return true if the
    *        event is the expected one, or false if it should be ignored and
    *        listening should continue. If not specified, the first event with
    *        the specified name resolves the returned promise.
-   * @param {bool} wantUntrusted [optional]
+   * @param {bool} wantsUntrusted [optional]
    *        Whether to accept untrusted events
    *
-   * @note As of bug 1588193, this function no longer rejects the returned
-   *       promise in the case of a checkFn error. Instead, since checkFn is now
-   *       called through eval in the content process, the error is thrown in
-   *       the listener created by ContentEventListenerChild. Work to improve
-   *       error handling (eg. to reject the promise as before and to preserve
-   *       the filename/stack) is being tracked in bug 1593811.
+   * @note Because this function is intended for testing, any error in checkFn
+   *       will cause the returned promise to be rejected instead of waiting for
+   *       the next event, since this is probably a bug in the test.
    *
    * @returns {Promise}
    */
   waitForContentEvent(
     browser,
     eventName,
     capture = false,
     checkFn,
-    wantUntrusted = false
+    wantsUntrusted = false
   ) {
-    return new Promise(resolve => {
-      let removeEventListener = this.addContentEventListener(
-        browser,
-        eventName,
-        () => {
-          removeEventListener();
-          resolve();
-        },
-        { capture, wantUntrusted },
-        checkFn
-      );
+    let parameters = {
+      eventName,
+      capture,
+      checkFnSource: checkFn ? checkFn.toSource() : null,
+      wantsUntrusted,
+    };
+    /* eslint-disable no-eval */
+    return ContentTask.spawn(browser, parameters, function({
+      eventName,
+      capture,
+      checkFnSource,
+      wantsUntrusted,
+    }) {
+      let checkFn;
+      if (checkFnSource) {
+        checkFn = eval(`(() => (${checkFnSource}))()`);
+      }
+      return new Promise((resolve, reject) => {
+        addEventListener(
+          eventName,
+          function listener(event) {
+            let completion = resolve;
+            try {
+              if (checkFn && !checkFn(event)) {
+                return;
+              }
+            } catch (e) {
+              completion = () => reject(e);
+            }
+            removeEventListener(eventName, listener, capture);
+            completion();
+          },
+          capture,
+          wantsUntrusted
+        );
+      });
     });
+    /* eslint-enable no-eval */
   },
 
   /**
    * Like waitForEvent, but acts on a popup. It ensures the popup is not already
    * in the expected state.
    *
    * @param {Element} popup
    *        The popup element that should receive the event.
@@ -1204,16 +1233,20 @@ var BrowserTestUtils = {
   },
 
   /**
    * Adds a content event listener on the given browser
    * element. Similar to waitForContentEvent, but the listener will
    * fire until it is removed. A callable object is returned that,
    * when called, removes the event listener. Note that this function
    * works even if the browser's frameloader is swapped.
+   * Note: This will only listen for events that either have the browsing
+   * context of the browser element at the time of the call, or that are fired
+   * on windows that were created after any call to the function since the start
+   * of the test. This could be improved if needed.
    *
    * @param {xul:browser} browser
    *        The browser element to listen for events in.
    * @param {string} eventName
    *        Name of the event to listen to.
    * @param {function} listener
    *        Function to call in parent process when event fires.
    *        Not passed any arguments.
@@ -1233,34 +1266,60 @@ var BrowserTestUtils = {
     browser,
     eventName,
     listener,
     listenerOptions = {},
     checkFn
   ) {
     let id = gListenerId++;
     let contentEventListeners = this._contentEventListeners;
-    contentEventListeners.set(id, {
-      listener,
-      browsingContext: browser.browsingContext,
-    });
+    contentEventListeners.set(id, { listener, browser });
 
     let eventListenerState = this._contentEventListenerSharedState;
     eventListenerState.set(id, {
       eventName,
       listenerOptions,
       checkFnSource: checkFn ? checkFn.toSource() : "",
     });
 
     Services.ppmm.sharedData.set(
       "BrowserTestUtils:ContentEventListener",
       eventListenerState
     );
     Services.ppmm.sharedData.flush();
 
+    if (!this._contentEventListenerActorRegistered) {
+      this._contentEventListenerActorRegistered = true;
+      registerContentEventListenerActor();
+
+      // We hadn't registered the actor yet, so any existing window
+      // for browser's BC will not have been created yet. Explicitly
+      // make sure the actors are created and ready to go now. This
+      // happens after the updating of sharedData so that the actors
+      // don't have to get created and do nothing, and then later have
+      // to be updated.
+      // Note: As mentioned in the comment at the start of this function,
+      // this will miss any windows that existed at the time that the function
+      // was initially called during this test, but that did not have the
+      // browser's browsing context.
+      let contextsToVisit = [browser.browsingContext];
+      while (contextsToVisit.length) {
+        let currentContext = contextsToVisit.pop();
+        let global = currentContext.currentWindowGlobal;
+        if (!global) {
+          continue;
+        }
+        let actor = browser.browsingContext.currentWindowGlobal.getActor(
+          "ContentEventListener"
+        );
+        actor.sendAsyncMessage("ContentEventListener:LateCreate");
+        contextsToVisit.push(...currentContext.getChildren());
+      }
+    }
+
     let unregisterFunction = function() {
       if (!eventListenerState.has(id)) {
         return;
       }
       eventListenerState.delete(id);
       contentEventListeners.delete(id);
       Services.ppmm.sharedData.set(
         "BrowserTestUtils:ContentEventListener",
@@ -1271,22 +1330,22 @@ var BrowserTestUtils = {
     return unregisterFunction;
   },
 
   /**
    * This is an internal method to be invoked by
    * BrowserTestUtilsParent.jsm when a content event we were listening for
    * happens.
    */
-  _receivedContentEventListener(listenerId, browsingContext) {
+  _receivedContentEventListener(listenerId, browser) {
     let listenerData = this._contentEventListeners.get(listenerId);
     if (!listenerData) {
       return;
     }
-    if (listenerData.browsingContext != browsingContext) {
+    if (listenerData.browser != browser) {
       return;
     }
     listenerData.listener();
   },
 
   /**
    * This is an internal method that cleans up any state from content event
    * listeners.
--- a/testing/mochitest/BrowserTestUtils/ContentEventListenerChild.jsm
+++ b/testing/mochitest/BrowserTestUtils/ContentEventListenerChild.jsm
@@ -20,16 +20,23 @@ class ContentEventListenerChild extends 
     this._shutdown = true;
     Services.cpmm.sharedData.removeEventListener("change", this);
     this._updateContentEventListeners(/* clearListeners = */ true);
     if (this._contentEvents.size != 0) {
       throw new Error(`Didn't expect content events after willDestroy`);
     }
   }
 
+  receiveMessage(msg) {
+    if (msg.name != "ContentEventListener:LateCreate") {
+      return;
+    }
+    this._updateContentEventListeners();
+  }
+
   handleEvent(event) {
     switch (event.type) {
       case "DOMWindowCreated": {
         this._updateContentEventListeners();
         break;
       }
 
       case "change": {
--- a/testing/mochitest/BrowserTestUtils/ContentEventListenerParent.jsm
+++ b/testing/mochitest/BrowserTestUtils/ContentEventListenerParent.jsm
@@ -9,17 +9,25 @@ var EXPORTED_SYMBOLS = ["ContentEventLis
 const { BrowserTestUtils } = ChromeUtils.import(
   "resource://testing-common/BrowserTestUtils.jsm"
 );
 
 class ContentEventListenerParent extends JSWindowActorParent {
   receiveMessage(aMessage) {
     switch (aMessage.name) {
       case "ContentEventListener:Run": {
+        let browser = this.browsingContext.top.embedderElement;
+        if (!browser) {
+          break;
+        }
+        // Handle RDM.
+        if (browser.outerBrowser) {
+          browser = browser.outerBrowser;
+        }
         BrowserTestUtils._receivedContentEventListener(
           aMessage.data.listenerId,
-          this.browsingContext
+          browser
         );
         break;
       }
     }
   }
 }
--- a/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
@@ -197,22 +197,17 @@ function testOnWindow(aTestData) {
         onContentBlockingEvent(aWebProgress, aRequest, aEvent) {
           expected = aTestData.reportUrl;
         },
         QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
       };
       wp.addProgressListener(progressListener, wp.NOTIFY_CONTENT_BLOCKING);
 
       await BrowserTestUtils.loadURI(browser, aTestData.url);
-      await BrowserTestUtils.browserLoaded(
-        browser,
-        false,
-        `http://${aTestData.url}`,
-        true
-      );
+      await BrowserTestUtils.waitForContentEvent(browser, "DOMContentLoaded");
       checkResults(aTestData, expected);
       win.close();
       resolve();
     })();
   });
 }
 SpecialPowers.pushPrefEnv(
   {"set": [
--- a/toolkit/mozapps/extensions/test/browser/browser_history_navigation.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_history_navigation.js
@@ -148,18 +148,32 @@ function is_in_discovery(aManager, url, 
   check_state(canGoBack, canGoForward);
 }
 
 async function expand_addon_element(aManager, aId) {
   var addon = get_addon_element(aManager, aId);
   addon.click();
 }
 
-function wait_for_page_load(browser) {
-  return BrowserTestUtils.browserLoaded(browser, false, "http://example.com/");
+function wait_for_page_show(browser) {
+  let promise = new Promise(resolve => {
+    let removeFunc;
+    let listener = () => {
+      removeFunc();
+      resolve();
+    };
+    removeFunc = BrowserTestUtils.addContentEventListener(
+      browser,
+      "pageshow",
+      listener,
+      {},
+      event => event.target.location == "http://example.com/"
+    );
+  });
+  return promise;
 }
 
 // Tests simple forward and back navigation and that the right heading and
 // category is selected
 add_task(async function test_navigate_history() {
   let aManager = await open_manager("addons://list/extension");
   info("Part 1");
   is_in_list(aManager, "addons://list/extension", false, false);
@@ -381,17 +395,17 @@ add_task(async function test_navigate_ba
     set: [["security.allow_eval_with_system_principal", true]],
   });
 
   let aManager = await open_manager("addons://list/plugin");
   info("Part 1");
   is_in_list(aManager, "addons://list/plugin", false, false);
 
   BrowserTestUtils.loadURI(gBrowser, "http://example.com/");
-  await wait_for_page_load(gBrowser.selectedBrowser);
+  await wait_for_page_show(gBrowser.selectedBrowser);
 
   info("Part 2");
 
   await new Promise(resolve =>
     executeSoon(function() {
       ok(gBrowser.canGoBack, "Should be able to go back");
       ok(!gBrowser.canGoForward, "Should not be able to go forward");
 
@@ -405,17 +419,17 @@ add_task(async function test_navigate_ba
 
         aManager = await wait_for_view_load(
           gBrowser.contentWindow.wrappedJSObject
         );
         info("Part 3");
         is_in_list(aManager, "addons://list/plugin", false, true);
 
         executeSoon(() => go_forward());
-        wait_for_page_load(gBrowser.selectedBrowser).then(() => {
+        wait_for_page_show(gBrowser.selectedBrowser).then(() => {
           info("Part 4");
 
           executeSoon(function() {
             ok(gBrowser.canGoBack, "Should be able to go back");
             ok(!gBrowser.canGoForward, "Should not be able to go forward");
 
             go_back();