Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
/**
* Tests if resending a request works.
*/
add_task(async function () {
if (
Services.prefs.getBoolPref(
"devtools.netmonitor.features.newEditAndResend",
true
)
) {
await testResendRequest();
} else {
await testOldEditAndResendPanel();
}
});
// This tests resending a request without editing using
// the resend context menu item. This particularly covering
// the new resend functionality.
async function testResendRequest() {
const { tab, monitor } = await initNetMonitor(POST_DATA_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
await performRequests(monitor, tab, 2);
is(
document.querySelectorAll(".request-list-item").length,
2,
"There are currently two requests"
);
const firstResend = await resendRequestAndWaitForNewRequest(
monitor,
document.querySelectorAll(".request-list-item")[0]
);
Assert.notStrictEqual(
firstResend.originalResource.resourceId,
firstResend.newResource.resourceId,
"The resent request is different resource from the first request"
);
is(
firstResend.originalResource.url,
firstResend.newResource.url,
"The resent request has the same url and query parameters and the first request"
);
// The priority header only appears when the urgency and incremental values
// are not both default values (u=3 and i=false). In this case the original
// request has no priority header and the resent request does, hence we subtract one.
is(
firstResend.originalResource.requestHeaders.headers.length,
firstResend.newResource.requestHeaders.headers.length - 1,
"The no of headers are the same"
);
// Because a resent request has a different purpose and principal it will
// also have a different CoS flag (meaning a different priority header).
// So we can't compare the original and resent request's priority and skip it.
firstResend.originalResource.requestHeaders.headers.forEach(
({ name, value }) => {
if (name === "Priority") {
return;
}
const foundHeader = firstResend.newResource.requestHeaders.headers.find(
header => header.name == name
);
is(
value,
foundHeader.value,
`The '${name}' header for the request and the resent request match`
);
}
);
info("Check that the custom headers and form data are resent correctly");
const secondResend = await resendRequestAndWaitForNewRequest(
monitor,
document.querySelectorAll(".request-list-item")[1]
);
Assert.notStrictEqual(
secondResend.originalResource.resourceId,
secondResend.newResource.resourceId,
"The resent request is different resource from the second request"
);
const customHeader =
secondResend.originalResource.requestHeaders.headers.find(
header => header.name == "custom-header-xxx"
);
const customHeaderInResentRequest =
secondResend.newResource.requestHeaders.headers.find(
header => header.name == "custom-header-xxx"
);
is(
customHeader.value,
customHeaderInResentRequest.value,
"The custom header in the resent request is the same as the second request"
);
is(
customHeaderInResentRequest.value,
"custom-value-xxx",
"The custom header in the resent request is correct"
);
is(
secondResend.originalResource.requestPostData.postData.text,
secondResend.newResource.requestPostData.postData.text,
"The form data in the resent is the same as the second request"
);
}
async function resendRequestAndWaitForNewRequest(monitor, originalRequestItem) {
const { document, store, windowRequire, connector } = monitor.panelWin;
const { getSelectedRequest, getDisplayedRequests } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
info("Select the request to resend");
const expectedNoOfRequestsAfterResend =
getDisplayedRequests(store.getState()).length + 1;
const waitForHeaders = waitUntil(() =>
document.querySelector(".headers-overview")
);
EventUtils.sendMouseEvent({ type: "mousedown" }, originalRequestItem);
await waitForHeaders;
const originalResourceId = getSelectedRequest(store.getState()).id;
const waitForNewRequest = waitUntil(
() =>
getDisplayedRequests(store.getState()).length ==
expectedNoOfRequestsAfterResend &&
getSelectedRequest(store.getState()).id !== originalResourceId
);
info("Open the context menu and select the resend for the request");
EventUtils.sendMouseEvent({ type: "contextmenu" }, originalRequestItem);
await selectContextMenuItem(monitor, "request-list-context-resend-only");
await waitForNewRequest;
const newResourceId = getSelectedRequest(store.getState()).id;
// Make sure we fetch the request headers and post data for the
// new request so we can assert them.
await connector.requestData(newResourceId, "requestHeaders");
await connector.requestData(newResourceId, "requestPostData");
return {
originalResource: getRequestById(store.getState(), originalResourceId),
newResource: getRequestById(store.getState(), newResourceId),
};
}
// This is a basic test for the old edit and resend panel
// This should be removed soon in Bug 1745416 when we remove
// the old panel functionality.
async function testOldEditAndResendPanel() {
const ADD_QUERY = "t1=t2";
const ADD_HEADER = "Test-header: true";
const ADD_UA_HEADER = "User-Agent: Custom-Agent";
const ADD_POSTDATA = "&t3=t4";
const { tab, monitor } = await initNetMonitor(POST_DATA_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
const { getSelectedRequest, getSortedRequests } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
store.dispatch(Actions.batchEnable(false));
// Execute requests.
await performRequests(monitor, tab, 2);
const origItemId = getSortedRequests(store.getState())[0].id;
store.dispatch(Actions.selectRequest(origItemId));
await waitForRequestData(
store,
["requestHeaders", "requestPostData"],
origItemId
);
let origItem = getSortedRequests(store.getState())[0];
// add a new custom request cloned from selected request
store.dispatch(Actions.cloneSelectedRequest());
await testCustomForm(origItem);
let customItem = getSelectedRequest(store.getState());
testCustomItem(customItem, origItem);
// edit the custom request
await editCustomForm();
// FIXME: reread the customItem, it's been replaced by a new object (immutable!)
customItem = getSelectedRequest(store.getState());
testCustomItemChanged(customItem, origItem);
// send the new request
const wait = waitForNetworkEvents(monitor, 1);
store.dispatch(Actions.sendCustomRequest());
await wait;
let sentItem;
// Testing sent request will require updated requestHeaders and requestPostData,
// we must wait for both properties get updated before starting test.
await waitUntil(() => {
sentItem = getSelectedRequest(store.getState());
origItem = getSortedRequests(store.getState())[0];
return (
sentItem &&
sentItem.requestHeaders &&
sentItem.requestPostData &&
origItem &&
origItem.requestHeaders &&
origItem.requestPostData
);
});
await testSentRequest(sentItem, origItem);
// Ensure the UI shows the new request, selected, and that the detail panel was closed.
is(
getSortedRequests(store.getState()).length,
3,
"There are 3 requests shown"
);
is(
document
.querySelector(".request-list-item.selected")
.getAttribute("data-id"),
sentItem.id,
"The sent request is selected"
);
is(
document.querySelector(".network-details-bar"),
null,
"The detail panel is hidden"
);
await teardown(monitor);
function testCustomItem(item, orig) {
is(
item.method,
orig.method,
"item is showing the same method as original request"
);
is(item.url, orig.url, "item is showing the same URL as original request");
}
function testCustomItemChanged(item, orig) {
const { url } = item;
const expectedUrl = orig.url + "&" + ADD_QUERY;
is(url, expectedUrl, "menu item is updated to reflect url entered in form");
}
/*
* Test that the New Request form was populated correctly
*/
async function testCustomForm(data) {
await waitUntil(() => document.querySelector(".custom-request-panel"));
is(
document.getElementById("custom-method-value").value,
data.method,
"new request form showing correct method"
);
is(
document.getElementById("custom-url-value").value,
data.url,
"new request form showing correct url"
);
const query = document.getElementById("custom-query-value");
is(
query.value,
"foo=bar\nbaz=42\ntype=urlencoded",
"new request form showing correct query string"
);
const headers = document
.getElementById("custom-headers-value")
.value.split("\n");
for (const { name, value } of data.requestHeaders.headers) {
ok(
headers.includes(name + ": " + value),
"form contains header from request"
);
}
const postData = document.getElementById("custom-postdata-value");
is(
postData.value,
data.requestPostData.postData.text,
"new request form showing correct post data"
);
}
/*
* Add some params and headers to the request form
*/
async function editCustomForm() {
monitor.panelWin.focus();
const query = document.getElementById("custom-query-value");
const queryFocus = once(query, "focus", false);
// Bug 1195825: Due to some unexplained dark-matter with promise,
// focus only works if delayed by one tick.
query.setSelectionRange(query.value.length, query.value.length);
executeSoon(() => query.focus());
await queryFocus;
// add params to url query string field
typeInNetmonitor(["VK_RETURN"], monitor);
typeInNetmonitor(ADD_QUERY, monitor);
const headers = document.getElementById("custom-headers-value");
const headersFocus = once(headers, "focus", false);
headers.setSelectionRange(headers.value.length, headers.value.length);
headers.focus();
await headersFocus;
// add a header
typeInNetmonitor(["VK_RETURN"], monitor);
typeInNetmonitor(ADD_HEADER, monitor);
// add a User-Agent header, to check if default headers can be modified
// (there will be two of them, first gets overwritten by the second)
typeInNetmonitor(["VK_RETURN"], monitor);
typeInNetmonitor(ADD_UA_HEADER, monitor);
const postData = document.getElementById("custom-postdata-value");
const postFocus = once(postData, "focus", false);
postData.setSelectionRange(postData.value.length, postData.value.length);
postData.focus();
await postFocus;
// add to POST data once textarea has updated
await waitUntil(() => postData.textContent !== "");
typeInNetmonitor(ADD_POSTDATA, monitor);
}
/*
* Make sure newly created event matches expected request
*/
async function testSentRequest(data, origData) {
is(data.method, origData.method, "correct method in sent request");
is(data.url, origData.url + "&" + ADD_QUERY, "correct url in sent request");
const { headers } = data.requestHeaders;
const hasHeader = headers.some(h => `${h.name}: ${h.value}` == ADD_HEADER);
ok(hasHeader, "new header added to sent request");
const hasUAHeader = headers.some(
h => `${h.name}: ${h.value}` == ADD_UA_HEADER
);
ok(hasUAHeader, "User-Agent header added to sent request");
is(
data.requestPostData.postData.text,
origData.requestPostData.postData.text + ADD_POSTDATA,
"post data added to sent request"
);
}
}