Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / devtools / client / netmonitor / test / browser_net_initiator.js
blob94fa3a86246def952598fb4aeaf7cab4e5aa1266
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 "use strict";
5 const {
6 getUrlBaseName,
7 } = require("resource://devtools/client/netmonitor/src/utils/request-utils.js");
8 /**
9 * Tests if request initiator is reported correctly.
12 const INITIATOR_FILE_NAME = "html_cause-test-page.html";
13 const INITIATOR_URL = HTTPS_EXAMPLE_URL + INITIATOR_FILE_NAME;
15 const EXPECTED_REQUESTS = [
17 method: "GET",
18 url: INITIATOR_URL,
19 causeType: "document",
20 causeUri: null,
21 stack: false,
24 method: "GET",
25 url: HTTPS_EXAMPLE_URL + "stylesheet_request",
26 causeType: "stylesheet",
27 causeUri: INITIATOR_URL,
28 stack: false,
31 method: "GET",
32 url: HTTPS_EXAMPLE_URL + "img_request",
33 causeType: "img",
34 causeUri: INITIATOR_URL,
35 stack: false,
38 method: "GET",
39 url: HTTPS_EXAMPLE_URL + "img_srcset_request",
40 causeType: "imageset",
41 causeUri: INITIATOR_URL,
42 stack: false,
45 method: "GET",
46 url: HTTPS_EXAMPLE_URL + "xhr_request",
47 causeType: "xhr",
48 causeUri: INITIATOR_URL,
49 stack: [{ fn: "performXhrRequestCallback", file: INITIATOR_URL, line: 32 }],
52 method: "GET",
53 url: HTTPS_EXAMPLE_URL + "fetch_request",
54 causeType: "fetch",
55 causeUri: INITIATOR_URL,
56 stack: [{ fn: "performFetchRequest", file: INITIATOR_URL, line: 37 }],
59 method: "GET",
60 url: HTTPS_EXAMPLE_URL + "promise_fetch_request",
61 causeType: "fetch",
62 causeUri: INITIATOR_URL,
63 stack: [
65 fn: "performPromiseFetchRequestCallback",
66 file: INITIATOR_URL,
67 line: 43,
70 fn: "performPromiseFetchRequest",
71 file: INITIATOR_URL,
72 line: 42,
73 asyncCause: "promise callback",
78 method: "GET",
79 url: HTTPS_EXAMPLE_URL + "timeout_fetch_request",
80 causeType: "fetch",
81 causeUri: INITIATOR_URL,
82 stack: [
84 fn: "performTimeoutFetchRequestCallback2",
85 file: INITIATOR_URL,
86 line: 50,
89 fn: "performTimeoutFetchRequestCallback1",
90 file: INITIATOR_URL,
91 line: 49,
92 asyncCause: "setTimeout handler",
97 method: "GET",
98 url: HTTPS_EXAMPLE_URL + "favicon_request",
99 causeType: "img",
100 causeUri: INITIATOR_URL,
101 // the favicon request is triggered in FaviconLoader.sys.mjs module, it should
102 // NOT be shown in the stack (bug 1280266). For now we intentionally
103 // specify the file and the line number to be properly sorted.
104 // NOTE: The line number can be an arbitrary number greater than 0.
105 stack: [
107 file: "resource:///modules/FaviconLoader.sys.mjs",
108 line: Number.MAX_SAFE_INTEGER,
113 method: "GET",
114 url: HTTPS_EXAMPLE_URL + "lazy_img_request",
115 causeType: "lazy-img",
116 causeUri: INITIATOR_URL,
117 stack: false,
120 method: "GET",
121 url: HTTPS_EXAMPLE_URL + "lazy_img_srcset_request",
122 causeType: "lazy-imageset",
123 causeUri: INITIATOR_URL,
124 stack: false,
127 method: "POST",
128 url: HTTPS_EXAMPLE_URL + "beacon_request",
129 causeType: "beacon",
130 causeUri: INITIATOR_URL,
131 stack: [{ fn: "performBeaconRequest", file: INITIATOR_URL, line: 82 }],
135 add_task(async function () {
136 // the initNetMonitor function clears the network request list after the
137 // page is loaded. That's why we first load a bogus page from SIMPLE_URL,
138 // and only then load the real thing from INITIATOR_URL - we want to catch
139 // all the requests the page is making, not only the XHRs.
140 // We can't use about:blank here, because initNetMonitor checks that the
141 // page has actually made at least one request.
142 const { tab, monitor } = await initNetMonitor(SIMPLE_URL, {
143 requestCount: 1,
146 const { document, store, windowRequire } = monitor.panelWin;
147 const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
148 const { getSortedRequests } = windowRequire(
149 "devtools/client/netmonitor/src/selectors/index"
152 store.dispatch(Actions.batchEnable(false));
154 const wait = waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
155 BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, INITIATOR_URL);
157 registerFaviconNotifier(tab.linkedBrowser);
159 await wait;
161 // For all expected requests
162 for (const [index, { stack }] of EXPECTED_REQUESTS.entries()) {
163 if (!stack) {
164 continue;
167 EventUtils.sendMouseEvent(
168 { type: "mousedown" },
169 document.querySelectorAll(
170 ".request-list-item .requests-list-initiator-lastframe"
171 )[index]
174 // Clicking on the initiator column should open the Stack Trace panel
175 const onStackTraceRendered = waitUntil(() =>
176 document.querySelector("#stack-trace-panel .stack-trace .frame-link")
178 await onStackTraceRendered;
182 store.getState().requests.requests.length,
183 EXPECTED_REQUESTS.length,
184 "All the page events should be recorded."
187 validateRequests(EXPECTED_REQUESTS, monitor);
189 // Sort the requests by initiator and check the order
190 EventUtils.sendMouseEvent(
191 { type: "click" },
192 document.querySelector("#requests-list-initiator-button")
195 const expectedOrder = EXPECTED_REQUESTS.sort(initiatorSortPredicate).map(
196 r => {
197 let isChromeFrames = false;
198 const lastFrameExists = !!r.stack;
199 let initiator = "";
200 let lineNumber = "";
201 if (lastFrameExists) {
202 const { file, line: _lineNumber } = r.stack[0];
203 initiator = getUrlBaseName(file);
204 lineNumber = ":" + _lineNumber;
205 isChromeFrames = file.startsWith("resource:///");
207 const causeStr = lastFrameExists ? " (" + r.causeType + ")" : r.causeType;
208 return {
209 initiatorStr: initiator + lineNumber + causeStr,
210 isChromeFrames,
215 expectedOrder.forEach((expectedInitiator, i) => {
216 const request = getSortedRequests(store.getState())[i];
217 let initiator;
218 // In cases of chrome frames, we shouldn't have stack.
219 if (
220 request.cause.stacktraceAvailable &&
221 !expectedInitiator.isChromeFrames
223 const { filename, lineNumber } = request.cause.lastFrame;
224 initiator =
225 getUrlBaseName(filename) +
226 ":" +
227 lineNumber +
228 " (" +
229 request.cause.type +
230 ")";
231 } else {
232 initiator = request.cause.type;
235 if (expectedInitiator.isChromeFrames) {
236 todo_is(
237 initiator,
238 expectedInitiator.initiatorStr,
239 `The request #${i} has the expected initiator after sorting`
241 } else {
243 initiator,
244 expectedInitiator.initiatorStr,
245 `The request #${i} has the expected initiator after sorting`
250 await teardown(monitor);
253 // derived from devtools/client/netmonitor/src/utils/sort-predicates.js
254 function initiatorSortPredicate(first, second) {
255 const firstLastFrame = first.stack ? first.stack[0] : null;
256 const secondLastFrame = second.stack ? second.stack[0] : null;
258 let firstInitiator = "";
259 let firstInitiatorLineNumber = 0;
261 if (firstLastFrame) {
262 firstInitiator = getUrlBaseName(firstLastFrame.file);
263 firstInitiatorLineNumber = firstLastFrame.line;
266 let secondInitiator = "";
267 let secondInitiatorLineNumber = 0;
269 if (secondLastFrame) {
270 secondInitiator = getUrlBaseName(secondLastFrame.file);
271 secondInitiatorLineNumber = secondLastFrame.line;
274 let result;
275 // if both initiators don't have a stack trace, compare their causes
276 if (!firstInitiator && !secondInitiator) {
277 result = compareValues(first.causeType, second.causeType);
278 } else if (!firstInitiator || !secondInitiator) {
279 // if one initiator doesn't have a stack trace but the other does, former should precede the latter
280 result = compareValues(firstInitiatorLineNumber, secondInitiatorLineNumber);
281 } else {
282 result = compareValues(firstInitiator, secondInitiator);
283 if (result === 0) {
284 result = compareValues(
285 firstInitiatorLineNumber,
286 secondInitiatorLineNumber
290 return result;