Backed out 4 changesets (bug 1588193) for Broswer-chrome failures on browser/base/content/test/favicons/browser_favicon_change_not_in_document.js. CLOSED TREE
authorDorel Luca <dluca@mozilla.com>
Wed, 06 Nov 2019 21:30:29 +0200
changeset 500904 42999b620bba2e3cabf71af4928b8716dcb11fc8
parent 500903 0984b2197e4b9d7d2fc17b4310f9acf46f098066
child 500905 bf88c8cec276cfa04f11ec93df35f455a0287e9b
push id114166
push userapavel@mozilla.com
push dateThu, 07 Nov 2019 10:04:01 +0000
treeherdermozilla-inbound@d271c572a9bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1588193
milestone72.0a1
backs outdf4c4004abc5aeb874666f06f0d49f059c94481f
1beab20978b27832e8ec3222c3cffbcc4d11e862
1ada54e7ba7c2cf72aa2f19c71aeb1f535c9d1ea
a0d9537d24c66ed3a6f8c7c60aca47f14e57b110
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 Broswer-chrome failures on browser/base/content/test/favicons/browser_favicon_change_not_in_document.js. CLOSED TREE Backed out changeset df4c4004abc5 (bug 1588193) Backed out changeset 1beab20978b2 (bug 1588193) Backed out changeset 1ada54e7ba7c (bug 1588193) Backed out changeset a0d9537d24c6 (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.top
+          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();