From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../src/har/test/browser-harautomation.ini | 16 ++ .../client/netmonitor/src/har/test/browser.ini | 29 +++ .../src/har/test/browser_harautomation_simple.js | 35 ++++ .../har/test/browser_net_har_copy_all_as_har.js | 220 +++++++++++++++++++++ .../src/har/test/browser_net_har_import.js | 149 ++++++++++++++ .../src/har/test/browser_net_har_import_no-mime.js | 78 ++++++++ .../src/har/test/browser_net_har_multipage.js | 153 ++++++++++++++ .../src/har/test/browser_net_har_post_data.js | 51 +++++ .../har/test/browser_net_har_post_data_on_get.js | 43 ++++ .../har/test/browser_net_har_throttle_upload.js | 69 +++++++ devtools/client/netmonitor/src/har/test/head.js | 45 +++++ .../src/har/test/html_har_import-test-page.html | 51 +++++ .../src/har/test/html_har_multipage_iframe.html | 24 +++ .../src/har/test/html_har_multipage_page.html | 30 +++ .../src/har/test/html_har_post-data-test-page.html | 55 ++++++ .../src/har/test/sjs_cache-test-server.sjs | 14 ++ .../src/har/test/sjs_cookies-test-server.sjs | 10 + 17 files changed, 1072 insertions(+) create mode 100644 devtools/client/netmonitor/src/har/test/browser-harautomation.ini create mode 100644 devtools/client/netmonitor/src/har/test/browser.ini create mode 100644 devtools/client/netmonitor/src/har/test/browser_harautomation_simple.js create mode 100644 devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js create mode 100644 devtools/client/netmonitor/src/har/test/browser_net_har_import.js create mode 100644 devtools/client/netmonitor/src/har/test/browser_net_har_import_no-mime.js create mode 100644 devtools/client/netmonitor/src/har/test/browser_net_har_multipage.js create mode 100644 devtools/client/netmonitor/src/har/test/browser_net_har_post_data.js create mode 100644 devtools/client/netmonitor/src/har/test/browser_net_har_post_data_on_get.js create mode 100644 devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js create mode 100644 devtools/client/netmonitor/src/har/test/head.js create mode 100644 devtools/client/netmonitor/src/har/test/html_har_import-test-page.html create mode 100644 devtools/client/netmonitor/src/har/test/html_har_multipage_iframe.html create mode 100644 devtools/client/netmonitor/src/har/test/html_har_multipage_page.html create mode 100644 devtools/client/netmonitor/src/har/test/html_har_post-data-test-page.html create mode 100644 devtools/client/netmonitor/src/har/test/sjs_cache-test-server.sjs create mode 100644 devtools/client/netmonitor/src/har/test/sjs_cookies-test-server.sjs (limited to 'devtools/client/netmonitor/src/har/test') diff --git a/devtools/client/netmonitor/src/har/test/browser-harautomation.ini b/devtools/client/netmonitor/src/har/test/browser-harautomation.ini new file mode 100644 index 0000000000..61ee56be44 --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser-harautomation.ini @@ -0,0 +1,16 @@ +[DEFAULT] +tags = devtools +subsuite = devtools +prefs= + # This preference needs to be set before starting Firefox, so we use a + # dedicated browser.ini + devtools.netmonitor.har.enableAutoExportToFile=true + +support-files = + head.js + !/devtools/client/netmonitor/test/head.js + !/devtools/client/netmonitor/test/html_simple-test-page.html + !/devtools/client/shared/test/shared-head.js + !/devtools/client/shared/test/telemetry-test-helpers.js + +[browser_harautomation_simple.js] diff --git a/devtools/client/netmonitor/src/har/test/browser.ini b/devtools/client/netmonitor/src/har/test/browser.ini new file mode 100644 index 0000000000..c45b2b0358 --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser.ini @@ -0,0 +1,29 @@ +[DEFAULT] +tags = devtools +subsuite = devtools +skip-if = http3 # Bug 1829298 +support-files = + head.js + html_har_import-test-page.html + html_har_multipage_iframe.html + html_har_multipage_page.html + html_har_post-data-test-page.html + sjs_cache-test-server.sjs + sjs_cookies-test-server.sjs + !/devtools/client/netmonitor/test/head.js + !/devtools/client/netmonitor/test/html_simple-test-page.html + !/devtools/client/shared/test/shared-head.js + !/devtools/client/shared/test/telemetry-test-helpers.js + +[browser_net_har_copy_all_as_har.js] +skip-if = + !debug && os == "mac" #Bug 1622925 + !debug && os == "linux" #Bug 1622925 + win10_2004 # Bug 1723573 + win11_2009 # Bug 1797751 +[browser_net_har_import.js] +[browser_net_har_import_no-mime.js] +[browser_net_har_multipage.js] +[browser_net_har_post_data.js] +[browser_net_har_post_data_on_get.js] +[browser_net_har_throttle_upload.js] diff --git a/devtools/client/netmonitor/src/har/test/browser_harautomation_simple.js b/devtools/client/netmonitor/src/har/test/browser_harautomation_simple.js new file mode 100644 index 0000000000..9da746d28f --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_harautomation_simple.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const HAR_FILENAME = "test_filename.har"; + +// We expect the HAR file to be created on reload in profD/har/logs +const HAR_PATH = ["har", "logs", HAR_FILENAME]; + +/** + * Smoke test for automated HAR export. + * Note that the `enableAutoExportToFile` is set from browser-harautomation.ini + * because the preference needs to be set before starting the browser. + */ +add_task(async function () { + // Set a simple test filename for the exported HAR. + await pushPref("devtools.netmonitor.har.defaultFileName", "test_filename"); + + const tab = await addTab(SIMPLE_URL); + const toolbox = await gDevTools.showToolboxForTab(tab, { + toolId: "inspector", + }); + + await reloadBrowser(); + + info("Wait until the HAR file is created in the profile directory"); + await waitUntil(() => FileUtils.getFile("ProfD", HAR_PATH).exists()); + + const harFile = FileUtils.getFile("ProfD", HAR_PATH); + ok(harFile.exists(), "HAR file was automatically created"); + + await toolbox.destroy(); + await removeTab(tab); +}); diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js b/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js new file mode 100644 index 0000000000..ab4302883c --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js @@ -0,0 +1,220 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Basic tests for exporting Network panel content into HAR format. + */ + +const EXPECTED_REQUEST_HEADER_COUNT = 9; +const EXPECTED_RESPONSE_HEADER_COUNT = 6; + +add_task(async function () { + // 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. + await pushPref("network.tcp.tcp_fastopen_enable", false); + const { tab, monitor, toolbox } = await initNetMonitor(SIMPLE_URL, { + requestCount: 1, + }); + + info("Starting test... "); + + await testSimpleReload({ tab, monitor, toolbox }); + await testResponseBodyLimits({ tab, monitor, toolbox }); + await testManyReloads({ tab, monitor, toolbox }); + await testClearedRequests({ tab, monitor, toolbox }); + + // Do not use teardown(monitor) as testClearedRequests register broken requests + // which never complete and would block on waitForAllNetworkUpdateEvents + await closeTabAndToolbox(); +}); + +async function testSimpleReload({ tab, monitor, toolbox }) { + info("Test with a simple page reload"); + + const har = await reloadAndCopyAllAsHar({ tab, monitor, toolbox }); + + // Check out HAR log + isnot(har.log, null, "The HAR log must exist"); + is(har.log.creator.name, "Firefox", "The creator field must be set"); + is(har.log.browser.name, "Firefox", "The browser field must be set"); + is(har.log.pages.length, 1, "There must be one page"); + is(har.log.entries.length, 1, "There must be one request"); + + const page = har.log.pages[0]; + + is(page.title, "Network Monitor test page", "There must be some page title"); + ok("onContentLoad" in page.pageTimings, "There must be onContentLoad time"); + ok("onLoad" in page.pageTimings, "There must be onLoad time"); + + const entry = har.log.entries[0]; + assertNavigationRequestEntry(entry); + + info("We get the response content and timings when doing a simple reload"); + isnot(entry.response.content.text, undefined, "Check response body"); + is(entry.response.content.text.length, 465, "Response body is complete"); + isnot(entry.timings, undefined, "Check timings"); +} + +async function testResponseBodyLimits({ tab, monitor, toolbox }) { + info("Test response body limit (non zero)."); + await pushPref("devtools.netmonitor.responseBodyLimit", 10); + let har = await reloadAndCopyAllAsHar({ tab, monitor, toolbox }); + let entry = har.log.entries[0]; + is(entry.response.content.text.length, 10, "Response body must be truncated"); + + info("Test response body limit (zero)."); + await pushPref("devtools.netmonitor.responseBodyLimit", 0); + har = await reloadAndCopyAllAsHar({ tab, monitor, toolbox }); + entry = har.log.entries[0]; + is( + entry.response.content.text.length, + 465, + "Response body must not be truncated" + ); +} + +async function testManyReloads({ tab, monitor, toolbox }) { + const har = await reloadAndCopyAllAsHar({ + tab, + monitor, + toolbox, + reloadTwice: true, + }); + // In most cases, we will have two requests, but sometimes, + // the first one might be missing as we couldn't fetch any lazy data for it. + ok(har.log.entries.length >= 1, "There must be at least one request"); + info( + "Assert the first navigation request which has been cancelled by the second reload" + ); + // Requests may come out of order, so try to find the bogus cancelled request + let entry = har.log.entries.find(e => e.response.status == 0); + if (entry) { + ok(entry, "Found the cancelled request"); + is(entry.request.method, "GET", "Method is set"); + is(entry.request.url, SIMPLE_URL, "URL is set"); + // We always get the following headers: + // "Host", "User-agent", "Accept", "Accept-Language", "Accept-Encoding", "Connection" + // but are missing the three last headers: + // "Upgrade-Insecure-Requests", "Pragma", "Cache-Control" + is(entry.request.headers.length, 6, "But headers are partialy populated"); + is(entry.response.status, 0, "And status is set to 0"); + } + + entry = har.log.entries.find(e => e.response.status != 0); + assertNavigationRequestEntry(entry); +} + +async function testClearedRequests({ tab, monitor, toolbox }) { + info("Navigate to an empty page"); + const topDocumentURL = + "https://example.org/document-builder.sjs?html=empty-document"; + const iframeURL = + "https://example.org/document-builder.sjs?html=" + + encodeURIComponent( + `iframe` + ); + + await waitForAllNetworkUpdateEvents(); + await navigateTo(topDocumentURL); + + info("Create an iframe doing a request and remove the iframe."); + info( + "Doing this, should notify a network request that is destroyed on the server side" + ); + const onNetworkEvents = waitForNetworkEvents(monitor, 2); + await SpecialPowers.spawn( + tab.linkedBrowser, + [iframeURL], + async function (_iframeURL) { + const iframe = content.document.createElement("iframe"); + iframe.setAttribute("src", _iframeURL); + content.document.body.appendChild(iframe); + } + ); + // Wait for the two request to be processed (iframe doc + fetch requests) + // before removing the iframe so that the netmonitor is able to fetch + // all lazy data without throwing + await onNetworkEvents; + await waitForAllNetworkUpdateEvents(); + + info("Remove the iframe so that lazy request data are freed"); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + content.document.querySelector("iframe").remove(); + }); + + // HAR will try to re-fetch lazy data and may throw on the iframe fetch request. + // This subtest is meants to verify we aren't throwing here and HAR export + // works fine, even if some requests can't be fetched. + const har = await copyAllAsHARWithContextMenu(monitor); + is(har.log.entries.length, 2, "There must be two requests"); + is( + har.log.entries[0].request.url, + topDocumentURL, + "First request is for the top level document" + ); + is( + har.log.entries[1].request.url, + iframeURL, + "Second request is for the iframe" + ); + info( + "The fetch request doesn't appear in HAR export, because its lazy data is freed and we completely ignore the request." + ); +} + +function assertNavigationRequestEntry(entry) { + info("Assert that the entry relates to the navigation request"); + ok(entry.time > 0, "Check the total time"); + is(entry.request.method, "GET", "Check the method"); + is(entry.request.url, SIMPLE_URL, "Check the URL"); + is( + entry.request.headers.length, + EXPECTED_REQUEST_HEADER_COUNT, + "Check number of request headers" + ); + is(entry.response.status, 200, "Check response status"); + is(entry.response.statusText, "OK", "Check response status text"); + is( + entry.response.headers.length, + EXPECTED_RESPONSE_HEADER_COUNT, + "Check number of response headers" + ); + is( + entry.response.content.mimeType, + "text/html", + "Check response content type" + ); +} +/** + * Reload the page and copy all as HAR. + */ +async function reloadAndCopyAllAsHar({ + tab, + monitor, + toolbox, + reloadTwice = false, +}) { + const { store, windowRequire } = monitor.panelWin; + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + + store.dispatch(Actions.batchEnable(false)); + + const onNetworkEvent = waitForNetworkEvents(monitor, 1); + const { onDomCompleteResource } = + await waitForNextTopLevelDomCompleteResource(toolbox.commands); + + if (reloadTwice) { + reloadBrowser(); + } + await reloadBrowser(); + + info("Waiting for network events"); + await onNetworkEvent; + info("Waiting for DOCUMENT_EVENT dom-complete resource"); + await onDomCompleteResource; + + return copyAllAsHARWithContextMenu(monitor); +} diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_import.js b/devtools/client/netmonitor/src/har/test/browser_net_har_import.js new file mode 100644 index 0000000000..879966e653 --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_import.js @@ -0,0 +1,149 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests for importing HAR data. + */ +add_task(async () => { + const { tab, monitor } = await initNetMonitor( + HAR_EXAMPLE_URL + "html_har_import-test-page.html", + { requestCount: 1 } + ); + + info("Starting test... "); + + const { actions, store, windowRequire } = monitor.panelWin; + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + const { HarImporter } = windowRequire( + "devtools/client/netmonitor/src/har/har-importer" + ); + + store.dispatch(Actions.batchEnable(false)); + + // Execute one POST request on the page and wait till its done. + const wait = waitForNetworkEvents(monitor, 3); + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + await content.wrappedJSObject.executeTest(); + }); + await wait; + + // Copy HAR into the clipboard + const json1 = await copyAllAsHARWithContextMenu(monitor, { asString: true }); + + // Import HAR string + const importer = new HarImporter(actions); + importer.import(json1); + + // Copy HAR into the clipboard again + const json2 = await copyAllAsHARWithContextMenu(monitor, { asString: true }); + + // Compare exported HAR data + const har1 = JSON.parse(json1); + const har2 = JSON.parse(json2); + + // Explicit tests + is(har2.log.entries.length, 3, "There must be expected number of requests"); + ok( + har2.log.pages[0].title.endsWith("Network Monitor Test Page"), + "There must be some page title" + ); + ok( + !!har2.log.entries[0].request.headers.length, + "There must be some request headers" + ); + ok( + !!har2.log.entries[0].response.headers.length, + "There must be some response headers" + ); + is( + har2.log.entries[1].response.cookies.length, + 3, + "There must be expected number of cookies" + ); + is( + har2.log.entries[1]._securityState, + "insecure", + "There must be expected security state" + ); + is(har2.log.entries[2].response.status, 304, "There must be expected status"); + + // Complex test comparing exported & imported HARs. + ok(compare(har1.log, har2.log, ["log"]), "Exported HAR must be the same"); + + // Clean up + return teardown(monitor); +}); + +/** + * Check equality of HAR files. + */ +function compare(obj1, obj2, path) { + const keys1 = Object.getOwnPropertyNames(obj1).sort(); + const keys2 = Object.getOwnPropertyNames(obj2).sort(); + + const name = path.join("/"); + + is( + keys1.length, + keys2.length, + "There must be the same number of keys for: " + name + ); + if (keys1.length != keys2.length) { + return false; + } + + is(keys1.join(), keys2.join(), "There must be the same keys for: " + name); + if (keys1.join() != keys2.join()) { + return false; + } + + // Page IDs are generated and don't have to be the same after import. + const ignore = [ + "log/entries/0/pageref", + "log/entries/1/pageref", + "log/entries/2/pageref", + "log/pages/0/id", + "log/pages/1/id", + "log/pages/2/id", + ]; + + let result = true; + for (let i = 0; i < keys1.length; i++) { + const key = keys1[i]; + const prop1 = obj1[key]; + const prop2 = obj2[key]; + + if (prop1 instanceof Array) { + if (!(prop2 instanceof Array)) { + ok(false, "Arrays are not the same " + name); + result = false; + break; + } + if (!compare(prop1, prop2, path.concat(key))) { + result = false; + break; + } + } else if (prop1 instanceof Object) { + if (!(prop2 instanceof Object)) { + ok(false, "Objects are not the same in: " + name); + result = false; + break; + } + if (!compare(prop1, prop2, path.concat(key))) { + result = false; + break; + } + } else if (prop1 !== prop2) { + const propName = name + "/" + key; + if (!ignore.includes(propName)) { + is(prop1, prop2, "Values are not the same: " + propName); + result = false; + break; + } + } + } + + return result; +} diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_import_no-mime.js b/devtools/client/netmonitor/src/har/test/browser_net_har_import_no-mime.js new file mode 100644 index 0000000000..91c5160217 --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_import_no-mime.js @@ -0,0 +1,78 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests importing HAR with missing `response.content.mimeType` does not crash the netmonitor. + */ +add_task(async () => { + const { monitor } = await initNetMonitor(SIMPLE_URL, { + requestCount: 1, + }); + + info("Starting test... "); + + const { document, actions, store, windowRequire } = monitor.panelWin; + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + + const { HarImporter } = windowRequire( + "devtools/client/netmonitor/src/har/har-importer" + ); + + store.dispatch(Actions.batchEnable(false)); + + // Invalid HAR json which should contain `entries[0].response.content.mimeType` + const invalidHarJSON = { + log: { + version: "1.2", + pages: [ + { + title: "bla", + }, + ], + entries: [ + { + request: { + method: "POST", + url: "https://bla.com", + httpVersion: "", + headers: [], + cookies: [], + queryString: [], + }, + response: { + content: { + size: 1231, + text: '{"requests":[{"uri":"https://bla.com"}]}', + }, + headers: [], + }, + timings: {}, + cache: {}, + }, + ], + }, + }; + + // Import invalid Har file + const importer = new HarImporter(actions); + importer.import(JSON.stringify(invalidHarJSON)); + + const waitForResponsePanelOpen = waitUntil(() => + document.querySelector("#response-panel") + ); + + // Open the response details panel + EventUtils.sendMouseEvent( + { type: "mousedown" }, + document.querySelector(".request-list-item") + ); + clickOnSidebarTab(document, "response"); + + await waitForResponsePanelOpen; + ok(true, "The response panel opened"); + + // Clean up + return teardown(monitor); +}); diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_multipage.js b/devtools/client/netmonitor/src/har/test/browser_net_har_multipage.js new file mode 100644 index 0000000000..38936f73fe --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_multipage.js @@ -0,0 +1,153 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +const MULTIPAGE_IFRAME_URL = HAR_EXAMPLE_URL + "html_har_multipage_iframe.html"; +const MULTIPAGE_PAGE_URL = HAR_EXAMPLE_URL + "html_har_multipage_page.html"; + +/** + * Tests HAR export with navigations and multipage support + */ +add_task(async function () { + await testHARWithNavigation({ enableMultipage: false, filter: false }); + await testHARWithNavigation({ enableMultipage: true, filter: false }); + await testHARWithNavigation({ enableMultipage: false, filter: true }); + await testHARWithNavigation({ enableMultipage: true, filter: true }); +}); + +async function testHARWithNavigation({ enableMultipage, filter }) { + await pushPref("devtools.netmonitor.persistlog", true); + await pushPref("devtools.netmonitor.har.multiple-pages", enableMultipage); + + const { tab, monitor } = await initNetMonitor(MULTIPAGE_PAGE_URL + "?page1", { + requestCount: 1, + }); + + info("Starting test... "); + + const { store, windowRequire } = monitor.panelWin; + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + + store.dispatch(Actions.batchEnable(false)); + + info("Perform 3 additional requests"); + let onNetworkEvents = waitForNetworkEvents(monitor, 3); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + content.wrappedJSObject.sendRequests(3); + }); + await onNetworkEvents; + + info("Navigate to a second page where we will not perform any extra request"); + onNetworkEvents = waitForNetworkEvents(monitor, 1); + await navigateTo(MULTIPAGE_PAGE_URL + "?page2"); + await onNetworkEvents; + + info("Navigate to a third page where we will not perform any extra request"); + onNetworkEvents = waitForNetworkEvents(monitor, 1); + await navigateTo(MULTIPAGE_PAGE_URL + "?page3"); + await onNetworkEvents; + + info("Perform 2 additional requests"); + onNetworkEvents = waitForNetworkEvents(monitor, 2); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + content.wrappedJSObject.sendRequests(2); + }); + await onNetworkEvents; + + info("Create an iframe which will perform 2 additional requests"); + onNetworkEvents = waitForNetworkEvents(monitor, 2); + await SpecialPowers.spawn( + tab.linkedBrowser, + [MULTIPAGE_IFRAME_URL], + async function (url) { + const iframe = content.document.createElement("iframe"); + const onLoad = new Promise(resolve => + iframe.addEventListener("load", resolve, { once: true }) + ); + content.content.document.body.appendChild(iframe); + iframe.setAttribute("src", url); + await onLoad; + } + ); + await onNetworkEvents; + + if (filter) { + info("Start filtering requests"); + store.dispatch(Actions.setRequestFilterText("?request")); + } + + info("Trigger Copy All As HAR from the context menu"); + const har = await copyAllAsHARWithContextMenu(monitor); + + // Check out the HAR log. + isnot(har.log, null, "The HAR log must exist"); + + if (enableMultipage) { + is(har.log.pages.length, 3, "There must be three pages"); + } else { + is(har.log.pages.length, 1, "There must be one page"); + } + + if (!filter) { + // Expect 9 requests: + // - 3 requests performed with sendRequests on the first page + // - 1 navigation request to the second page + // - 1 navigation request to the third page + // - 2 requests performed with sendRequests on the third page + // - 1 request to load an iframe on the third page + // - 1 request from the iframe on the third page + is(har.log.entries.length, 9, "There must be 9 requests"); + } else { + // Same but we only expect the fetch requests + is(har.log.entries.length, 6, "There must be 6 requests"); + } + + if (enableMultipage) { + // With multipage enabled, check that the page entries are valid and that + // requests are referencing the expected page id. + assertPageDetails(har.log.pages[0], "page_0", "HAR Multipage test page"); + assertPageRequests(har.log.entries, 0, 2, har.log.pages[0].id); + + assertPageDetails(har.log.pages[1], "page_1", "HAR Multipage test page"); + if (filter) { + // When filtering, we don't expect any request to match page_1 + } else { + assertPageRequests(har.log.entries, 3, 3, har.log.pages[1].id); + } + + assertPageDetails(har.log.pages[2], "page_2", "HAR Multipage test page"); + if (filter) { + assertPageRequests(har.log.entries, 3, 5, har.log.pages[2].id); + } else { + assertPageRequests(har.log.entries, 4, 8, har.log.pages[2].id); + } + } else { + is(har.log.pages[0].id, "page_1"); + // Without multipage, all requests are associated with the only page entry. + for (const entry of har.log.entries) { + is(entry.pageref, "page_1"); + } + } + + // Clean up + return teardown(monitor); +} + +function assertPageDetails(page, expectedId, expectedTitle) { + is(page.id, expectedId, "Page has the expected id"); + is(page.title, expectedTitle, "Page has the expected title"); +} + +function assertPageRequests(entries, startIndex, endIndex, expectedPageId) { + for (let i = startIndex; i < endIndex + 1; i++) { + const entry = entries[i]; + is( + entry.pageref, + expectedPageId, + `Entry ${i} is attached to page id: ${expectedPageId}` + ); + } +} diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_post_data.js b/devtools/client/netmonitor/src/har/test/browser_net_har_post_data.js new file mode 100644 index 0000000000..0640364a39 --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_post_data.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests for exporting POST data into HAR format. + */ +add_task(async function () { + const { tab, monitor } = await initNetMonitor( + HAR_EXAMPLE_URL + "html_har_post-data-test-page.html", + { requestCount: 1 } + ); + + info("Starting test... "); + + const { store, windowRequire } = monitor.panelWin; + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + + store.dispatch(Actions.batchEnable(false)); + + // Execute one POST request on the page and wait till its done. + const wait = waitForNetworkEvents(monitor, 1); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + content.wrappedJSObject.executeTest(); + }); + await wait; + + // Copy HAR into the clipboard (asynchronous). + const har = await copyAllAsHARWithContextMenu(monitor); + + // Check out the HAR log. + isnot(har.log, null, "The HAR log must exist"); + is(har.log.pages.length, 1, "There must be one page"); + is(har.log.entries.length, 1, "There must be one request"); + + const entry = har.log.entries[0]; + is( + entry.request.postData.mimeType, + "application/json", + "Check post data content type" + ); + is( + entry.request.postData.text, + "{'first': 'John', 'last': 'Doe'}", + "Check post data payload" + ); + + // Clean up + return teardown(monitor); +}); diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_post_data_on_get.js b/devtools/client/netmonitor/src/har/test/browser_net_har_post_data_on_get.js new file mode 100644 index 0000000000..206fc43da6 --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_post_data_on_get.js @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests for exporting POST data into HAR format. + */ +add_task(async function () { + const { tab, monitor } = await initNetMonitor( + HAR_EXAMPLE_URL + "html_har_post-data-test-page.html", + { requestCount: 1 } + ); + + info("Starting test... "); + + const { store, windowRequire } = monitor.panelWin; + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + + store.dispatch(Actions.batchEnable(false)); + + // Execute one GET request on the page and wait till its done. + const wait = waitForNetworkEvents(monitor, 1); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + content.wrappedJSObject.executeTest3(); + }); + await wait; + + // Copy HAR into the clipboard (asynchronous). + const har = await copyAllAsHARWithContextMenu(monitor); + + // Check out the HAR log. + isnot(har.log, null, "The HAR log must exist"); + is(har.log.pages.length, 1, "There must be one page"); + is(har.log.entries.length, 1, "There must be one request"); + + const entry = har.log.entries[0]; + + is(entry.request.postData, undefined, "Check post data is not present"); + + // Clean up + return teardown(monitor); +}); diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js b/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js new file mode 100644 index 0000000000..24f7d482ca --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test timing of upload when throttling. + +"use strict"; + +add_task(async function () { + await throttleUploadTest(true); + await throttleUploadTest(false); +}); + +async function throttleUploadTest(actuallyThrottle) { + const { tab, monitor } = await initNetMonitor( + HAR_EXAMPLE_URL + "html_har_post-data-test-page.html", + { requestCount: 1 } + ); + + info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")"); + + const { connector, store, windowRequire } = monitor.panelWin; + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + + store.dispatch(Actions.batchEnable(false)); + + const size = 4096; + const uploadSize = actuallyThrottle ? size / 3 : 0; + + const throttleProfile = { + latency: 0, + download: 200000, + upload: uploadSize, + }; + + info("sending throttle request"); + await connector.updateNetworkThrottling(true, throttleProfile); + + // Execute one POST request on the page and wait till its done. + const wait = waitForNetworkEvents(monitor, 1); + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ size }], + async function (args) { + content.wrappedJSObject.executeTest2(args.size); + } + ); + await wait; + + // Copy HAR into the clipboard (asynchronous). + const har = await copyAllAsHARWithContextMenu(monitor); + + // Check out the HAR log. + isnot(har.log, null, "The HAR log must exist"); + is(har.log.pages.length, 1, "There must be one page"); + is(har.log.entries.length, 1, "There must be one request"); + + const entry = har.log.entries[0]; + is(entry.request.postData.text, "x".repeat(size), "Check post data payload"); + + const wasTwoSeconds = entry.timings.send >= 2000; + if (actuallyThrottle) { + ok(wasTwoSeconds, "upload should have taken more than 2 seconds"); + } else { + ok(!wasTwoSeconds, "upload should not have taken more than 2 seconds"); + } + + // Clean up + await teardown(monitor); +} diff --git a/devtools/client/netmonitor/src/har/test/head.js b/devtools/client/netmonitor/src/har/test/head.js new file mode 100644 index 0000000000..b41ea580fd --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/head.js @@ -0,0 +1,45 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* eslint no-unused-vars: [2, {"vars": "local", "args": "none"}] */ +/* import-globals-from ../../../test/head.js */ + +// Load the NetMonitor head.js file to share its API. +var netMonitorHead = + "chrome://mochitests/content/browser/devtools/client/netmonitor/test/head.js"; +Services.scriptloader.loadSubScript(netMonitorHead, this); + +// Directory with HAR related test files. +const HAR_EXAMPLE_URL = + "http://example.com/browser/devtools/client/netmonitor/src/har/test/"; + +/** + * Trigger a "copy all as har" from the context menu of the requests list. + + * @param {Object} monitor + * The network monitor object + */ +async function copyAllAsHARWithContextMenu(monitor, { asString = false } = {}) { + const { HarMenuUtils } = monitor.panelWin.windowRequire( + "devtools/client/netmonitor/src/har/har-menu-utils" + ); + + info("Open the context menu on the first visible request."); + const firstRequest = + monitor.panelWin.document.querySelectorAll(".request-list-item")[0]; + + EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequest); + EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequest); + + info("Trigger Copy All As HAR from the context menu"); + const onHarCopyDone = HarMenuUtils.once("copy-all-as-har-done"); + await selectContextMenuItem(monitor, "request-list-context-copy-all-as-har"); + const jsonString = await onHarCopyDone; + + if (asString) { + return jsonString; + } + return JSON.parse(jsonString); +} diff --git a/devtools/client/netmonitor/src/har/test/html_har_import-test-page.html b/devtools/client/netmonitor/src/har/test/html_har_import-test-page.html new file mode 100644 index 0000000000..04d5ec33ba --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/html_har_import-test-page.html @@ -0,0 +1,51 @@ + + + + + + + + + + + Network Monitor Test Page + + + +

