Bug 1924993 - [devtools] Debugger tests wait before typing in conditional panel r...
[gecko.git] / devtools / client / netmonitor / test / browser_net_resend.js
blob9150bfe3bac05189dd7d4bb9f7d95d7492357655
1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/ */
4 "use strict";
6 /**
7 * Tests if resending a request works.
8 */
10 add_task(async function () {
11 if (
12 Services.prefs.getBoolPref(
13 "devtools.netmonitor.features.newEditAndResend",
14 true
16 ) {
17 await testResendRequest();
18 } else {
19 await testOldEditAndResendPanel();
21 });
23 // This tests resending a request without editing using
24 // the resend context menu item. This particularly covering
25 // the new resend functionality.
26 async function testResendRequest() {
27 const { tab, monitor } = await initNetMonitor(POST_DATA_URL, {
28 requestCount: 1,
29 });
30 info("Starting test... ");
32 const { document, store, windowRequire } = monitor.panelWin;
34 // Action should be processed synchronously in tests.
35 const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
36 store.dispatch(Actions.batchEnable(false));
38 await performRequests(monitor, tab, 2);
40 is(
41 document.querySelectorAll(".request-list-item").length,
43 "There are currently two requests"
46 const firstResend = await resendRequestAndWaitForNewRequest(
47 monitor,
48 document.querySelectorAll(".request-list-item")[0]
51 Assert.notStrictEqual(
52 firstResend.originalResource.resourceId,
53 firstResend.newResource.resourceId,
54 "The resent request is different resource from the first request"
57 is(
58 firstResend.originalResource.url,
59 firstResend.newResource.url,
60 "The resent request has the same url and query parameters and the first request"
63 // The priority header only appears when the urgency and incremental values
64 // are not both default values (u=3 and i=false). In this case the original
65 // request has no priority header and the resent request does, hence we subtract one.
66 is(
67 firstResend.originalResource.requestHeaders.headers.length,
68 firstResend.newResource.requestHeaders.headers.length - 1,
69 "The no of headers are the same"
72 // Because a resent request has a different purpose and principal it will
73 // also have a different CoS flag (meaning a different priority header).
74 // So we can't compare the original and resent request's priority and skip it.
75 firstResend.originalResource.requestHeaders.headers.forEach(
76 ({ name, value }) => {
77 if (name === "Priority") {
78 return;
80 const foundHeader = firstResend.newResource.requestHeaders.headers.find(
81 header => header.name == name
83 is(
84 value,
85 foundHeader.value,
86 `The '${name}' header for the request and the resent request match`
91 info("Check that the custom headers and form data are resent correctly");
92 const secondResend = await resendRequestAndWaitForNewRequest(
93 monitor,
94 document.querySelectorAll(".request-list-item")[1]
97 Assert.notStrictEqual(
98 secondResend.originalResource.resourceId,
99 secondResend.newResource.resourceId,
100 "The resent request is different resource from the second request"
103 const customHeader =
104 secondResend.originalResource.requestHeaders.headers.find(
105 header => header.name == "custom-header-xxx"
108 const customHeaderInResentRequest =
109 secondResend.newResource.requestHeaders.headers.find(
110 header => header.name == "custom-header-xxx"
114 customHeader.value,
115 customHeaderInResentRequest.value,
116 "The custom header in the resent request is the same as the second request"
120 customHeaderInResentRequest.value,
121 "custom-value-xxx",
122 "The custom header in the resent request is correct"
126 secondResend.originalResource.requestPostData.postData.text,
127 secondResend.newResource.requestPostData.postData.text,
128 "The form data in the resent is the same as the second request"
132 async function resendRequestAndWaitForNewRequest(monitor, originalRequestItem) {
133 const { document, store, windowRequire, connector } = monitor.panelWin;
134 const { getSelectedRequest, getDisplayedRequests } = windowRequire(
135 "devtools/client/netmonitor/src/selectors/index"
138 info("Select the request to resend");
139 const expectedNoOfRequestsAfterResend =
140 getDisplayedRequests(store.getState()).length + 1;
142 const waitForHeaders = waitUntil(() =>
143 document.querySelector(".headers-overview")
145 EventUtils.sendMouseEvent({ type: "mousedown" }, originalRequestItem);
146 await waitForHeaders;
148 const originalResourceId = getSelectedRequest(store.getState()).id;
150 const waitForNewRequest = waitUntil(
151 () =>
152 getDisplayedRequests(store.getState()).length ==
153 expectedNoOfRequestsAfterResend &&
154 getSelectedRequest(store.getState()).id !== originalResourceId
157 info("Open the context menu and select the resend for the request");
158 EventUtils.sendMouseEvent({ type: "contextmenu" }, originalRequestItem);
159 await selectContextMenuItem(monitor, "request-list-context-resend-only");
160 await waitForNewRequest;
162 const newResourceId = getSelectedRequest(store.getState()).id;
164 // Make sure we fetch the request headers and post data for the
165 // new request so we can assert them.
166 await connector.requestData(newResourceId, "requestHeaders");
167 await connector.requestData(newResourceId, "requestPostData");
169 return {
170 originalResource: getRequestById(store.getState(), originalResourceId),
171 newResource: getRequestById(store.getState(), newResourceId),
175 // This is a basic test for the old edit and resend panel
176 // This should be removed soon in Bug 1745416 when we remove
177 // the old panel functionality.
178 async function testOldEditAndResendPanel() {
179 const ADD_QUERY = "t1=t2";
180 const ADD_HEADER = "Test-header: true";
181 const ADD_UA_HEADER = "User-Agent: Custom-Agent";
182 const ADD_POSTDATA = "&t3=t4";
184 const { tab, monitor } = await initNetMonitor(POST_DATA_URL, {
185 requestCount: 1,
187 info("Starting test... ");
189 const { document, store, windowRequire } = monitor.panelWin;
190 const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
191 const { getSelectedRequest, getSortedRequests } = windowRequire(
192 "devtools/client/netmonitor/src/selectors/index"
195 store.dispatch(Actions.batchEnable(false));
197 // Execute requests.
198 await performRequests(monitor, tab, 2);
200 const origItemId = getSortedRequests(store.getState())[0].id;
202 store.dispatch(Actions.selectRequest(origItemId));
203 await waitForRequestData(
204 store,
205 ["requestHeaders", "requestPostData"],
206 origItemId
209 let origItem = getSortedRequests(store.getState())[0];
211 // add a new custom request cloned from selected request
213 store.dispatch(Actions.cloneSelectedRequest());
214 await testCustomForm(origItem);
216 let customItem = getSelectedRequest(store.getState());
217 testCustomItem(customItem, origItem);
219 // edit the custom request
220 await editCustomForm();
222 // FIXME: reread the customItem, it's been replaced by a new object (immutable!)
223 customItem = getSelectedRequest(store.getState());
224 testCustomItemChanged(customItem, origItem);
226 // send the new request
227 const wait = waitForNetworkEvents(monitor, 1);
228 store.dispatch(Actions.sendCustomRequest());
229 await wait;
231 let sentItem;
232 // Testing sent request will require updated requestHeaders and requestPostData,
233 // we must wait for both properties get updated before starting test.
234 await waitUntil(() => {
235 sentItem = getSelectedRequest(store.getState());
236 origItem = getSortedRequests(store.getState())[0];
237 return (
238 sentItem &&
239 sentItem.requestHeaders &&
240 sentItem.requestPostData &&
241 origItem &&
242 origItem.requestHeaders &&
243 origItem.requestPostData
247 await testSentRequest(sentItem, origItem);
249 // Ensure the UI shows the new request, selected, and that the detail panel was closed.
251 getSortedRequests(store.getState()).length,
253 "There are 3 requests shown"
256 document
257 .querySelector(".request-list-item.selected")
258 .getAttribute("data-id"),
259 sentItem.id,
260 "The sent request is selected"
263 document.querySelector(".network-details-bar"),
264 null,
265 "The detail panel is hidden"
268 await teardown(monitor);
270 function testCustomItem(item, orig) {
272 item.method,
273 orig.method,
274 "item is showing the same method as original request"
276 is(item.url, orig.url, "item is showing the same URL as original request");
279 function testCustomItemChanged(item, orig) {
280 const { url } = item;
281 const expectedUrl = orig.url + "&" + ADD_QUERY;
283 is(url, expectedUrl, "menu item is updated to reflect url entered in form");
287 * Test that the New Request form was populated correctly
289 async function testCustomForm(data) {
290 await waitUntil(() => document.querySelector(".custom-request-panel"));
292 document.getElementById("custom-method-value").value,
293 data.method,
294 "new request form showing correct method"
298 document.getElementById("custom-url-value").value,
299 data.url,
300 "new request form showing correct url"
303 const query = document.getElementById("custom-query-value");
305 query.value,
306 "foo=bar\nbaz=42\ntype=urlencoded",
307 "new request form showing correct query string"
310 const headers = document
311 .getElementById("custom-headers-value")
312 .value.split("\n");
313 for (const { name, value } of data.requestHeaders.headers) {
315 headers.includes(name + ": " + value),
316 "form contains header from request"
320 const postData = document.getElementById("custom-postdata-value");
322 postData.value,
323 data.requestPostData.postData.text,
324 "new request form showing correct post data"
329 * Add some params and headers to the request form
331 async function editCustomForm() {
332 monitor.panelWin.focus();
334 const query = document.getElementById("custom-query-value");
335 const queryFocus = once(query, "focus", false);
336 // Bug 1195825: Due to some unexplained dark-matter with promise,
337 // focus only works if delayed by one tick.
338 query.setSelectionRange(query.value.length, query.value.length);
339 executeSoon(() => query.focus());
340 await queryFocus;
342 // add params to url query string field
343 typeInNetmonitor(["VK_RETURN"], monitor);
344 typeInNetmonitor(ADD_QUERY, monitor);
346 const headers = document.getElementById("custom-headers-value");
347 const headersFocus = once(headers, "focus", false);
348 headers.setSelectionRange(headers.value.length, headers.value.length);
349 headers.focus();
350 await headersFocus;
352 // add a header
353 typeInNetmonitor(["VK_RETURN"], monitor);
354 typeInNetmonitor(ADD_HEADER, monitor);
356 // add a User-Agent header, to check if default headers can be modified
357 // (there will be two of them, first gets overwritten by the second)
358 typeInNetmonitor(["VK_RETURN"], monitor);
359 typeInNetmonitor(ADD_UA_HEADER, monitor);
361 const postData = document.getElementById("custom-postdata-value");
362 const postFocus = once(postData, "focus", false);
363 postData.setSelectionRange(postData.value.length, postData.value.length);
364 postData.focus();
365 await postFocus;
367 // add to POST data once textarea has updated
368 await waitUntil(() => postData.textContent !== "");
369 typeInNetmonitor(ADD_POSTDATA, monitor);
373 * Make sure newly created event matches expected request
375 async function testSentRequest(data, origData) {
376 is(data.method, origData.method, "correct method in sent request");
377 is(data.url, origData.url + "&" + ADD_QUERY, "correct url in sent request");
379 const { headers } = data.requestHeaders;
380 const hasHeader = headers.some(h => `${h.name}: ${h.value}` == ADD_HEADER);
381 ok(hasHeader, "new header added to sent request");
383 const hasUAHeader = headers.some(
384 h => `${h.name}: ${h.value}` == ADD_UA_HEADER
386 ok(hasUAHeader, "User-Agent header added to sent request");
389 data.requestPostData.postData.text,
390 origData.requestPostData.postData.text + ADD_POSTDATA,
391 "post data added to sent request"