/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const TEST_FILE = "test-network-request.html"; const TEST_PATH = "https://example.com/browser/devtools/client/webconsole/test/browser/"; const TEST_URI = TEST_PATH + TEST_FILE; requestLongerTimeout(4); pushPref("devtools.webconsole.filter.net", false); pushPref("devtools.webconsole.filter.netxhr", true); // Update waitFor default interval (10ms) to avoid test timeouts. // The test often times out on waitFor statements use a 50ms interval instead. waitFor.overrideIntervalForTestFile = 50; const tabs = [ { id: "headers", testEmpty: testEmptyHeaders, testContent: testHeaders, }, { id: "cookies", testEmpty: testEmptyCookies, testContent: testCookies, }, { id: "request", testEmpty: testEmptyRequest, testContent: testRequest, }, { id: "response", testEmpty: testEmptyResponse, testContent: testResponse, }, { id: "timings", testEmpty: testEmptyTimings, testContent: testTimings, }, { id: "stack-trace", testEmpty: testEmptyStackTrace, testContent: testStackTrace, }, { id: "security", testEmpty: testEmptySecurity, testContent: testSecurity, }, ]; /** * Main test for checking HTTP logs in the Console panel. */ add_task(async function task() { const hud = await openNewTabAndConsole(TEST_URI); // Test proper UI update when request is opened. // For every tab (with HTTP details): // 1. Execute long-time request // 2. Expand the net log before the request finishes (set default tab) // 3. Check the default tab empty content // 4. Wait till the request finishes // 5. Check content of all tabs for (const tab of tabs) { info(`Test "${tab.id}" panel`); await openRequestBeforeUpdates(hud, tab); } }); async function openRequestBeforeUpdates(hud, tab) { const toolbox = hud.toolbox; await clearOutput(hud); const xhrUrl = TEST_PATH + "sjs_slow-response-test-server.sjs"; const onMessage = waitForMessageByType(hud, xhrUrl, ".network"); // Fire an XHR POST request. SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () { content.wrappedJSObject.testXhrPostSlowResponse(); }); info(`Wait for ${xhrUrl} message`); const { node: messageNode } = await onMessage; ok(messageNode, "Network message found."); // Set the default panel. const state = hud.ui.wrapper.getStore().getState(); state.ui.networkMessageActiveTabId = tab.id; // Expand network log await expandXhrMessage(messageNode); // Except the security tab. It isn't available till the // "securityInfo" packet type is received, so doesn't // fit this part of the test. if (tab.id != "security") { // Make sure the current tab is the expected one. const currentTab = messageNode.querySelector(`#${tab.id}-tab`); is( currentTab.getAttribute("aria-selected"), "true", "The correct tab is selected" ); if (tab.testEmpty) { info("Test that the tab is empty"); tab.testEmpty(messageNode); } } info("Test content of the default tab"); await tab.testContent(messageNode); info("Test all tabs in the network log"); await testNetworkMessage(toolbox, messageNode); } // Panel testing helpers async function testNetworkMessage(toolbox, messageNode) { await testStatusInfo(messageNode); await testHeaders(messageNode); await testCookies(messageNode); await testRequest(messageNode); await testResponse(messageNode); await testTimings(messageNode); await testStackTrace(messageNode); await testSecurity(messageNode); await waitForLazyRequests(toolbox); } // Status Info async function testStatusInfo(messageNode) { const statusInfo = await waitFor(() => messageNode.querySelector(".status-info") ); ok(statusInfo, "Status info is not empty"); } // Headers function testEmptyHeaders(messageNode) { const emptyNotice = messageNode.querySelector("#headers-panel .empty-notice"); ok(emptyNotice, "Headers tab is empty"); } async function testHeaders(messageNode) { const headersTab = messageNode.querySelector("#headers-tab"); ok(headersTab, "Headers tab is available"); // Select Headers tab and check the content. headersTab.click(); await waitFor( () => messageNode.querySelector("#headers-panel .headers-overview"), "Wait for .header-overview to be rendered" ); } // Cookies function testEmptyCookies(messageNode) { const emptyNotice = messageNode.querySelector("#cookies-panel .empty-notice"); ok(emptyNotice, "Cookies tab is empty"); } async function testCookies(messageNode) { const cookiesTab = messageNode.querySelector("#cookies-tab"); ok(cookiesTab, "Cookies tab is available"); // Select tab and check the content. cookiesTab.click(); await waitFor( () => messageNode.querySelector("#cookies-panel .treeValueCell"), "Wait for .treeValueCell to be rendered" ); } // Request function testEmptyRequest(messageNode) { const emptyNotice = messageNode.querySelector("#request-panel .empty-notice"); ok(emptyNotice, "Request tab is empty"); } async function testRequest(messageNode) { const requestTab = messageNode.querySelector("#request-tab"); ok(requestTab, "Request tab is available"); // Select Request tab and check the content. CodeMirror initialization // is delayed to prevent UI freeze, so wait for a little while. requestTab.click(); const requestPanel = messageNode.querySelector("#request-panel"); await waitForSourceEditor(requestPanel); const requestContent = requestPanel.querySelector( ".panel-container .CodeMirror" ); ok(requestContent, "Request content is available"); ok( requestContent.textContent.includes("Hello world!"), "Request POST body is correct" ); } // Response function testEmptyResponse(messageNode) { const panel = messageNode.querySelector("#response-panel .tab-panel"); is( panel.textContent, "No response data available for this request", "Cookies tab is empty" ); } async function testResponse(messageNode) { const responseTab = messageNode.querySelector("#response-tab"); ok(responseTab, "Response tab is available"); // Select Response tab and check the content. CodeMirror initialization // is delayed, so again wait for a little while. responseTab.click(); const responsePanel = messageNode.querySelector("#response-panel"); const responsePayloadHeader = await waitFor(() => responsePanel.querySelector(".data-header") ); // Expand the header if it wasn't yet. if (responsePayloadHeader.getAttribute("aria-expanded") === "false") { responsePayloadHeader.click(); } await waitForSourceEditor(responsePanel); const responseContent = messageNode.querySelector( "#response-panel .editor-row-container .CodeMirror" ); ok(responseContent, "Response content is available"); ok(responseContent.textContent, "Response text is available"); } // Timings function testEmptyTimings(messageNode) { const panel = messageNode.querySelector("#timings-panel .tab-panel"); is(panel.textContent, "No timings for this request", "Timings tab is empty"); } async function testTimings(messageNode) { const timingsTab = messageNode.querySelector("#timings-tab"); ok(timingsTab, "Timings tab is available"); // Select Timings tab and check the content. timingsTab.click(); const timingsContent = await waitFor(() => messageNode.querySelector( "#timings-panel .timings-container .timings-label", "Wait for .timings-label to be rendered" ) ); ok(timingsContent, "Timings content is available"); ok(timingsContent.textContent, "Timings text is available"); } // Stack Trace function testEmptyStackTrace(messageNode) { const panel = messageNode.querySelector("#stack-trace-panel .tab-panel"); is(panel.textContent, "", "StackTrace tab is empty"); } async function testStackTrace(messageNode) { const stackTraceTab = messageNode.querySelector("#stack-trace-tab"); ok(stackTraceTab, "StackTrace tab is available"); // Select Stack Trace tab and check the content. stackTraceTab.click(); await waitFor( () => messageNode.querySelector("#stack-trace-panel .frame-link"), "Wait for .frame-link to be rendered" ); } // Security function testEmptySecurity(messageNode) { const panel = messageNode.querySelector("#security-panel .tab-panel"); is(panel.textContent, "", "Security tab is empty"); } async function testSecurity(messageNode) { const securityTab = await waitFor(() => messageNode.querySelector("#security-tab") ); ok(securityTab, "Security tab is available"); // Select Security tab and check the content. securityTab.click(); await waitFor( () => messageNode.querySelector("#security-panel .treeTable .treeRow"), "Wait for #security-panel .treeTable .treeRow to be rendered" ); } async function waitForSourceEditor(panel) { return waitUntil(() => { return !!panel.querySelector(".CodeMirror"); }); } function expandXhrMessage(node) { info( "Click on XHR message and wait for the network detail panel to be displayed" ); node.querySelector(".url").click(); return waitFor( () => node.querySelector(".network-info"), "Wait for .network-info to be rendered" ); }