HAR import test

+ + + + + diff --git a/devtools/client/netmonitor/src/har/test/html_har_multipage_iframe.html b/devtools/client/netmonitor/src/har/test/html_har_multipage_iframe.html new file mode 100644 index 0000000000..4e0fc96344 --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/html_har_multipage_iframe.html @@ -0,0 +1,24 @@ + + + + + + + + + + + Network Monitor HAR Multipage test iframe + + + +

HAR Multipage test iframe

+ + + + + diff --git a/devtools/client/netmonitor/src/har/test/html_har_multipage_page.html b/devtools/client/netmonitor/src/har/test/html_har_multipage_page.html new file mode 100644 index 0000000000..d36fbca52b --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/html_har_multipage_page.html @@ -0,0 +1,30 @@ + + + + + + + + + + + HAR Multipage test page + + + +

HAR Multipage test page

+ + + + + diff --git a/devtools/client/netmonitor/src/har/test/html_har_post-data-test-page.html b/devtools/client/netmonitor/src/har/test/html_har_post-data-test-page.html new file mode 100644 index 0000000000..5e42c6139d --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/html_har_post-data-test-page.html @@ -0,0 +1,55 @@ + + + + + + + + + + + Network Monitor Test Page + + + +

HAR POST data test

+ + + + + diff --git a/devtools/client/netmonitor/src/har/test/sjs_cache-test-server.sjs b/devtools/client/netmonitor/src/har/test/sjs_cache-test-server.sjs new file mode 100644 index 0000000000..66081fe1bb --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/sjs_cache-test-server.sjs @@ -0,0 +1,14 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 304, "Not Modified"); + response.setHeader( + "Cache-Control", + "no-transform,public,max-age=300,s-maxage=900" + ); + response.setHeader("Expires", "Thu, 01 Dec 2100 20:00:00 GMT"); + response.setHeader("Content-Type", "text/plain; charset=utf-8", false); + response.write("Hello from cache!"); +} diff --git a/devtools/client/netmonitor/src/har/test/sjs_cookies-test-server.sjs b/devtools/client/netmonitor/src/har/test/sjs_cookies-test-server.sjs new file mode 100644 index 0000000000..a86a0f13cd --- /dev/null +++ b/devtools/client/netmonitor/src/har/test/sjs_cookies-test-server.sjs @@ -0,0 +1,10 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +function handleRequest(request, response) { + response.setHeader("Set-Cookie", "tom=cool; Max-Age=10; HttpOnly", true); + response.setHeader("Set-Cookie", "bob=true; Max-Age=10; HttpOnly", true); + response.setHeader("Set-Cookie", "foo=bar; Max-Age=10; HttpOnly", true); + response.write("Hello world!"); +} -- cgit v1.2.3