Bug 1404917 - fix tests r=Honza draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 26 Oct 2017 15:58:50 -0700
changeset 696268 268e37e83b74999ca6e788c3dd1734b393790cc1
parent 696267 a9194a08b707e27052ebad87734b03db69be75d8
child 696269 120cac44662ee5156309b7facd01c806d6c39d97
push id88671
push userbmo:poirot.alex@gmail.com
push dateFri, 10 Nov 2017 10:12:58 +0000
reviewersHonza
bugs1404917
milestone58.0a1
Bug 1404917 - fix tests r=Honza MozReview-Commit-ID: C9aKaUoRjbB
devtools/client/netmonitor/test/browser.ini
devtools/client/netmonitor/test/browser_net_autoscroll.js
devtools/client/netmonitor/test/browser_net_brotli.js
devtools/client/netmonitor/test/browser_net_clear.js
devtools/client/netmonitor/test/browser_net_content-type.js
devtools/client/netmonitor/test/browser_net_headers-alignment.js
devtools/client/netmonitor/test/browser_net_resend_cors.js
devtools/client/netmonitor/test/browser_net_security-error.js
devtools/client/netmonitor/test/browser_net_security-state.js
devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
devtools/client/netmonitor/test/browser_net_simple-request-data.js
devtools/client/netmonitor/test/browser_net_streaming-response.js
devtools/client/netmonitor/test/head.js
devtools/client/netmonitor/test/html_infinite-get-page.html
devtools/client/netmonitor/test/shared-head.js
devtools/client/styleeditor/test/browser.ini
devtools/client/styleeditor/test/browser_styleeditor_fetch-from-cache.js
devtools/client/webconsole/new-console-output/test/mochitest/browser_netmonitor_shows_reqs_in_webconsole.js
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_attach.js
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_openinnet.js
devtools/client/webconsole/new-console-output/test/mochitest/head.js
devtools/client/webconsole/test/browser_netmonitor_shows_reqs_in_webconsole.js
devtools/client/webconsole/test/browser_webconsole_netlogging_panel.js
devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
   dropmarker.svg
   head.js
+  shared-head.js
   html_cause-test-page.html
   html_content-type-without-cache-test-page.html
   html_brotli-test-page.html
   html_image-tooltip-test-page.html
   html_cors-test-page.html
   html_custom-get-page.html
   html_cyrillic-test-page.html
   html_frame-test-page.html
