/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; /** * Tests if requests render correct information in the menu UI. */ function test() { // Disable tcp fast open, because it is setting a response header indicator // (bug 1352274). TCP Fast Open is not present on all platforms therefore the // number of response headers will vary depending on the platform. Services.prefs.setBoolPref("network.tcp.tcp_fastopen_enable", false); const { L10N, } = require("resource://devtools/client/netmonitor/src/utils/l10n.js"); initNetMonitor(SIMPLE_SJS, { requestCount: 1 }).then( async ({ tab, monitor }) => { info("Starting test... "); const { document, store, windowRequire, connector } = monitor.panelWin; const { EVENTS, TEST_EVENTS } = windowRequire( "devtools/client/netmonitor/src/constants" ); const { getDisplayedRequests, getSelectedRequest, getSortedRequests } = windowRequire("devtools/client/netmonitor/src/selectors/index"); const promiseList = []; promiseList.push(waitForNetworkEvents(monitor, 1)); function expectEvent(evt, cb) { promiseList.push( new Promise((resolve, reject) => { monitor.panelWin.api.once(evt, _ => { cb().then(resolve, reject); }); }) ); } expectEvent(TEST_EVENTS.NETWORK_EVENT, async () => { is( getSelectedRequest(store.getState()), undefined, "There shouldn't be any selected item in the requests menu." ); is( store.getState().requests.requests.length, 1, "The requests menu should not be empty after the first request." ); is( !!document.querySelector(".network-details-bar"), false, "The network details panel should still be hidden after first request." ); const requestItem = getSortedRequests(store.getState())[0]; is( typeof requestItem.id, "string", "The attached request id is incorrect." ); isnot( requestItem.id, "", "The attached request id should not be empty." ); is( typeof requestItem.startedMs, "number", "The attached startedMs is incorrect." ); isnot( requestItem.startedMs, 0, "The attached startedMs should not be zero." ); /* * Bug 1666495: this is not possible to assert not yet set attributes * because of throttling, which only updates the frontend after a few attributes * are already retrieved via onResourceUpdates events. * This test should be tweaked with slow responding requests in order to assert * such behavior without disabling throttling. is( requestItem.requestHeaders, undefined, "The requestHeaders should not yet be set." ); is( requestItem.requestCookies, undefined, "The requestCookies should not yet be set." ); is( requestItem.requestPostData, undefined, "The requestPostData should not yet be set." ); is( requestItem.responseHeaders, undefined, "The responseHeaders should not yet be set." ); is( requestItem.responseCookies, undefined, "The responseCookies should not yet be set." ); is( requestItem.httpVersion, undefined, "The httpVersion should not yet be set." ); is(requestItem.status, undefined, "The status should not yet be set."); is( requestItem.statusText, undefined, "The statusText should not yet be set." ); is( requestItem.headersSize, undefined, "The headersSize should not yet be set." ); is( requestItem.transferredSize, undefined, "The transferredSize should not yet be set." ); is( requestItem.contentSize, undefined, "The contentSize should not yet be set." ); is( requestItem.responseContent, undefined, "The responseContent should not yet be set." ); is( requestItem.totalTime, undefined, "The totalTime should not yet be set." ); is( requestItem.eventTimings, undefined, "The eventTimings should not yet be set." ); */ verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS ); }); expectEvent(TEST_EVENTS.RECEIVED_REQUEST_HEADERS, async () => { await waitForRequestData(store, ["requestHeaders"]); const requestItem = getSortedRequests(store.getState())[0]; ok( requestItem.requestHeaders, "There should be a requestHeaders data available." ); is( requestItem.requestHeaders.headers.length, 10, "The requestHeaders data has an incorrect |headers| property." ); isnot( requestItem.requestHeaders.headersSize, 0, "The requestHeaders data has an incorrect |headersSize| property." ); // Can't test for the exact request headers size because the value may // vary across platforms ("User-Agent" header differs). verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS ); }); expectEvent(TEST_EVENTS.RECEIVED_REQUEST_COOKIES, async () => { await waitForRequestData(store, ["requestCookies"]); const requestItem = getSortedRequests(store.getState())[0]; ok( requestItem.requestCookies, "There should be a requestCookies data available." ); is( requestItem.requestCookies.length, 2, "The requestCookies data has an incorrect |cookies| property." ); verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS ); }); monitor.panelWin.api.once(TEST_EVENTS.RECEIVED_REQUEST_POST_DATA, () => { ok(false, "Trap listener: this request doesn't have any post data."); }); expectEvent(TEST_EVENTS.RECEIVED_RESPONSE_HEADERS, async () => { await waitForRequestData(store, ["responseHeaders"]); const requestItem = getSortedRequests(store.getState())[0]; ok( requestItem.responseHeaders, "There should be a responseHeaders data available." ); is( requestItem.responseHeaders.headers.length, 13, "The responseHeaders data has an incorrect |headers| property." ); is( requestItem.responseHeaders.headersSize, 335, "The responseHeaders data has an incorrect |headersSize| property." ); verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS ); }); expectEvent(TEST_EVENTS.RECEIVED_RESPONSE_COOKIES, async () => { await waitForRequestData(store, ["responseCookies"]); const requestItem = getSortedRequests(store.getState())[0]; ok( requestItem.responseCookies, "There should be a responseCookies data available." ); is( requestItem.responseCookies.length, 2, "The responseCookies data has an incorrect |cookies| property." ); verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS ); }); expectEvent(TEST_EVENTS.STARTED_RECEIVING_RESPONSE, async () => { await waitForRequestData(store, [ "httpVersion", "status", "statusText", "headersSize", ]); const requestItem = getSortedRequests(store.getState())[0]; is( requestItem.httpVersion, "HTTP/1.1", "The httpVersion data has an incorrect value." ); is( requestItem.status, "200", "The status data has an incorrect value." ); is( requestItem.statusText, "Och Aye", "The statusText data has an incorrect value." ); is( requestItem.headersSize, 335, "The headersSize data has an incorrect value." ); const requestListItem = document.querySelector(".request-list-item"); requestListItem.scrollIntoView(); const requestsListStatus = requestListItem.querySelector(".status-code"); EventUtils.sendMouseEvent({ type: "mouseover" }, requestsListStatus); await waitUntil(() => requestsListStatus.title); await waitForDOMIfNeeded( requestListItem, ".requests-list-timings-total" ); verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS, { status: "200", statusText: "Och Aye", } ); }); expectEvent(EVENTS.PAYLOAD_READY, async () => { await waitForRequestData(store, [ "transferredSize", "contentSize", "mimeType", ]); const requestItem = getSortedRequests(store.getState())[0]; is( requestItem.transferredSize, 347, "The transferredSize data has an incorrect value." ); is( requestItem.contentSize, 12, "The contentSize data has an incorrect value." ); is( requestItem.mimeType, "text/plain; charset=utf-8", "The mimeType data has an incorrect value." ); verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS, { type: "plain", fullMimeType: "text/plain; charset=utf-8", transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 347), size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12), } ); }); expectEvent(EVENTS.UPDATING_EVENT_TIMINGS, async () => { await waitForRequestData(store, ["eventTimings"]); const requestItem = getSortedRequests(store.getState())[0]; is( typeof requestItem.totalTime, "number", "The attached totalTime is incorrect." ); ok( requestItem.totalTime >= 0, "The attached totalTime should be positive." ); verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS, { time: true, } ); }); expectEvent(EVENTS.RECEIVED_EVENT_TIMINGS, async () => { await waitForRequestData(store, ["eventTimings"]); const requestItem = getSortedRequests(store.getState())[0]; ok( requestItem.eventTimings, "There should be a eventTimings data available." ); is( typeof requestItem.eventTimings.timings.blocked, "number", "The eventTimings data has an incorrect |timings.blocked| property." ); is( typeof requestItem.eventTimings.timings.dns, "number", "The eventTimings data has an incorrect |timings.dns| property." ); is( typeof requestItem.eventTimings.timings.ssl, "number", "The eventTimings data has an incorrect |timings.ssl| property." ); is( typeof requestItem.eventTimings.timings.connect, "number", "The eventTimings data has an incorrect |timings.connect| property." ); is( typeof requestItem.eventTimings.timings.send, "number", "The eventTimings data has an incorrect |timings.send| property." ); is( typeof requestItem.eventTimings.timings.wait, "number", "The eventTimings data has an incorrect |timings.wait| property." ); is( typeof requestItem.eventTimings.timings.receive, "number", "The eventTimings data has an incorrect |timings.receive| property." ); is( typeof requestItem.eventTimings.totalTime, "number", "The eventTimings data has an incorrect |totalTime| property." ); verifyRequestItemTarget( document, getDisplayedRequests(store.getState()), requestItem, "GET", SIMPLE_SJS, { time: true, } ); }); const wait = waitForNetworkEvents(monitor, 1); await reloadBrowser(); await wait; const requestItem = getSortedRequests(store.getState())[0]; if (!requestItem.requestHeaders) { connector.requestData(requestItem.id, "requestHeaders"); } if (!requestItem.responseHeaders) { connector.requestData(requestItem.id, "responseHeaders"); } await Promise.all(promiseList); await teardown(monitor); finish(); } ); }