1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
7 } = require("resource://devtools/client/netmonitor/src/utils/request-utils.js");
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
= [
19 causeType
: "document",
25 url
: HTTPS_EXAMPLE_URL
+ "stylesheet_request",
26 causeType
: "stylesheet",
27 causeUri
: INITIATOR_URL
,
32 url
: HTTPS_EXAMPLE_URL
+ "img_request",
34 causeUri
: INITIATOR_URL
,
39 url
: HTTPS_EXAMPLE_URL
+ "img_srcset_request",
40 causeType
: "imageset",
41 causeUri
: INITIATOR_URL
,
46 url
: HTTPS_EXAMPLE_URL
+ "xhr_request",
48 causeUri
: INITIATOR_URL
,
49 stack
: [{ fn
: "performXhrRequestCallback", file
: INITIATOR_URL
, line
: 32 }],
53 url
: HTTPS_EXAMPLE_URL
+ "fetch_request",
55 causeUri
: INITIATOR_URL
,
56 stack
: [{ fn
: "performFetchRequest", file
: INITIATOR_URL
, line
: 37 }],
60 url
: HTTPS_EXAMPLE_URL
+ "promise_fetch_request",
62 causeUri
: INITIATOR_URL
,
65 fn
: "performPromiseFetchRequestCallback",
70 fn
: "performPromiseFetchRequest",
73 asyncCause
: "promise callback",
79 url
: HTTPS_EXAMPLE_URL
+ "timeout_fetch_request",
81 causeUri
: INITIATOR_URL
,
84 fn
: "performTimeoutFetchRequestCallback2",
89 fn
: "performTimeoutFetchRequestCallback1",
92 asyncCause
: "setTimeout handler",
98 url
: HTTPS_EXAMPLE_URL
+ "favicon_request",
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.
107 file
: "resource:///modules/FaviconLoader.sys.mjs",
108 line
: Number
.MAX_SAFE_INTEGER
,
114 url
: HTTPS_EXAMPLE_URL
+ "lazy_img_request",
115 causeType
: "lazy-img",
116 causeUri
: INITIATOR_URL
,
121 url
: HTTPS_EXAMPLE_URL
+ "lazy_img_srcset_request",
122 causeType
: "lazy-imageset",
123 causeUri
: INITIATOR_URL
,
128 url
: HTTPS_EXAMPLE_URL
+ "beacon_request",
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
, {
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
);
161 // For all expected requests
162 for (const [index
, { stack
}] of EXPECTED_REQUESTS
.entries()) {
167 EventUtils
.sendMouseEvent(
168 { type
: "mousedown" },
169 document
.querySelectorAll(
170 ".request-list-item .requests-list-initiator-lastframe"
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(
192 document
.querySelector("#requests-list-initiator-button")
195 const expectedOrder
= EXPECTED_REQUESTS
.sort(initiatorSortPredicate
).map(
197 let isChromeFrames
= false;
198 const lastFrameExists
= !!r
.stack
;
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
;
209 initiatorStr
: initiator
+ lineNumber
+ causeStr
,
215 expectedOrder
.forEach((expectedInitiator
, i
) => {
216 const request
= getSortedRequests(store
.getState())[i
];
218 // In cases of chrome frames, we shouldn't have stack.
220 request
.cause
.stacktraceAvailable
&&
221 !expectedInitiator
.isChromeFrames
223 const { filename
, lineNumber
} = request
.cause
.lastFrame
;
225 getUrlBaseName(filename
) +
232 initiator
= request
.cause
.type
;
235 if (expectedInitiator
.isChromeFrames
) {
238 expectedInitiator
.initiatorStr
,
239 `The request #${i} has the expected initiator after sorting`
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
;
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
);
282 result
= compareValues(firstInitiator
, secondInitiator
);
284 result
= compareValues(
285 firstInitiatorLineNumber
,
286 secondInitiatorLineNumber