--- a/devtools/client/netmonitor/test/browser_net_autoscroll.js
+++ b/devtools/client/netmonitor/test/browser_net_autoscroll.js
@@ -5,17 +5,17 @@
 
 /**
  * Bug 863102 - Automatically scroll down upon new network requests.
  * edited to account for changes made to fix Bug 1360457
  */
 add_task(function* () {
   requestLongerTimeout(4);
 
-  let { monitor } = yield initNetMonitor(INFINITE_GET_URL, true);
+  let { tab, monitor } = yield initNetMonitor(INFINITE_GET_URL, true);
   let { document, windowRequire, store } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Wait until the first request makes the empty notice disappear
   yield waitForRequestListToAppear();
 
@@ -52,16 +52,21 @@ add_task(function* () {
   // from just below the headers.
   store.dispatch(Actions.selectRequestByIndex(0));
   yield waitForNetworkEvents(monitor, 8);
   yield waitSomeTime();
   let requestsContainerHeaders = requestsContainer.firstChild;
   let headersHeight = requestsContainerHeaders.offsetHeight;
   is(requestsContainer.scrollTop, headersHeight, "Did not scroll.");
 
+  // Stop doing requests.
+  yield ContentTask.spawn(tab.linkedBrowser, {}, function () {
+    content.wrappedJSObject.stopRequests();
+  });
+
   // Done: clean up.
   return teardown(monitor);
 
   function waitForRequestListToAppear() {
     info("Waiting until the empty notice disappears and is replaced with the list");
     return waitUntil(() => !!document.querySelector(".requests-list-contents"));
   }
 
--- a/devtools/client/netmonitor/test/browser_net_brotli.js
+++ b/devtools/client/netmonitor/test/browser_net_brotli.js
@@ -46,21 +46,23 @@ add_task(function* () {
       type: "plain",
       fullMimeType: "text/plain",
       transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 60),
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 64),
       time: true
     });
 
   wait = waitForDOM(document, ".CodeMirror-code");
+  let onResponseContent = monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT);
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   yield wait;
+  yield onResponseContent;
   yield testResponse("br");
   yield teardown(monitor);
 
   function* testResponse(type) {
     switch (type) {
       case "br": {
         is(document.querySelector(".CodeMirror-line").textContent, "X".repeat(64),
           "The text shown in the source editor is incorrect for the brotli request.");
--- a/devtools/client/netmonitor/test/browser_net_clear.js
+++ b/devtools/client/netmonitor/test/browser_net_clear.js
@@ -8,40 +8,39 @@
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
-  let { EVENTS } = windowRequire("devtools/client/netmonitor/src/constants");
   let detailsPanelToggleButton = document.querySelector(".network-details-panel-toggle");
   let clearButton = document.querySelector(".requests-list-clear-button");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Make sure we start in a sane state
   assertNoRequestState();
 
   // Load one request and assert it shows up in the list
-  let networkEvent = monitor.panelWin.once(EVENTS.NETWORK_EVENT);
+  let onMonitorUpdated = waitForAllRequestsFinished(monitor);
   tab.linkedBrowser.reload();
-  yield networkEvent;
+  yield onMonitorUpdated;
 
   assertSingleRequestState();
 
   // Click clear and make sure the requests are gone
   EventUtils.sendMouseEvent({ type: "click" }, clearButton);
   assertNoRequestState();
 
   // Load a second request and make sure they still show up
-  networkEvent = monitor.panelWin.once(EVENTS.NETWORK_EVENT);
+  onMonitorUpdated = waitForAllRequestsFinished(monitor);
   tab.linkedBrowser.reload();
-  yield networkEvent;
+  yield onMonitorUpdated;
 
   assertSingleRequestState();
 
   // Make sure we can now open the network details panel
   EventUtils.sendMouseEvent({ type: "click" }, detailsPanelToggleButton);
 
   ok(document.querySelector(".network-details-panel") &&
     !detailsPanelToggleButton.classList.contains("pane-collapsed"),
--- a/devtools/client/netmonitor/test/browser_net_content-type.js
+++ b/devtools/client/netmonitor/test/browser_net_content-type.js
@@ -17,17 +17,17 @@ add_task(function* () {
   let {
     getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
-  yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
+  yield ContentTask.spawn(tab.linkedBrowser, {}, function () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
 
   for (let requestItem of document.querySelectorAll(".request-list-item")) {
     let requestsListStatus = requestItem.querySelector(".requests-list-status");
     requestItem.scrollIntoView();
     EventUtils.sendMouseEvent({ type: "mouseover" }, requestsListStatus);
@@ -137,35 +137,35 @@ add_task(function* () {
       type: "plain",
       fullMimeType: "text/plain",
       transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 324),
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73),
       time: true
     }
   );
 
-  yield selectIndexAndWaitForSourceEditor(0);
+  yield selectIndexAndWaitForSourceEditor(monitor, 0);
   yield testResponseTab("xml");
 
-  yield selectIndexAndWaitForSourceEditor(1);
+  yield selectIndexAndWaitForSourceEditor(monitor, 1);
   yield testResponseTab("css");
 
-  yield selectIndexAndWaitForSourceEditor(2);
+  yield selectIndexAndWaitForSourceEditor(monitor, 2);
   yield testResponseTab("js");
 
   yield selectIndexAndWaitForJSONView(3);
   yield testResponseTab("json");
 
-  yield selectIndexAndWaitForSourceEditor(4);
+  yield selectIndexAndWaitForSourceEditor(monitor, 4);
   yield testResponseTab("html");
 
   yield selectIndexAndWaitForImageView(5);
   yield testResponseTab("png");
 
-  yield selectIndexAndWaitForSourceEditor(6);
+  yield selectIndexAndWaitForSourceEditor(monitor, 6);
   yield testResponseTab("gzip");
 
   yield teardown(monitor);
 
   function* testResponseTab(type) {
     let tabpanel = document.querySelector("#response-panel");
 
     function checkVisibility(box) {
@@ -265,37 +265,31 @@ add_task(function* () {
 
         is(text, new Array(1000).join("Hello gzip!"),
           "The text shown in the source editor is incorrect for the gzip request.");
         break;
       }
     }
   }
 
-  function* selectIndexAndWaitForSourceEditor(index) {
-    let editor = document.querySelector("#response-panel .CodeMirror-code");
-    if (!editor) {
-      let waitDOM = waitForDOM(document, "#response-panel .CodeMirror-code");
-      EventUtils.sendMouseEvent({ type: "mousedown" },
-        document.querySelectorAll(".request-list-item")[index]);
-      document.querySelector("#response-tab").click();
-      yield waitDOM;
-    } else {
-      EventUtils.sendMouseEvent({ type: "mousedown" },
-        document.querySelectorAll(".request-list-item")[index]);
-    }
-  }
-
   function* selectIndexAndWaitForJSONView(index) {
+    let onResponseContent = monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT);
     let tabpanel = document.querySelector("#response-panel");
     let waitDOM = waitForDOM(tabpanel, ".treeTable");
     store.dispatch(Actions.selectRequestByIndex(index));
     yield waitDOM;
+    yield onResponseContent;
+
+    // Waiting for RECEIVED_RESPONSE_CONTENT isn't enough.
+    // DOM may not be fully updated yet and checkVisibility(json) may still fail.
+    yield waitForTick();
   }
 
   function* selectIndexAndWaitForImageView(index) {
+    let onResponseContent = monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT);
     let tabpanel = document.querySelector("#response-panel");
     let waitDOM = waitForDOM(tabpanel, ".response-image");
     store.dispatch(Actions.selectRequestByIndex(index));
     let [imageNode] = yield waitDOM;
     yield once(imageNode, "load");
+    yield onResponseContent;
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_headers-alignment.js
+++ b/devtools/client/netmonitor/test/browser_net_headers-alignment.js
@@ -5,17 +5,17 @@
 
 /**
  * Bug 1360457 - Mis-alignment between headers and columns on overflow
  */
 
 add_task(function* () {
   requestLongerTimeout(4);
 
-  let { monitor } = yield initNetMonitor(INFINITE_GET_URL, true);
+  let { tab, monitor } = yield initNetMonitor(INFINITE_GET_URL, true);
   let { document, windowRequire, store } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Wait until the first request makes the empty notice disappear
   yield waitForRequestListToAppear();
 
@@ -35,16 +35,21 @@ add_task(function* () {
     let aHeaderColumn = headers.childNodes[columnNumber];
     let aRequestColumn = firstRequestLine.childNodes[columnNumber];
     is(aHeaderColumn.getBoundingClientRect().left,
        aRequestColumn.getBoundingClientRect().left,
        "Headers for columns number " + columnNumber + " are aligned."
     );
   }
 
+  // Stop doing requests.
+  yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
+    content.wrappedJSObject.stopRequests();
+  });
+
   // Done: clean up.
   return teardown(monitor);
 
   function waitForRequestListToAppear() {
     info("Waiting until the empty notice disappears and is replaced with the list");
     return waitUntil(() => !!document.querySelector(".requests-list-contents"));
   }
 
--- a/devtools/client/netmonitor/test/browser_net_resend_cors.js
+++ b/devtools/client/netmonitor/test/browser_net_resend_cors.js
@@ -51,25 +51,29 @@ add_task(function* () {
     info("Sending the cloned request (without change)");
     store.dispatch(Actions.sendCustomRequest(connector));
   });
 
   info("Waiting for both resent requests");
   yield onRequests;
 
   // Check the resent requests
-  ITEMS.forEach((item, i) => {
+  for (let i = 0; i < ITEMS.length; i++) {
+    let item = ITEMS[i];
     is(item.method, METHODS[i], `The ${item.method} request has the right method`);
     is(item.url, requestUrl, `The ${item.method} request has the right URL`);
     is(item.status, 200, `The ${item.method} response has the right status`);
 
     if (item.method === "POST") {
+      // Force fetching response content
+      let responseContent = yield connector.requestData(item.id, "responseContent");
+
       is(item.requestPostData.postData.text, "post-data",
         "The POST request has the right POST data");
       // eslint-disable-next-line mozilla/no-cpows-in-tests
-      is(item.responseContent.content.text, "Access-Control-Allow-Origin: *",
+      is(responseContent.content.text, "Access-Control-Allow-Origin: *",
         "The POST response has the right content");
     }
-  });
+  }
 
   info("Finishing the test");
   return teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_security-error.js
+++ b/devtools/client/netmonitor/test/browser_net_security-error.js
@@ -42,19 +42,16 @@ add_task(function* () {
    * completed.
    */
   function waitForSecurityBrokenNetworkEvent() {
     let awaitedEvents = [
       "UPDATING_REQUEST_HEADERS",
       "RECEIVED_REQUEST_HEADERS",
       "UPDATING_REQUEST_COOKIES",
       "RECEIVED_REQUEST_COOKIES",
-      "STARTED_RECEIVING_RESPONSE",
-      "UPDATING_RESPONSE_CONTENT",
-      "RECEIVED_RESPONSE_CONTENT",
       "UPDATING_EVENT_TIMINGS",
       "RECEIVED_EVENT_TIMINGS",
       "UPDATING_SECURITY_INFO",
       "RECEIVED_SECURITY_INFO",
     ];
 
     let promises = awaitedEvents.map((event) => {
       return monitor.panelWin.once(EVENTS[event]);
--- a/devtools/client/netmonitor/test/browser_net_security-state.js
+++ b/devtools/client/netmonitor/test/browser_net_security-state.js
@@ -75,49 +75,40 @@ add_task(function* () {
     yield executeRequests(1, "http://test1.example.com" + CORS_SJS_PATH);
     yield done;
 
     done = waitForNetworkEvents(monitor, 1);
     info("Requesting a resource over HTTPS.");
     yield executeRequests(1, "https://example.com" + CORS_SJS_PATH);
     yield done;
 
-    done = waitForSecurityBrokenNetworkEvent(true);
+    done = waitForSecurityBrokenNetworkEvent();
     info("Requesting a resource over HTTP to localhost.");
     yield executeRequests(1, "http://localhost" + CORS_SJS_PATH);
     yield done;
 
     const expectedCount = Object.keys(EXPECTED_SECURITY_STATES).length;
     is(store.getState().requests.requests.size,
       expectedCount,
       expectedCount + " events logged.");
   }
 
   /**
    * Returns a promise that's resolved once a request with security issues is
    * completed.
    */
-  function waitForSecurityBrokenNetworkEvent(networkError) {
+  function waitForSecurityBrokenNetworkEvent() {
     let awaitedEvents = [
       "UPDATING_REQUEST_HEADERS",
       "RECEIVED_REQUEST_HEADERS",
       "UPDATING_REQUEST_COOKIES",
       "RECEIVED_REQUEST_COOKIES",
-      "STARTED_RECEIVING_RESPONSE",
-      "UPDATING_RESPONSE_CONTENT",
-      "RECEIVED_RESPONSE_CONTENT",
       "UPDATING_EVENT_TIMINGS",
       "RECEIVED_EVENT_TIMINGS",
     ];
 
-    // If the reason for breakage is a network error, then the
-    // STARTED_RECEIVING_RESPONSE event does not fire.
-    if (networkError) {
-      awaitedEvents = awaitedEvents.filter(e => e !== "STARTED_RECEIVING_RESPONSE");
-    }
-
     let promises = awaitedEvents.map((event) => {
       return monitor.panelWin.once(EVENTS[event]);
     });
 
     return Promise.all(promises);
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
+++ b/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
@@ -93,19 +93,16 @@ add_task(function* () {
    * completed.
    */
   function waitForSecurityBrokenNetworkEvent() {
     let awaitedEvents = [
       "UPDATING_REQUEST_HEADERS",
       "RECEIVED_REQUEST_HEADERS",
       "UPDATING_REQUEST_COOKIES",
       "RECEIVED_REQUEST_COOKIES",
-      "STARTED_RECEIVING_RESPONSE",
-      "UPDATING_RESPONSE_CONTENT",
-      "RECEIVED_RESPONSE_CONTENT",
       "UPDATING_EVENT_TIMINGS",
       "RECEIVED_EVENT_TIMINGS",
     ];
 
     let promises = awaitedEvents.map((event) => {
       return monitor.panelWin.once(EVENTS[event]);
     });
 
--- a/devtools/client/netmonitor/test/browser_net_simple-request-data.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-data.js
@@ -245,50 +245,34 @@ function test() {
         SIMPLE_SJS,
         {
           status: "200",
           statusText: "Och Aye"
         }
       );
     });
 
-    expectEvent(EVENTS.RECEIVED_RESPONSE_CONTENT, async () => {
+    expectEvent(EVENTS.PAYLOAD_READY, async () => {
       await waitUntil(() => {
         let requestItem = getSortedRequests(store.getState()).get(0);
         return requestItem &&
                requestItem.transferredSize &&
                requestItem.contentSize &&
-               requestItem.mimeType &&
-               requestItem.responseContent;
+               requestItem.mimeType;
       });
 
       let requestItem = getSortedRequests(store.getState()).get(0);
 
       is(requestItem.transferredSize, "342",
         "The transferredSize data has an incorrect value.");
       is(requestItem.contentSize, "12",
         "The contentSize data has an incorrect value.");
       is(requestItem.mimeType, "text/plain; charset=utf-8",
         "The mimeType data has an incorrect value.");
 
-      ok(requestItem.responseContent,
-        "There should be a responseContent data available.");
-      // eslint-disable-next-line mozilla/no-cpows-in-tests
-      is(requestItem.responseContent.content.mimeType,
-        "text/plain; charset=utf-8",
-        "The responseContent data has an incorrect |content.mimeType| property.");
-      // eslint-disable-next-line mozilla/no-cpows-in-tests
-      is(requestItem.responseContent.content.text,
-        "Hello world!",
-        "The responseContent data has an incorrect |content.text| property.");
-      // eslint-disable-next-line mozilla/no-cpows-in-tests
-      is(requestItem.responseContent.content.size,
-        12,
-        "The responseContent data has an incorrect |content.size| property.");
-
       verifyRequestItemTarget(
         document,
         getDisplayedRequests(store.getState()),
         requestItem,
         "GET",
         SIMPLE_SJS,
         {
           type: "plain",
--- a/devtools/client/netmonitor/test/browser_net_streaming-response.js
+++ b/devtools/client/netmonitor/test/browser_net_streaming-response.js
@@ -60,37 +60,23 @@ add_task(function* () {
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   yield wait;
 
   store.dispatch(Actions.selectRequest(null));
 
-  yield selectIndexAndWaitForSourceEditor(0);
+  yield selectIndexAndWaitForSourceEditor(monitor, 0);
   // the hls-m3u8 part
   testEditorContent(REQUESTS[0]);
 
-  yield selectIndexAndWaitForSourceEditor(1);
+  yield selectIndexAndWaitForSourceEditor(monitor, 1);
   // the mpeg-dash part
   testEditorContent(REQUESTS[1]);
 
   return teardown(monitor);
 
-  function* selectIndexAndWaitForSourceEditor(index) {
-    let editor = document.querySelector("#response-panel .CodeMirror-code");
-    if (!editor) {
-      let waitDOM = waitForDOM(document, "#response-panel .CodeMirror-code");
-      EventUtils.sendMouseEvent({ type: "mousedown" },
-        document.querySelectorAll(".request-list-item")[index]);
-      document.querySelector("#response-tab").click();
-      yield waitDOM;
-    } else {
-      EventUtils.sendMouseEvent({ type: "mousedown" },
-        document.querySelectorAll(".request-list-item")[index]);
-    }
-  }
-
   function testEditorContent([ fmt, textRe ]) {
     ok(document.querySelector(".CodeMirror-line").textContent.match(textRe),
       "The text shown in the source editor for " + fmt + " is correct.");
   }
 });
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -1,24 +1,28 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* import-globals-from ../../framework/test/shared-head.js */
+/* import-globals-from shared-head.js */
 /* exported Toolbox, restartNetMonitor, teardown, waitForExplicitFinish,
    verifyRequestItemTarget, waitFor, testFilterButtons, loadCommonFrameScript,
-   performRequestsInContent, waitForNetworkEvents */
+   performRequestsInContent, waitForNetworkEvents, selectIndexAndWaitForSourceEditor */
 
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
-const { EVENTS } = require("devtools/client/netmonitor/src/constants");
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js",
+  this);
+
 const {
   getFormattedIPAndPort,
   getFormattedTime,
 } = require("devtools/client/netmonitor/src/utils/format-utils");
 const {
   decodeUnicodeUrl,
   getFormattedProtocol,
   getUrlBaseName,
@@ -276,16 +280,22 @@ function restartNetMonitor(monitor, newU
 }
 
 function teardown(monitor) {
   info("Destroying the specified network monitor.");
 
   return Task.spawn(function* () {
     let tab = monitor.toolbox.target.tab;
 
+    // Ensure that there is no pending RDP requests related to payload request
+    // done from FirefoxDataProvider.
+    info("Wait for completion of all pending RDP requests...");
+    yield waitForExistingRequests(monitor);
+    info("All pending requests finished.");
+
     let onDestroyed = monitor.once("destroyed");
     yield removeTab(tab);
     yield onDestroyed;
   });
 }
 
 function waitForNetworkEvents(monitor, getRequests, postRequests = 0) {
   return new Promise((resolve) => {
@@ -301,23 +311,24 @@ function waitForNetworkEvents(monitor, g
       ["UPDATING_REQUEST_COOKIES", onGenericEvent],
       ["RECEIVED_REQUEST_COOKIES", onGenericEvent],
       ["UPDATING_REQUEST_POST_DATA", onPostEvent],
       ["RECEIVED_REQUEST_POST_DATA", onPostEvent],
       ["UPDATING_RESPONSE_HEADERS", onGenericEvent],
       ["RECEIVED_RESPONSE_HEADERS", onGenericEvent],
       ["UPDATING_RESPONSE_COOKIES", onGenericEvent],
       ["RECEIVED_RESPONSE_COOKIES", onGenericEvent],
-      ["STARTED_RECEIVING_RESPONSE", onGenericEvent],
-      ["UPDATING_RESPONSE_CONTENT", onGenericEvent],
-      ["RECEIVED_RESPONSE_CONTENT", onGenericEvent],
       ["UPDATING_EVENT_TIMINGS", onGenericEvent],
       ["RECEIVED_EVENT_TIMINGS", onGenericEvent],
       ["PAYLOAD_READY", onPayloadReady]
     ];
+    let expectedGenericEvents = awaitedEventsToListeners
+      .filter(([, listener]) => listener == onGenericEvent).length;
+    let expectedPostEvents = awaitedEventsToListeners
+      .filter(([, listener]) => listener == onPostEvent).length;
 
     function initProgressForURL(url) {
       if (progress[url]) {
         return;
       }
       progress[url] = {};
       awaitedEventsToListeners.forEach(function ([e]) {
         progress[url][e] = 0;
@@ -360,32 +371,34 @@ function waitForNetworkEvents(monitor, g
       }
 
       payloadReady++;
       maybeResolve(event, actor, networkInfo);
     }
 
     function maybeResolve(event, actor, networkInfo) {
       info("> Network events progress: " +
-        genericEvents + "/" + ((getRequests + postRequests) * 13) + ", " +
-        postEvents + "/" + (postRequests * 2) + ", " +
+        "Payload: " + payloadReady + "/" + (getRequests + postRequests) + ", " +
+        "Generic: " + genericEvents + "/" +
+          ((getRequests + postRequests) * expectedGenericEvents) + ", " +
+        "Post: " + postEvents + "/" + (postRequests * expectedPostEvents) + ", " +
         "got " + event + " for " + actor);
 
       let url = networkInfo.request.url;
       updateProgressForURL(url, event);
 
       // Uncomment this to get a detailed progress logging (when debugging a test)
       // info("> Current state: " + JSON.stringify(progress, null, 2));
 
-      // There are 15 updates which need to be fired for a request to be
-      // considered finished. The "requestPostData" packet isn't fired for
-      // non-POST requests.
+      // There are `expectedGenericEvents` updates which need to be fired for a request
+      // to be considered finished. The "requestPostData" packet isn't fired for non-POST
+      // requests.
       if (payloadReady >= (getRequests + postRequests) &&
-        genericEvents >= (getRequests + postRequests) * 13 &&
-        postEvents >= postRequests * 2) {
+        genericEvents >= (getRequests + postRequests) * expectedGenericEvents &&
+        postEvents >= postRequests * expectedPostEvents) {
         awaitedEventsToListeners.forEach(([e, l]) => panel.off(EVENTS[e], l));
         executeSoon(resolve);
       }
     }
 
     awaitedEventsToListeners.forEach(([e, l]) => panel.on(EVENTS[e], l));
   });
 }
@@ -679,8 +692,30 @@ function waitForContentMessage(name) {
 
   return new Promise((resolve) => {
     mm.addMessageListener(name, function onMessage(msg) {
       mm.removeMessageListener(name, onMessage);
       resolve(msg);
     });
   });
 }
+
+/**
+ * Select a request and switch to its response panel.
+ *
+ * @param {Number} index The request index to be selected
+ */
+async function selectIndexAndWaitForSourceEditor(monitor, index) {
+  let document = monitor.panelWin.document;
+  let onResponseContent = monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT);
+  // Select the request first, as it may try to fetch whatever is the current request's
+  // responseContent if we select the ResponseTab first.
+  EventUtils.sendMouseEvent({ type: "mousedown" },
+    document.querySelectorAll(".request-list-item")[index]);
+  // We may already be on the ResponseTab, so only select it if needed.
+  let editor = document.querySelector("#response-panel .CodeMirror-code");
+  if (!editor) {
+    let waitDOM = waitForDOM(document, "#response-panel .CodeMirror-code");
+    document.querySelector("#response-tab").click();
+    await waitDOM;
+  }
+  await onResponseContent;
+}
--- a/devtools/client/netmonitor/test/html_infinite-get-page.html
+++ b/devtools/client/netmonitor/test/html_infinite-get-page.html
@@ -26,18 +26,24 @@
             callback();
           }
         };
         xhr.send(null);
       }
 
       // Use a count parameter to defeat caching.
       let count = 0;
+      let doRequests = true;
+      function stopRequests() { // eslint-disable-line no-unused-vars
+        doRequests = false;
+      }
 
       (function performRequests() {
         get("request_" + (count++), function () {
-          setTimeout(performRequests, 50);
+          if (doRequests) {
+            setTimeout(performRequests, 50);
+          }
         });
       })();
     </script>
   </body>
 
 </html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/shared-head.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* exported EVENTS, waitForExistingRequests */
+
+"use strict";
+
+const { EVENTS } = require("devtools/client/netmonitor/src/constants");
+
+async function waitForExistingRequests(monitor) {
+  let { store } = monitor.panelWin;
+  function getRequests() {
+    return store.getState().requests.requests;
+  }
+  function areAllRequestsFullyLoaded() {
+    let requests = getRequests().valueSeq();
+    for (let request of requests) {
+      // Ignore cloned request as we don't lazily fetch data for them
+      // and have arbitrary number of field set.
+      if (request.id.includes("-clone")) {
+        continue;
+      }
+      // Do same check than FirefoxDataProvider.isRequestPayloadReady,
+      // in order to ensure there is no more pending payload requests to be done.
+      if (!request.requestHeaders || !request.requestCookies ||
+          !request.eventTimings ||
+          (!request.securityInfo && !request.fromServiceWorker) ||
+          ((!request.responseHeaders || !request.responseCookies) &&
+            request.securityState != "broken" &&
+            (!request.responseContentAvailable || request.status))) {
+        return false;
+      }
+    }
+    return true;
+  }
+  // If there is no request, we are good to go.
+  if (getRequests().size == 0) {
+    return;
+  }
+  while (!areAllRequestsFullyLoaded()) {
+    await monitor.panelWin.once(EVENTS.PAYLOAD_READY);
+  }
+}
--- a/devtools/client/styleeditor/test/browser.ini
+++ b/devtools/client/styleeditor/test/browser.ini
@@ -53,16 +53,17 @@ support-files =
   doc_xulpage.xul
   sync.html
   utf-16.css
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/inspector/shared/test/head.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
+  !/devtools/client/netmonitor/test/shared-head.js
   !/devtools/client/responsive.html/test/browser/devices.json
   !/devtools/client/shared/test/test-actor-registry.js
   !/devtools/client/shared/test/test-actor.js
 
 [browser_styleeditor_add_stylesheet.js]
 [browser_styleeditor_autocomplete.js]
 [browser_styleeditor_autocomplete-disabled.js]
 [browser_styleeditor_bom.js]
--- a/devtools/client/styleeditor/test/browser_styleeditor_fetch-from-cache.js
+++ b/devtools/client/styleeditor/test/browser_styleeditor_fetch-from-cache.js
@@ -1,16 +1,21 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
+/* import-globals-from ../../netmonitor/test/shared-head.js */
+
 // A test to ensure Style Editor doesn't bybass cache when loading style sheet
 // contents (bug 978688).
 
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
+
 const TEST_URL = TEST_BASE_HTTP + "doc_uncached.html";
 
 add_task(function* () {
   // Disable rcwn to make cache behavior deterministic.
   yield pushPref("network.http.rcwn.enabled", false);
 
   info("Opening netmonitor");
   let tab = yield addTab("about:blank");
@@ -29,16 +34,18 @@ add_task(function* () {
   yield navigateTo(TEST_URL);
 
   info("Opening Style Editor");
   let styleeditor = yield toolbox.selectTool("styleeditor");
 
   info("Waiting for the source to be loaded.");
   yield styleeditor.UI.editors[0].getSourceEditor();
 
+  yield waitForExistingRequests(monitor);
+
   info("Checking Netmonitor contents.");
   let items = [];
   for (let item of getSortedRequests(store.getState())) {
     if (item.url.endsWith("doc_uncached.css")) {
       items.push(item);
     }
   }
 
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_netmonitor_shows_reqs_in_webconsole.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_netmonitor_shows_reqs_in_webconsole.js
@@ -59,9 +59,11 @@ async function testNetmonitor(toolbox) {
   await waitUntil(() => store.getState().requests.requests.size > 0);
 
   is(store.getState().requests.requests.size, 1,
     "Network request appears in the network panel");
 
   let item = getSortedRequests(store.getState()).get(0);
   is(item.method, "GET", "The attached method is correct.");
   is(item.url, TEST_PATH, "The attached url is correct.");
+
+  await waitForExistingRequests(monitor);
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_attach.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_attach.js
@@ -44,16 +44,18 @@ add_task(async function task() {
   // Expand network log
   urlNode.click();
 
   await consoleReady;
 
   info("network-request-payload-ready received");
 
   await testNetworkMessage(messageNode);
+
+  await waitForExistingRequests(monitor);
 });
 
 async function testNetworkMessage(messageNode) {
   let headersTab = messageNode.querySelector("#headers-tab");
 
   ok(headersTab, "Headers tab is available");
 
   // Headers tab should be selected by default, so just check its content.
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_openinnet.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_openinnet.js
@@ -70,9 +70,12 @@ async function testNetmonitorLink(toolbo
   store.dispatch(actions.batchEnable(false));
 
   await waitUntil(() => {
     const selected = getSelectedRequest(store.getState());
     return selected && selected.url === url;
   });
 
   ok(true, "The attached url is correct.");
+
+  let monitor = toolbox.getCurrentPanel();
+  await waitForExistingRequests(monitor);
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/head.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/head.js
@@ -1,26 +1,30 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 /* import-globals-from ../../../../framework/test/shared-head.js */
+/* import-globals-from ../../../../netmonitor/test/shared-head.js */
 /* exported WCUL10n, openNewTabAndConsole, waitForMessages, waitForMessage, waitFor,
    findMessage, openContextMenu, hideContextMenu, loadDocument, hasFocus,
    waitForNodeMutation, testOpenInDebugger, checkClickOnNode, jstermSetValueAndComplete,
    openDebugger, openConsole */
 
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 // Load the shared-head file first.
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
+
 var {HUDService} = require("devtools/client/webconsole/hudservice");
 var WCUL10n = require("devtools/client/webconsole/webconsole-l10n");
 
 Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true);
 registerCleanupFunction(function* () {
   Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
   Services.prefs.clearUserPref("devtools.webconsole.ui.filterbar");
 
--- a/devtools/client/webconsole/test/browser_netmonitor_shows_reqs_in_webconsole.js
+++ b/devtools/client/webconsole/test/browser_netmonitor_shows_reqs_in_webconsole.js
@@ -1,15 +1,18 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
+
 const TEST_URI = "data:text/html;charset=utf8,Test that the netmonitor " +
                  "displays requests that have been recorded in the " +
                  "web console, even if the netmonitor hadn't opened yet.";
 
 const TEST_FILE = "test-network-request.html";
 const TEST_PATH = "http://example.com/browser/devtools/client/webconsole/" +
                   "test/" + TEST_FILE;
 
@@ -71,9 +74,11 @@ function* testNetmonitor(toolbox) {
 
   yield waitUntil(() => store.getState().requests.requests.size > 0);
 
   is(store.getState().requests.requests.size, 1, "Network request appears in the network panel");
 
   let item = getSortedRequests(store.getState()).get(0);
   is(item.method, "GET", "The attached method is correct.");
   is(item.url, TEST_PATH, "The attached url is correct.");
+
+  yield waitForExistingRequests(monitor);
 }
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging_panel.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging_panel.js
@@ -1,34 +1,41 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+/* import-globals-from ../../netmonitor/test/shared-head.js */
+
 // Tests that network log messages bring up the network panel.
 
 "use strict";
 
 const TEST_NETWORK_REQUEST_URI =
   "http://example.com/browser/devtools/client/webconsole/test/" +
   "test-network-request.html";
 
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
+
 add_task(function* () {
   let finishedRequest = waitForFinishedRequest(({ request }) => {
     return request.url.endsWith("test-network-request.html");
   });
 
   const hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
   let request = yield finishedRequest;
 
   yield hud.ui.openNetworkPanel(request.actor);
   let toolbox = gDevTools.getToolbox(hud.target);
   is(toolbox.currentToolId, "netmonitor", "Network panel was opened");
-  let panel = toolbox.getCurrentPanel();
+  let monitor = toolbox.getCurrentPanel();
 
-  let { store, windowRequire } = panel.panelWin;
+  let { store, windowRequire } = monitor.panelWin;
   let { getSelectedRequest } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   let selected = getSelectedRequest(store.getState());
   is(selected.method, request.request.method,
      "The correct request is selected");
   is(selected.url, request.request.url,
      "The correct request is definitely selected");
+
+  yield waitForExistingRequests(monitor);
 });
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js
@@ -1,23 +1,28 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+/* import-globals-from ../../netmonitor/test/shared-head.js */
+
 // Tests that network log messages bring up the network panel and select the
 // right request even if it was previously filtered off.
 
 "use strict";
 
 const TEST_FILE_URI =
   "http://example.com/browser/devtools/client/webconsole/test/" +
   "test-network.html";
 const TEST_URI = "data:text/html;charset=utf8,<p>test file URI";
 
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
+
 var hud;
 
 add_task(function* () {
   let requests = [];
   let { browser } = yield loadTab(TEST_URI);
 
   yield pushPrefEnv();
   hud = yield openConsole();
@@ -32,18 +37,18 @@ add_task(function* () {
   yield testMessages();
   let htmlRequest = requests.find(e => e.request.url.endsWith("html"));
   ok(htmlRequest, "htmlRequest was a html");
 
   yield hud.ui.openNetworkPanel(htmlRequest.actor);
   let toolbox = gDevTools.getToolbox(hud.target);
   is(toolbox.currentToolId, "netmonitor", "Network panel was opened");
 
-  let panel = toolbox.getCurrentPanel();
-  let { store, windowRequire } = panel.panelWin;
+  let monitor = toolbox.getCurrentPanel();
+  let { store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   let { getSelectedRequest } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   let selected = getSelectedRequest(store.getState());
   is(selected.method, htmlRequest.request.method,
      "The correct request is selected");
   is(selected.url, htmlRequest.request.url,
      "The correct request is definitely selected");
@@ -59,16 +64,18 @@ add_task(function* () {
   is(selected.method, htmlRequest.request.method,
      "The correct request is selected");
   is(selected.url, htmlRequest.request.url,
      "The correct request is definitely selected");
 
   // All tests are done. Shutdown.
   HUDService.lastFinishedRequest.callback = null;
   htmlRequest = browser = requests = hud = null;
+
+  yield waitForExistingRequests(monitor);
 });
 
 function testMessages() {
   return waitForMessages({
     webconsole: hud,
     messages: [{
       text: "running network console logging tests",
       category: CATEGORY_WEBDEV,