summaryrefslogtreecommitdiffstats
path: root/testing/talos/talos/tests/devtools/addon/content/tests/netmonitor/netmonitor-helpers.js
blob: f981c399f620e9d5dc9f9b1360f5fdc47aa895fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const { EVENTS } = require("devtools/client/netmonitor/src/constants");
const Actions = require("devtools/client/netmonitor/src/actions/index");
const {
  getToolbox,
  runTest,
  waitForDOMElement,
} = require("damp-test/tests/head");

/**
 * Start monitoring all incoming update events about network requests and wait until
 * a complete info about all requests is received. (We wait for the timings info
 * explicitly, because that's always the last piece of information that is received.)
 *
 * This method is designed to wait for network requests that are issued during a page
 * load, when retrieving page resources (scripts, styles, images). It has certain
 * assumptions that can make it unsuitable for other types of network communication:
 * - it waits for at least one network request to start and finish before returning
 * - it waits only for request that were issued after it was called. Requests that are
 *   already in mid-flight will be ignored.
 * - the request start and end times are overlapping. If a new request starts a moment
 *   after the previous one was finished, the wait will be ended in the "interim"
 *   period.
 *
 * We might need to allow a range of requests because even though we run with
 * cache disabled, different loads can still be coalesced, and whether they're
 * coalesced or not depends on timing.
 *
 * @returns a promise that resolves when the wait is done.
 */
async function waitForAllRequestsFinished(
  minExpectedRequests,
  maxExpectedRequests
) {
  let toolbox = getToolbox();
  let window = toolbox.getCurrentPanel().panelWin;

  return new Promise(resolve => {
    // Explicitly waiting for specific number of requests arrived
    let payloadReady = 0;
    let resolveWithLessThanMaxRequestsTimer = null;

    function onPayloadReady() {
      payloadReady++;
      dump(`Waiting for ${maxExpectedRequests - payloadReady} requests\n`);
      maybeResolve();
    }

    function doResolve() {
      // All requests are done - unsubscribe from events and resolve!
      window.api.off(EVENTS.PAYLOAD_READY, onPayloadReady);
      // Resolve after current frame
      setTimeout(resolve, 1);
    }

    function maybeResolve() {
      if (resolveWithLessThanMaxRequestsTimer) {
        clearTimeout(resolveWithLessThanMaxRequestsTimer);
        resolveWithLessThanMaxRequestsTimer = null;
      }

      // Have all the requests finished yet?
      if (payloadReady >= maxExpectedRequests) {
        doResolve();
        return;
      }

      // If we're past the minimum threshold, wait to see if more requests come
      // up, but resolve otherwise.
      if (payloadReady >= minExpectedRequests) {
        resolveWithLessThanMaxRequestsTimer = setTimeout(doResolve, 1000);
      }
    }

    window.api.on(EVENTS.PAYLOAD_READY, onPayloadReady);
  });
}

function waitForLoad(iframe) {
  return new Promise(resolve => iframe.addEventListener("load", resolve));
}

function clickElement(el, win) {
  const clickEvent = new win.MouseEvent("click", {
    bubbles: true,
    cancelable: true,
    view: win,
  });
  el.dispatchEvent(clickEvent);
}

function mouseDownElement(el, win) {
  const mouseEvent = new win.MouseEvent("mousedown", {
    bubbles: true,
    cancelable: true,
    view: win,
  });
  el.dispatchEvent(mouseEvent);
}

exports.waitForNetworkRequests = async function (
  label,
  toolbox,
  minExpectedRequests,
  maxExpectedRequests = minExpectedRequests
) {
  let test = runTest(label + ".requestsFinished.DAMP");
  await waitForAllRequestsFinished(minExpectedRequests, maxExpectedRequests);
  test.done();
};

exports.exportHar = async function (label, toolbox) {
  let test = runTest(label + ".exportHar");

  // Export HAR from the Network panel.
  await toolbox.getHARFromNetMonitor();

  test.done();
};

exports.openResponseDetailsPanel = async function (label, toolbox) {
  const win = toolbox.getCurrentPanel().panelWin;
  const { document, store } = win;
  const monitor = document.querySelector(".monitor-panel");

  // html test
  const testHtml = runTest(label + ".responsePanel.html");

  store.dispatch(Actions.batchEnable(false));

  const waitForDetailsBar = waitForDOMElement(monitor, ".network-details-bar");
  store.dispatch(Actions.toggleNetworkDetails());
  await waitForDetailsBar;

  const sideBar = document.querySelector(".network-details-bar");
  const iframeSelector = "#response-panel .html-preview iframe";
  const waitForIframe = waitForDOMElement(sideBar, iframeSelector);

  clickElement(document.querySelector("#response-tab"), win);

  await waitForIframe;
  await waitForLoad(document.querySelector(iframeSelector));

  testHtml.done();

  // close the sidebar
  store.dispatch(Actions.toggleNetworkDetails());

  // Sort the request list on the size column (in descending order)
  // to make sure we use the largest response.
  const sizeColumnHeader = document.querySelector(
    "#requests-list-contentSize-button"
  );
  const waitForDesc = waitForDOMElement(
    sizeColumnHeader.parentNode,
    "#requests-list-contentSize-button[data-sorted='descending']"
  );
  // Click the size header twice to make sure the requests
  // are sorted in descending order.
  clickElement(sizeColumnHeader, win);
  clickElement(sizeColumnHeader, win);
  await waitForDesc;

  // editor test
  const testEditor = runTest(label + ".responsePanel.editor");
  const request = document.querySelectorAll(".request-list-item")[0];
  const waitForEditor = waitForDOMElement(
    monitor,
    "#response-panel .CodeMirror.cm-s-mozilla"
  );
  mouseDownElement(request, win);
  await waitForEditor;

  testEditor.done();
  store.dispatch(Actions.toggleNetworkDetails());
};