summaryrefslogtreecommitdiff
path: root/browser/devtools/netmonitor/test
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2014-05-21 11:38:25 +0200
committerwolfbeast <mcwerewolf@gmail.com>2014-05-21 11:38:25 +0200
commitd25ba7d760b017b038e5aa6c0a605b4a330eb68d (patch)
tree16ec27edc7d5f83986f16236d3a36a2682a0f37e /browser/devtools/netmonitor/test
parenta942906574671868daf122284a9c4689e6924f74 (diff)
downloadpalemoon-gre-d25ba7d760b017b038e5aa6c0a605b4a330eb68d.tar.gz
Recommit working copy to repo with proper line endings.
Diffstat (limited to 'browser/devtools/netmonitor/test')
-rw-r--r--browser/devtools/netmonitor/test/Makefile.in73
-rw-r--r--browser/devtools/netmonitor/test/browser_net_aaa_leaktest.js28
-rw-r--r--browser/devtools/netmonitor/test/browser_net_accessibility-01.js80
-rw-r--r--browser/devtools/netmonitor/test/browser_net_accessibility-02.js123
-rw-r--r--browser/devtools/netmonitor/test/browser_net_autoscroll.js89
-rw-r--r--browser/devtools/netmonitor/test/browser_net_content-type.js228
-rw-r--r--browser/devtools/netmonitor/test/browser_net_cyrillic-01.js41
-rw-r--r--browser/devtools/netmonitor/test/browser_net_cyrillic-02.js42
-rw-r--r--browser/devtools/netmonitor/test/browser_net_filter-01.js184
-rw-r--r--browser/devtools/netmonitor/test/browser_net_filter-02.js181
-rw-r--r--browser/devtools/netmonitor/test/browser_net_filter-03.js186
-rw-r--r--browser/devtools/netmonitor/test/browser_net_footer-summary.js121
-rw-r--r--browser/devtools/netmonitor/test/browser_net_json-long.js96
-rw-r--r--browser/devtools/netmonitor/test/browser_net_json-malformed.js71
-rw-r--r--browser/devtools/netmonitor/test/browser_net_jsonp.js83
-rw-r--r--browser/devtools/netmonitor/test/browser_net_large-response.js47
-rw-r--r--browser/devtools/netmonitor/test/browser_net_page-nav.js68
-rw-r--r--browser/devtools/netmonitor/test/browser_net_pane-collapse.js66
-rw-r--r--browser/devtools/netmonitor/test/browser_net_pane-toggle.js79
-rw-r--r--browser/devtools/netmonitor/test/browser_net_post-data-01.js153
-rw-r--r--browser/devtools/netmonitor/test/browser_net_post-data-02.js62
-rw-r--r--browser/devtools/netmonitor/test/browser_net_prefs-and-l10n.js67
-rw-r--r--browser/devtools/netmonitor/test/browser_net_prefs-reload.js217
-rw-r--r--browser/devtools/netmonitor/test/browser_net_req-resp-bodies.js60
-rw-r--r--browser/devtools/netmonitor/test/browser_net_simple-init.js84
-rw-r--r--browser/devtools/netmonitor/test/browser_net_simple-request-data.js237
-rw-r--r--browser/devtools/netmonitor/test/browser_net_simple-request-details.js239
-rw-r--r--browser/devtools/netmonitor/test/browser_net_simple-request.js60
-rw-r--r--browser/devtools/netmonitor/test/browser_net_sort-01.js248
-rw-r--r--browser/devtools/netmonitor/test/browser_net_sort-02.js249
-rw-r--r--browser/devtools/netmonitor/test/browser_net_sort-03.js177
-rw-r--r--browser/devtools/netmonitor/test/browser_net_status-codes.js155
-rw-r--r--browser/devtools/netmonitor/test/browser_net_timeline_ticks.js135
-rw-r--r--browser/devtools/netmonitor/test/head.js283
-rw-r--r--browser/devtools/netmonitor/test/html_content-type-test-page.html43
-rw-r--r--browser/devtools/netmonitor/test/html_custom-get-page.html39
-rw-r--r--browser/devtools/netmonitor/test/html_cyrillic-test-page.html34
-rw-r--r--browser/devtools/netmonitor/test/html_filter-test-page.html55
-rw-r--r--browser/devtools/netmonitor/test/html_infinite-get-page.html36
-rw-r--r--browser/devtools/netmonitor/test/html_json-long-test-page.html33
-rw-r--r--browser/devtools/netmonitor/test/html_json-malformed-test-page.html33
-rw-r--r--browser/devtools/netmonitor/test/html_jsonp-test-page.html33
-rw-r--r--browser/devtools/netmonitor/test/html_navigate-test-page.html13
-rw-r--r--browser/devtools/netmonitor/test/html_post-data-test-page.html72
-rw-r--r--browser/devtools/netmonitor/test/html_post-raw-test-page.html34
-rw-r--r--browser/devtools/netmonitor/test/html_simple-test-page.html13
-rw-r--r--browser/devtools/netmonitor/test/html_sorting-test-page.html42
-rw-r--r--browser/devtools/netmonitor/test/html_status-codes-test-page.html41
-rw-r--r--browser/devtools/netmonitor/test/moz.build5
-rw-r--r--browser/devtools/netmonitor/test/sjs_content-type-test-server.sjs127
-rw-r--r--browser/devtools/netmonitor/test/sjs_simple-test-server.sjs9
-rw-r--r--browser/devtools/netmonitor/test/sjs_sorting-test-server.sjs18
-rw-r--r--browser/devtools/netmonitor/test/sjs_status-codes-test-server.sjs34
-rw-r--r--browser/devtools/netmonitor/test/test-image.pngbin0 -> 580 bytes
54 files changed, 5026 insertions, 0 deletions
diff --git a/browser/devtools/netmonitor/test/Makefile.in b/browser/devtools/netmonitor/test/Makefile.in
new file mode 100644
index 000000000..7ec624bac
--- /dev/null
+++ b/browser/devtools/netmonitor/test/Makefile.in
@@ -0,0 +1,73 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH = @DEPTH@
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MOCHITEST_BROWSER_TESTS = \
+ browser_net_aaa_leaktest.js \
+ browser_net_autoscroll.js \
+ browser_net_simple-init.js \
+ browser_net_page-nav.js \
+ browser_net_prefs-and-l10n.js \
+ browser_net_prefs-reload.js \
+ browser_net_pane-collapse.js \
+ browser_net_pane-toggle.js \
+ browser_net_simple-request.js \
+ browser_net_simple-request-data.js \
+ browser_net_simple-request-details.js \
+ browser_net_content-type.js \
+ browser_net_cyrillic-01.js \
+ browser_net_cyrillic-02.js \
+ browser_net_large-response.js \
+ browser_net_status-codes.js \
+ browser_net_post-data-01.js \
+ browser_net_post-data-02.js \
+ browser_net_jsonp.js \
+ browser_net_json-long.js \
+ browser_net_json-malformed.js \
+ browser_net_timeline_ticks.js \
+ browser_net_sort-01.js \
+ browser_net_sort-02.js \
+ browser_net_sort-03.js \
+ browser_net_filter-01.js \
+ browser_net_filter-02.js \
+ browser_net_filter-03.js \
+ browser_net_accessibility-01.js \
+ browser_net_accessibility-02.js \
+ browser_net_footer-summary.js \
+ browser_net_req-resp-bodies.js \
+ head.js \
+ $(NULL)
+
+MOCHITEST_BROWSER_PAGES = \
+ test-image.png \
+ html_simple-test-page.html \
+ html_navigate-test-page.html \
+ html_content-type-test-page.html \
+ html_cyrillic-test-page.html \
+ html_status-codes-test-page.html \
+ html_post-data-test-page.html \
+ html_post-raw-test-page.html \
+ html_jsonp-test-page.html \
+ html_json-long-test-page.html \
+ html_json-malformed-test-page.html \
+ html_sorting-test-page.html \
+ html_filter-test-page.html \
+ html_infinite-get-page.html \
+ html_custom-get-page.html \
+ sjs_simple-test-server.sjs \
+ sjs_content-type-test-server.sjs \
+ sjs_status-codes-test-server.sjs \
+ sjs_sorting-test-server.sjs \
+ $(NULL)
+
+MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
+
+include $(topsrcdir)/config/rules.mk
diff --git a/browser/devtools/netmonitor/test/browser_net_aaa_leaktest.js b/browser/devtools/netmonitor/test/browser_net_aaa_leaktest.js
new file mode 100644
index 000000000..a9cd6fea7
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_aaa_leaktest.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the network monitor leaks on initialization and sudden destruction.
+ * You can also use this initialization format as a template for other tests.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, NetMonitorView, NetMonitorController } = aMonitor.panelWin;
+ let { RequestsMenu, NetworkDetails } = NetMonitorView;
+
+ ok(aTab, "Should have a tab available.");
+ ok(aDebuggee, "Should have a debuggee available.");
+ ok(aMonitor, "Should have a network monitor pane available.");
+
+ ok(document, "Should have a document available.");
+ ok(NetMonitorView, "Should have a NetMonitorView object available.");
+ ok(NetMonitorController, "Should have a NetMonitorController object available.");
+ ok(RequestsMenu, "Should have a RequestsMenu object available.");
+ ok(NetworkDetails, "Should have a NetworkDetails object available.");
+
+ teardown(aMonitor).then(finish);
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_accessibility-01.js b/browser/devtools/netmonitor/test/browser_net_accessibility-01.js
new file mode 100644
index 000000000..7c9f54391
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_accessibility-01.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if focus modifiers work for the SideMenuWidget.
+ */
+
+function test() {
+ initNetMonitor(CUSTOM_GET_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 2).then(() => {
+ check(-1, false);
+
+ RequestsMenu.focusLastVisibleItem();
+ check(1, true);
+ RequestsMenu.focusFirstVisibleItem();
+ check(0, true);
+
+ RequestsMenu.focusNextItem();
+ check(1, true);
+ RequestsMenu.focusPrevItem();
+ check(0, true);
+
+ RequestsMenu.focusItemAtDelta(+1);
+ check(1, true);
+ RequestsMenu.focusItemAtDelta(-1);
+ check(0, true);
+
+ RequestsMenu.focusItemAtDelta(+10);
+ check(1, true);
+ RequestsMenu.focusItemAtDelta(-10);
+ check(0, true);
+
+ aDebuggee.performRequests(18);
+ return waitForNetworkEvents(aMonitor, 18);
+ })
+ .then(() => {
+ RequestsMenu.focusLastVisibleItem();
+ check(19, true);
+ RequestsMenu.focusFirstVisibleItem();
+ check(0, true);
+
+ RequestsMenu.focusNextItem();
+ check(1, true);
+ RequestsMenu.focusPrevItem();
+ check(0, true);
+
+ RequestsMenu.focusItemAtDelta(+10);
+ check(10, true);
+ RequestsMenu.focusItemAtDelta(-10);
+ check(0, true);
+
+ RequestsMenu.focusItemAtDelta(+100);
+ check(19, true);
+ RequestsMenu.focusItemAtDelta(-100);
+ check(0, true);
+
+ teardown(aMonitor).then(finish);
+ });
+
+ let count = 0;
+
+ function check(aSelectedIndex, aPaneVisibility) {
+ info("Performing check " + (count++) + ".");
+
+ is(RequestsMenu.selectedIndex, aSelectedIndex,
+ "The selected item in the requests menu was incorrect.");
+ is(NetMonitorView.detailsPaneHidden, !aPaneVisibility,
+ "The network requests details pane visibility state was incorrect.");
+ }
+
+ aDebuggee.performRequests(2);
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_accessibility-02.js b/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
new file mode 100644
index 000000000..aac9162e1
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
@@ -0,0 +1,123 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if keyboard and mouse navigation works in the network requests menu.
+ */
+
+function test() {
+ initNetMonitor(CUSTOM_GET_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { window, $, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 2).then(() => {
+ check(-1, false);
+
+ EventUtils.sendKey("DOWN", window);
+ check(0, true);
+ EventUtils.sendKey("UP", window);
+ check(0, true);
+
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(1, true);
+ EventUtils.sendKey("PAGE_UP", window);
+ check(0, true);
+
+ EventUtils.sendKey("END", window);
+ check(1, true);
+ EventUtils.sendKey("HOME", window);
+ check(0, true);
+
+ aDebuggee.performRequests(18);
+ return waitForNetworkEvents(aMonitor, 18);
+ })
+ .then(() => {
+ EventUtils.sendKey("DOWN", window);
+ check(1, true);
+ EventUtils.sendKey("DOWN", window);
+ check(2, true);
+ EventUtils.sendKey("UP", window);
+ check(1, true);
+ EventUtils.sendKey("UP", window);
+ check(0, true);
+
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(4, true);
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(8, true);
+ EventUtils.sendKey("PAGE_UP", window);
+ check(4, true);
+ EventUtils.sendKey("PAGE_UP", window);
+ check(0, true);
+
+ EventUtils.sendKey("HOME", window);
+ check(0, true);
+ EventUtils.sendKey("HOME", window);
+ check(0, true);
+ EventUtils.sendKey("PAGE_UP", window);
+ check(0, true);
+ EventUtils.sendKey("HOME", window);
+ check(0, true);
+
+ EventUtils.sendKey("END", window);
+ check(19, true);
+ EventUtils.sendKey("END", window);
+ check(19, true);
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(19, true);
+ EventUtils.sendKey("END", window);
+ check(19, true);
+
+ EventUtils.sendKey("PAGE_UP", window);
+ check(15, true);
+ EventUtils.sendKey("PAGE_UP", window);
+ check(11, true);
+ EventUtils.sendKey("UP", window);
+ check(10, true);
+ EventUtils.sendKey("UP", window);
+ check(9, true);
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(13, true);
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(17, true);
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(19, true);
+ EventUtils.sendKey("PAGE_DOWN", window);
+ check(19, true);
+
+ EventUtils.sendKey("HOME", window);
+ check(0, true);
+ EventUtils.sendKey("DOWN", window);
+ check(1, true);
+ EventUtils.sendKey("END", window);
+ check(19, true);
+ EventUtils.sendKey("DOWN", window);
+ check(19, true);
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
+ check(-1, false);
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, $(".side-menu-widget-item"));
+ check(0, true);
+
+ teardown(aMonitor).then(finish);
+ });
+
+ let count = 0;
+
+ function check(aSelectedIndex, aPaneVisibility) {
+ info("Performing check " + (count++) + ".");
+
+ is(RequestsMenu.selectedIndex, aSelectedIndex,
+ "The selected item in the requests menu was incorrect.");
+ is(NetMonitorView.detailsPaneHidden, !aPaneVisibility,
+ "The network requests details pane visibility state was incorrect.");
+ }
+
+ aDebuggee.performRequests(2);
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_autoscroll.js b/browser/devtools/netmonitor/test/browser_net_autoscroll.js
new file mode 100644
index 000000000..64f60badf
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_autoscroll.js
@@ -0,0 +1,89 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Bug 863102 - Automatically scroll down upon new network requests.
+ */
+
+function test() {
+ let monitor, debuggee, requestsContainer, scrollTop;
+
+ initNetMonitor(INFINITE_GET_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ monitor = aMonitor;
+ debuggee = aDebuggee;
+ let win = monitor.panelWin;
+ let topNode = win.document.getElementById("requests-menu-contents");
+ requestsContainer = topNode.getElementsByTagName("scrollbox")[0];
+ ok(!!requestsContainer, "Container element exists as expected.");
+ })
+
+ // (1) Check that the scroll position is maintained at the bottom
+ // when the requests overflow the vertical size of the container.
+ .then(() => {
+ return waitForRequestsToOverflowContainer(monitor, requestsContainer);
+ })
+ .then(() => {
+ ok(scrolledToBottom(requestsContainer), "Scrolled to bottom on overflow.");
+ })
+
+ // (2) Now set the scroll position somewhere in the middle and check
+ // that additional requests do not change the scroll position.
+ .then(() => {
+ let children = requestsContainer.childNodes;
+ let middleNode = children.item(children.length / 2);
+ middleNode.scrollIntoView();
+ ok(!scrolledToBottom(requestsContainer), "Not scrolled to bottom.");
+ scrollTop = requestsContainer.scrollTop; // save for comparison later
+ return waitForNetworkEvents(monitor, 8);
+ })
+ .then(() => {
+ is(requestsContainer.scrollTop, scrollTop, "Did not scroll.");
+ })
+
+ // (3) Now set the scroll position back at the bottom and check that
+ // additional requests *do* cause the container to scroll down.
+ .then(() => {
+ requestsContainer.scrollTop = requestsContainer.scrollHeight;
+ ok(scrolledToBottom(requestsContainer), "Set scroll position to bottom.");
+ return waitForNetworkEvents(monitor, 8);
+ })
+ .then(() => {
+ ok(scrolledToBottom(requestsContainer), "Still scrolled to bottom.");
+ })
+
+ // (4) Now select an item in the list and check that additional requests
+ // do not change the scroll position.
+ .then(() => {
+ monitor.panelWin.NetMonitorView.RequestsMenu.selectedIndex = 0;
+ return waitForNetworkEvents(monitor, 8);
+ })
+ .then(() => {
+ is(requestsContainer.scrollTop, 0, "Did not scroll.");
+ })
+
+ // Done; clean up.
+ .then(() => {
+ return teardown(monitor).then(finish);
+ })
+
+ // Handle exceptions in the chain of promises.
+ .then(null, (err) => {
+ ok(false, err);
+ finish();
+ });
+
+ function waitForRequestsToOverflowContainer (aMonitor, aContainer) {
+ return waitForNetworkEvents(aMonitor, 1).then(() => {
+ if (aContainer.scrollHeight > aContainer.clientHeight) {
+ // Wait for some more just for good measure.
+ return waitForNetworkEvents(aMonitor, 8);
+ } else {
+ return waitForRequestsToOverflowContainer(aMonitor, aContainer);
+ }
+ });
+ }
+
+ function scrolledToBottom(aElement) {
+ return aElement.scrollTop + aElement.clientHeight >= aElement.scrollHeight;
+ }
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_content-type.js b/browser/devtools/netmonitor/test/browser_net_content-type.js
new file mode 100644
index 000000000..3c7ed2d62
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_content-type.js
@@ -0,0 +1,228 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if different response content types are handled correctly.
+ */
+
+function test() {
+ initNetMonitor(CONTENT_TYPE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 6).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CONTENT_TYPE_SJS + "?fmt=xml", {
+ status: 200,
+ statusText: "OK",
+ type: "xml",
+ fullMimeType: "text/xml; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
+ "GET", CONTENT_TYPE_SJS + "?fmt=css", {
+ status: 200,
+ statusText: "OK",
+ type: "css",
+ fullMimeType: "text/css; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2),
+ "GET", CONTENT_TYPE_SJS + "?fmt=js", {
+ status: 200,
+ statusText: "OK",
+ type: "js",
+ fullMimeType: "application/javascript; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3),
+ "GET", CONTENT_TYPE_SJS + "?fmt=json", {
+ status: 200,
+ statusText: "OK",
+ type: "json",
+ fullMimeType: "application/json; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
+ "GET", CONTENT_TYPE_SJS + "?fmt=bogus", {
+ status: 404,
+ statusText: "Not Found",
+ type: "html",
+ fullMimeType: "text/html; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5),
+ "GET", TEST_IMAGE, {
+ status: 200,
+ statusText: "OK",
+ type: "png",
+ fullMimeType: "image/png",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.75),
+ time: true
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+
+ testResponseTab("xml")
+ .then(() => {
+ RequestsMenu.selectedIndex = 1;
+ return testResponseTab("css");
+ })
+ .then(() => {
+ RequestsMenu.selectedIndex = 2;
+ return testResponseTab("js");
+ })
+ .then(() => {
+ RequestsMenu.selectedIndex = 3;
+ return testResponseTab("json");
+ })
+ .then(() => {
+ RequestsMenu.selectedIndex = 4;
+ return testResponseTab("html");
+ })
+ .then(() => {
+ RequestsMenu.selectedIndex = 5;
+ return testResponseTab("png");
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+
+ function testResponseTab(aType) {
+ let tab = document.querySelectorAll("#details-pane tab")[3];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
+
+ is(tab.getAttribute("selected"), "true",
+ "The response tab in the network details pane should be selected.");
+
+ function checkVisibility(aBox) {
+ is(tabpanel.querySelector("#response-content-info-header")
+ .hasAttribute("hidden"), true,
+ "The response info header doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-json-box")
+ .hasAttribute("hidden"), aBox != "json",
+ "The response content json box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-textarea-box")
+ .hasAttribute("hidden"), aBox != "textarea",
+ "The response content textarea box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-image-box")
+ .hasAttribute("hidden"), aBox != "image",
+ "The response content image box doesn't have the intended visibility.");
+ }
+
+ switch (aType) {
+ case "xml": {
+ checkVisibility("textarea");
+
+ return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText(), "<label value='greeting'>Hello XML!</label>",
+ "The text shown in the source editor is incorrect for the xml request.");
+ is(aEditor.getMode(), SourceEditor.MODES.HTML,
+ "The mode active in the source editor is incorrect for the xml request.");
+ });
+ }
+ case "css": {
+ checkVisibility("textarea");
+
+ return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText(), "body:pre { content: 'Hello CSS!' }",
+ "The text shown in the source editor is incorrect for the xml request.");
+ is(aEditor.getMode(), SourceEditor.MODES.CSS,
+ "The mode active in the source editor is incorrect for the xml request.");
+ });
+ }
+ case "js": {
+ checkVisibility("textarea");
+
+ return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText(), "function() { return 'Hello JS!'; }",
+ "The text shown in the source editor is incorrect for the xml request.");
+ is(aEditor.getMode(), SourceEditor.MODES.JAVASCRIPT,
+ "The mode active in the source editor is incorrect for the xml request.");
+ });
+ }
+ case "json": {
+ checkVisibility("json");
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
+ "There should be 1 json scope displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-property").length, 2,
+ "There should be 2 json properties displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+ "The empty notice should not be displayed in this tabpanel.");
+
+ let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+
+ is(jsonScope.querySelector(".name").getAttribute("value"),
+ L10N.getStr("jsonScopeName"),
+ "The json scope doesn't have the correct title.");
+
+ is(jsonScope.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
+ "greeting", "The first json property name was incorrect.");
+ is(jsonScope.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
+ "\"Hello JSON!\"", "The first json property value was incorrect.");
+
+ is(jsonScope.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
+ "__proto__", "The second json property name was incorrect.");
+ is(jsonScope.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
+ "[object Object]", "The second json property value was incorrect.");
+
+ return Promise.resolve();
+ }
+ case "html": {
+ checkVisibility("textarea");
+
+ return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText(), "<blink>Not Found</blink>",
+ "The text shown in the source editor is incorrect for the xml request.");
+ is(aEditor.getMode(), SourceEditor.MODES.HTML,
+ "The mode active in the source editor is incorrect for the xml request.");
+ });
+ }
+ case "png": {
+ checkVisibility("image");
+
+ let imageNode = tabpanel.querySelector("#response-content-image");
+ let deferred = Promise.defer();
+
+ imageNode.addEventListener("load", function onLoad() {
+ imageNode.removeEventListener("load", onLoad);
+
+ is(tabpanel.querySelector("#response-content-image-name-value")
+ .getAttribute("value"), "test-image.png",
+ "The image name info isn't correct.");
+ is(tabpanel.querySelector("#response-content-image-mime-value")
+ .getAttribute("value"), "image/png",
+ "The image mime info isn't correct.");
+ is(tabpanel.querySelector("#response-content-image-encoding-value")
+ .getAttribute("value"), "base64",
+ "The image encoding info isn't correct.");
+ is(tabpanel.querySelector("#response-content-image-dimensions-value")
+ .getAttribute("value"), "16 x 16",
+ "The image dimensions info isn't correct.");
+
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+ }
+ }
+ }
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js b/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js
new file mode 100644
index 000000000..f9da54b31
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js
@@ -0,0 +1,41 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if cyrillic text is rendered correctly in the source editor.
+ */
+
+function test() {
+ initNetMonitor(CYRILLIC_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CONTENT_TYPE_SJS + "?fmt=txt", {
+ status: 200,
+ statusText: "DA DA DA"
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+
+ NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText().indexOf("\u044F"), 26, // я
+ "The text shown in the source editor is incorrect.");
+ is(aEditor.getMode(), SourceEditor.MODES.TEXT,
+ "The mode active in the source editor is incorrect.");
+
+ teardown(aMonitor).then(finish);
+ });
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js b/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js
new file mode 100644
index 000000000..d47d8e4af
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if cyrillic text is rendered correctly in the source editor
+ * when loaded directly from an HTML page.
+ */
+
+function test() {
+ initNetMonitor(CYRILLIC_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CYRILLIC_URL, {
+ status: 200,
+ statusText: "OK"
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+
+ NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText().indexOf("\u044F"), 189, // я
+ "The text shown in the source editor is incorrect.");
+ is(aEditor.getMode(), SourceEditor.MODES.HTML,
+ "The mode active in the source editor is incorrect.");
+
+ teardown(aMonitor).then(finish);
+ });
+ });
+
+ aDebuggee.location.reload();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_filter-01.js b/browser/devtools/netmonitor/test/browser_net_filter-01.js
new file mode 100644
index 000000000..c6d36e57f
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_filter-01.js
@@ -0,0 +1,184 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if filtering items in the network table works correctly.
+ */
+
+function test() {
+ initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { $, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 8).then(() => {
+ EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
+
+ isnot(RequestsMenu.selectedItem, null,
+ "There should be a selected item in the requests menu.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be selected in the requests menu.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should not be hidden after toggle button was pressed.");
+
+ testButtons("all");
+ testContents([1, 1, 1, 1, 1, 1, 1, 1])
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
+ testButtons("html");
+ return testContents([1, 0, 0, 0, 0, 0, 0, 0]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
+ testButtons("css");
+ return testContents([0, 1, 0, 0, 0, 0, 0, 0]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-js-button"));
+ testButtons("js");
+ return testContents([0, 0, 1, 0, 0, 0, 0, 0]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-xhr-button"));
+ testButtons("xhr");
+ return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-fonts-button"));
+ testButtons("fonts");
+ return testContents([0, 0, 0, 1, 0, 0, 0, 0]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-images-button"));
+ testButtons("images");
+ return testContents([0, 0, 0, 0, 1, 0, 0, 0]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-media-button"));
+ testButtons("media");
+ return testContents([0, 0, 0, 0, 0, 1, 1, 0]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
+ testButtons("flash");
+ return testContents([0, 0, 0, 0, 0, 0, 0, 1]);
+ })
+ .then(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
+ testButtons("all");
+ return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ function testButtons(aFilterType) {
+ let doc = aMonitor.panelWin.document;
+ let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
+ let buttons = doc.querySelectorAll(".requests-menu-footer-button");
+
+ for (let button of buttons) {
+ if (button != target) {
+ is(button.hasAttribute("checked"), false,
+ "The " + button.id + " button should not have a 'checked' attribute.");
+ } else {
+ is(button.hasAttribute("checked"), true,
+ "The " + button.id + " button should have a 'checked' attribute.");
+ }
+ }
+ }
+
+ function testContents(aVisibility) {
+ isnot(RequestsMenu.selectedItem, null,
+ "There should still be a selected item after filtering.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be still selected after filtering.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should still be visible after filtering.");
+
+ is(RequestsMenu.orderedItems.length, aVisibility.length,
+ "There should be a specific amount of items in the requests menu.");
+ is(RequestsMenu.visibleItems.length, aVisibility.filter(e => e).length,
+ "There should be a specific amount of visbile items in the requests menu.");
+
+ for (let i = 0; i < aVisibility.length; i++) {
+ is(RequestsMenu.getItemAtIndex(i).target.hidden, !aVisibility[i],
+ "The item at index " + i + " doesn't have the correct hidden state.");
+ }
+
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CONTENT_TYPE_SJS + "?fmt=html", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "html",
+ fullMimeType: "text/html; charset=utf-8"
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
+ "GET", CONTENT_TYPE_SJS + "?fmt=css", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "css",
+ fullMimeType: "text/css; charset=utf-8"
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2),
+ "GET", CONTENT_TYPE_SJS + "?fmt=js", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "js",
+ fullMimeType: "application/javascript; charset=utf-8"
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3),
+ "GET", CONTENT_TYPE_SJS + "?fmt=font", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "woff",
+ fullMimeType: "font/woff"
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
+ "GET", CONTENT_TYPE_SJS + "?fmt=image", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "png",
+ fullMimeType: "image/png"
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5),
+ "GET", CONTENT_TYPE_SJS + "?fmt=audio", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "ogg",
+ fullMimeType: "audio/ogg"
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
+ "GET", CONTENT_TYPE_SJS + "?fmt=video", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "webm",
+ fullMimeType: "video/webm"
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(7),
+ "GET", CONTENT_TYPE_SJS + "?fmt=flash", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "x-shockwave-flash",
+ fullMimeType: "application/x-shockwave-flash"
+ });
+
+ return Promise.resolve(null);
+ }
+
+ aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_filter-02.js b/browser/devtools/netmonitor/test/browser_net_filter-02.js
new file mode 100644
index 000000000..5b8c6457a
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_filter-02.js
@@ -0,0 +1,181 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if filtering items in the network table works correctly with new requests.
+ */
+
+function test() {
+ initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { $, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 8).then(() => {
+ EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
+
+ isnot(RequestsMenu.selectedItem, null,
+ "There should be a selected item in the requests menu.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be selected in the requests menu.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should not be hidden after toggle button was pressed.");
+
+ testButtons("all");
+ testContents([1, 1, 1, 1, 1, 1, 1, 1])
+ .then(() => {
+ info("Testing html filtering.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
+ testButtons("html");
+ return testContents([1, 0, 0, 0, 0, 0, 0, 0]);
+ })
+ .then(() => {
+ info("Performing more requests.");
+ aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
+ return waitForNetworkEvents(aMonitor, 8);
+ })
+ .then(() => {
+ info("Testing html filtering again.");
+ testButtons("html");
+ return testContents([1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
+ })
+ .then(() => {
+ info("Performing more requests.");
+ aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
+ return waitForNetworkEvents(aMonitor, 8);
+ })
+ .then(() => {
+ info("Testing html filtering again.");
+ testButtons("html");
+ return testContents([1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ function testButtons(aFilterType) {
+ let doc = aMonitor.panelWin.document;
+ let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
+ let buttons = doc.querySelectorAll(".requests-menu-footer-button");
+
+ for (let button of buttons) {
+ if (button != target) {
+ is(button.hasAttribute("checked"), false,
+ "The " + button.id + " button should not have a 'checked' attribute.");
+ } else {
+ is(button.hasAttribute("checked"), true,
+ "The " + button.id + " button should have a 'checked' attribute.");
+ }
+ }
+ }
+
+ function testContents(aVisibility) {
+ isnot(RequestsMenu.selectedItem, null,
+ "There should still be a selected item after filtering.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be still selected after filtering.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should still be visible after filtering.");
+
+ is(RequestsMenu.orderedItems.length, aVisibility.length,
+ "There should be a specific amount of items in the requests menu.");
+ is(RequestsMenu.visibleItems.length, aVisibility.filter(e => e).length,
+ "There should be a specific amount of visbile items in the requests menu.");
+
+ for (let i = 0; i < aVisibility.length; i++) {
+ is(RequestsMenu.getItemAtIndex(i).target.hidden, !aVisibility[i],
+ "The item at index " + i + " doesn't have the correct hidden state.");
+ }
+
+ for (let i = 0; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=html", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "html",
+ fullMimeType: "text/html; charset=utf-8"
+ });
+ }
+ for (let i = 1; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=css", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "css",
+ fullMimeType: "text/css; charset=utf-8"
+ });
+ }
+ for (let i = 2; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=js", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "js",
+ fullMimeType: "application/javascript; charset=utf-8"
+ });
+ }
+ for (let i = 3; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=font", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "woff",
+ fullMimeType: "font/woff"
+ });
+ }
+ for (let i = 4; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=image", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "png",
+ fullMimeType: "image/png"
+ });
+ }
+ for (let i = 5; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=audio", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "ogg",
+ fullMimeType: "audio/ogg"
+ });
+ }
+ for (let i = 6; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=video", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "webm",
+ fullMimeType: "video/webm"
+ });
+ }
+ for (let i = 7; i < aVisibility.length; i += 8) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
+ "GET", CONTENT_TYPE_SJS + "?fmt=flash", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "x-shockwave-flash",
+ fullMimeType: "application/x-shockwave-flash"
+ });
+ }
+
+ return Promise.resolve(null);
+ }
+
+ aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_filter-03.js b/browser/devtools/netmonitor/test/browser_net_filter-03.js
new file mode 100644
index 000000000..e874a02ad
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_filter-03.js
@@ -0,0 +1,186 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if filtering items in the network table works correctly with new requests
+ * and while sorting is enabled.
+ */
+
+function test() {
+ initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { $, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 7).then(() => {
+ EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
+
+ isnot(RequestsMenu.selectedItem, null,
+ "There should be a selected item in the requests menu.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be selected in the requests menu.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should not be hidden after toggle button was pressed.");
+
+ testButtons("all");
+ testContents([0, 1, 2, 3, 4, 5, 6], 7, 0)
+ .then(() => {
+ info("Sorting by size, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
+ testButtons("all");
+ return testContents([6, 4, 5, 0, 1, 2, 3], 7, 6);
+ })
+ .then(() => {
+ info("Testing html filtering.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
+ testButtons("html");
+ return testContents([6, 4, 5, 0, 1, 2, 3], 1, 6);
+ })
+ .then(() => {
+ info("Performing more requests.");
+ aDebuggee.performRequests('{ "getMedia": true }');
+ return waitForNetworkEvents(aMonitor, 7);
+ })
+ .then(() => {
+ info("Testing html filtering again.");
+ resetSorting();
+ testButtons("html");
+ return testContents([8, 13, 9, 11, 10, 12, 0, 4, 1, 5, 2, 6, 3, 7], 2, 13);
+ })
+ .then(() => {
+ info("Performing more requests.");
+ aDebuggee.performRequests('{ "getMedia": true }');
+ return waitForNetworkEvents(aMonitor, 7);
+ })
+ .then(() => {
+ info("Testing html filtering again.");
+ resetSorting();
+ testButtons("html");
+ return testContents([12, 13, 20, 14, 16, 18, 15, 17, 19, 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11], 3, 20);
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ function resetSorting() {
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-waterfall-button"));
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
+ }
+
+ function testButtons(aFilterType) {
+ let doc = aMonitor.panelWin.document;
+ let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
+ let buttons = doc.querySelectorAll(".requests-menu-footer-button");
+
+ for (let button of buttons) {
+ if (button != target) {
+ is(button.hasAttribute("checked"), false,
+ "The " + button.id + " button should not have a 'checked' attribute.");
+ } else {
+ is(button.hasAttribute("checked"), true,
+ "The " + button.id + " button should have a 'checked' attribute.");
+ }
+ }
+ }
+
+ function testContents(aOrder, aVisible, aSelection) {
+ isnot(RequestsMenu.selectedItem, null,
+ "There should still be a selected item after filtering.");
+ is(RequestsMenu.selectedIndex, aSelection,
+ "The first item should be still selected after filtering.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should still be visible after filtering.");
+
+ is(RequestsMenu.orderedItems.length, aOrder.length,
+ "There should be a specific amount of items in the requests menu.");
+ is(RequestsMenu.visibleItems.length, aVisible,
+ "There should be a specific amount of visbile items in the requests menu.");
+
+ for (let i = 0; i < aOrder.length; i++) {
+ is(RequestsMenu.getItemAtIndex(i), RequestsMenu.orderedItems[i],
+ "The requests menu items aren't ordered correctly. Misplaced item " + i + ".");
+ }
+
+ for (let i = 0, len = aOrder.length / 7; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i]),
+ "GET", CONTENT_TYPE_SJS + "?fmt=html", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "html",
+ fullMimeType: "text/html; charset=utf-8"
+ });
+ }
+ for (let i = 0, len = aOrder.length / 7; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len]),
+ "GET", CONTENT_TYPE_SJS + "?fmt=css", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "css",
+ fullMimeType: "text/css; charset=utf-8"
+ });
+ }
+ for (let i = 0, len = aOrder.length / 7; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 2]),
+ "GET", CONTENT_TYPE_SJS + "?fmt=js", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "js",
+ fullMimeType: "application/javascript; charset=utf-8"
+ });
+ }
+ for (let i = 0, len = aOrder.length / 7; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 3]),
+ "GET", CONTENT_TYPE_SJS + "?fmt=font", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "woff",
+ fullMimeType: "font/woff"
+ });
+ }
+ for (let i = 0, len = aOrder.length / 7; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 4]),
+ "GET", CONTENT_TYPE_SJS + "?fmt=image", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "png",
+ fullMimeType: "image/png"
+ });
+ }
+ for (let i = 0, len = aOrder.length / 7; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 5]),
+ "GET", CONTENT_TYPE_SJS + "?fmt=audio", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "ogg",
+ fullMimeType: "audio/ogg"
+ });
+ }
+ for (let i = 0, len = aOrder.length / 7; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 6]),
+ "GET", CONTENT_TYPE_SJS + "?fmt=video", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "OK",
+ type: "webm",
+ fullMimeType: "video/webm"
+ });
+ }
+
+ return Promise.resolve(null);
+ }
+
+ let str = "'<p>'" + new Array(10).join(Math.random(10)) + "'</p>'";
+ aDebuggee.performRequests('{ "htmlContent": "' + str + '", "getMedia": true }');
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_footer-summary.js b/browser/devtools/netmonitor/test/browser_net_footer-summary.js
new file mode 100644
index 000000000..4ef217f53
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_footer-summary.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if the summary text displayed in the network requests menu footer
+ * is correct.
+ */
+
+function test() {
+ let { PluralForm } = Cu.import("resource://gre/modules/PluralForm.jsm", {});
+
+ initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { $, L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+ testStatus();
+
+ waitForNetworkEvents(aMonitor, 8).then(() => {
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-js-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-xhr-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-fonts-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-images-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-media-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
+ testStatus();
+
+ info("Performing more requests.");
+ aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
+ return waitForNetworkEvents(aMonitor, 8);
+ })
+ .then(() => {
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-js-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-xhr-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-fonts-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-images-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-media-button"));
+ testStatus();
+
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
+ testStatus();
+
+ teardown(aMonitor).then(finish);
+ })
+
+ function testStatus() {
+ let summary = $("#request-menu-network-summary");
+ let value = summary.getAttribute("value");
+ info("Current summary: " + value);
+
+ let visibleItems = RequestsMenu.visibleItems;
+ let visibleRequestsCount = visibleItems.length;
+ let totalRequestsCount = RequestsMenu.itemCount;
+ info("Current requests: " + visibleRequestsCount + " of " + totalRequestsCount + ".");
+
+ if (!totalRequestsCount) {
+ is(value, "",
+ "The current summary text is incorrect, expected an empty string.");
+ return;
+ }
+
+ if (!visibleRequestsCount) {
+ is(value, L10N.getStr("networkMenu.empty"),
+ "The current summary text is incorrect, expected an 'empty' label.");
+ return;
+ }
+
+ let totalBytes = RequestsMenu._getTotalBytesOfRequests(visibleItems);
+ let totalMillis =
+ RequestsMenu._getNewestRequest(visibleItems).attachment.endedMillis -
+ RequestsMenu._getOldestRequest(visibleItems).attachment.startedMillis;
+
+ info("Computed total bytes: " + totalBytes);
+ info("Computed total millis: " + totalMillis);
+
+ is(value, PluralForm.get(visibleRequestsCount, L10N.getStr("networkMenu.summary"))
+ .replace("#1", visibleRequestsCount)
+ .replace("#2", L10N.numberWithDecimals((totalBytes || 0) / 1024, 2))
+ .replace("#3", L10N.numberWithDecimals((totalMillis || 0) / 1000, 2))
+ , "The current summary text is incorrect.")
+ }
+
+ aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_json-long.js b/browser/devtools/netmonitor/test/browser_net_json-long.js
new file mode 100644
index 000000000..c683b8cda
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_json-long.js
@@ -0,0 +1,96 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if very long JSON responses are handled correctly.
+ */
+
+function test() {
+ initNetMonitor(JSON_LONG_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ // This is receiving over 80 KB of json and will populate over 6000 items
+ // in a variables view instance. Debug builds are slow.
+ requestLongerTimeout(4);
+
+ let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CONTENT_TYPE_SJS + "?fmt=json-long", {
+ status: 200,
+ statusText: "OK",
+ type: "json",
+ fullMimeType: "text/json; charset=utf-8",
+ size: L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(85975/1024, 2)),
+ time: true
+ });
+
+ aMonitor.panelWin.once("NetMonitor:ResponseBodyAvailable", () => {
+ testResponseTab();
+ teardown(aMonitor).then(finish);
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+
+ function testResponseTab() {
+ let tab = document.querySelectorAll("#details-pane tab")[3];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
+
+ is(tab.getAttribute("selected"), "true",
+ "The response tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelector("#response-content-info-header")
+ .hasAttribute("hidden"), true,
+ "The response info header doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-json-box")
+ .hasAttribute("hidden"), false,
+ "The response content json box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-textarea-box")
+ .hasAttribute("hidden"), true,
+ "The response content textarea box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-image-box")
+ .hasAttribute("hidden"), true,
+ "The response content image box doesn't have the intended visibility.");
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
+ "There should be 1 json scope displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-property").length, 6057,
+ "There should be 6057 json properties displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+ "The empty notice should not be displayed in this tabpanel.");
+
+ let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+ let names = ".variables-view-property .name";
+ let values = ".variables-view-property .value";
+
+ is(jsonScope.querySelector(".name").getAttribute("value"),
+ L10N.getStr("jsonScopeName"),
+ "The json scope doesn't have the correct title.");
+
+ is(jsonScope.querySelectorAll(names)[0].getAttribute("value"),
+ "0", "The first json property name was incorrect.");
+ is(jsonScope.querySelectorAll(values)[0].getAttribute("value"),
+ "[object Object]", "The first json property value was incorrect.");
+
+ is(jsonScope.querySelectorAll(names)[1].getAttribute("value"),
+ "greeting", "The second json property name was incorrect.");
+ is(jsonScope.querySelectorAll(values)[1].getAttribute("value"),
+ "\"Hello long string JSON!\"", "The second json property value was incorrect.");
+
+ is(Array.slice(jsonScope.querySelectorAll(names), -1).shift().getAttribute("value"),
+ "__proto__", "The last json property name was incorrect.");
+ is(Array.slice(jsonScope.querySelectorAll(values), -1).shift().getAttribute("value"),
+ "[object Object]", "The last json property value was incorrect.");
+ }
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_json-malformed.js b/browser/devtools/netmonitor/test/browser_net_json-malformed.js
new file mode 100644
index 000000000..1ea3124d4
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_json-malformed.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if malformed JSON responses are handled correctly.
+ */
+
+function test() {
+ initNetMonitor(JSON_MALFORMED_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CONTENT_TYPE_SJS + "?fmt=json-malformed", {
+ status: 200,
+ statusText: "OK",
+ type: "json",
+ fullMimeType: "text/json; charset=utf-8"
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+
+ let tab = document.querySelectorAll("#details-pane tab")[3];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
+
+ is(tab.getAttribute("selected"), "true",
+ "The response tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelector("#response-content-info-header")
+ .hasAttribute("hidden"), false,
+ "The response info header doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-info-header")
+ .getAttribute("value"),
+ "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
+ "The response info header doesn't have the intended value attribute.");
+ is(tabpanel.querySelector("#response-content-info-header")
+ .getAttribute("tooltiptext"),
+ "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
+ "The response info header doesn't have the intended tooltiptext attribute.");
+
+ is(tabpanel.querySelector("#response-content-json-box")
+ .hasAttribute("hidden"), true,
+ "The response content json box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-textarea-box")
+ .hasAttribute("hidden"), false,
+ "The response content textarea box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-image-box")
+ .hasAttribute("hidden"), true,
+ "The response content image box doesn't have the intended visibility.");
+
+ NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText(), "{ \"greeting\": \"Hello malformed JSON!\" },",
+ "The text shown in the source editor is incorrect.");
+ is(aEditor.getMode(), SourceEditor.MODES.JAVASCRIPT,
+ "The mode active in the source editor is incorrect.");
+
+ teardown(aMonitor).then(finish);
+ });
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_jsonp.js b/browser/devtools/netmonitor/test/browser_net_jsonp.js
new file mode 100644
index 000000000..a3b3f03c9
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_jsonp.js
@@ -0,0 +1,83 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if JSONP responses are handled correctly.
+ */
+
+function test() {
+ initNetMonitor(JSONP_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CONTENT_TYPE_SJS + "?fmt=jsonp&jsonp=$_0123Fun", {
+ status: 200,
+ statusText: "OK",
+ type: "json",
+ fullMimeType: "text/json; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
+ time: true
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+
+ testResponseTab();
+ teardown(aMonitor).then(finish);
+
+ function testResponseTab() {
+ let tab = document.querySelectorAll("#details-pane tab")[3];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
+
+ is(tab.getAttribute("selected"), "true",
+ "The response tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelector("#response-content-info-header")
+ .hasAttribute("hidden"), true,
+ "The response info header doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-json-box")
+ .hasAttribute("hidden"), false,
+ "The response content json box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-textarea-box")
+ .hasAttribute("hidden"), true,
+ "The response content textarea box doesn't have the intended visibility.");
+ is(tabpanel.querySelector("#response-content-image-box")
+ .hasAttribute("hidden"), true,
+ "The response content image box doesn't have the intended visibility.");
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
+ "There should be 1 json scope displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-property").length, 2,
+ "There should be 2 json properties displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+ "The empty notice should not be displayed in this tabpanel.");
+
+ let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+
+ is(jsonScope.querySelector(".name").getAttribute("value"),
+ L10N.getFormatStr("jsonpScopeName", "$_0123Fun"),
+ "The json scope doesn't have the correct title.");
+
+ is(jsonScope.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
+ "greeting", "The first json property name was incorrect.");
+ is(jsonScope.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
+ "\"Hello JSONP!\"", "The first json property value was incorrect.");
+
+ is(jsonScope.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
+ "__proto__", "The second json property name was incorrect.");
+ is(jsonScope.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
+ "[object Object]", "The second json property value was incorrect.");
+ }
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_large-response.js b/browser/devtools/netmonitor/test/browser_net_large-response.js
new file mode 100644
index 000000000..41561ed50
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_large-response.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if very large response contents are just displayed as plain text.
+ */
+
+function test() {
+ initNetMonitor(CUSTOM_GET_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ // This test could potentially be slow because over 100 KB of stuff
+ // is going to be requested and displayed in the source editor.
+ requestLongerTimeout(2);
+
+ let { document, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "GET", CONTENT_TYPE_SJS + "?fmt=html-long", {
+ status: 200,
+ statusText: "OK"
+ });
+
+ aMonitor.panelWin.once("NetMonitor:ResponseBodyAvailable", () => {
+ NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ ok(aEditor.getText().match(/^<p>/),
+ "The text shown in the source editor is incorrect.");
+ is(aEditor.getMode(), SourceEditor.MODES.TEXT,
+ "The mode active in the source editor is incorrect.");
+
+ teardown(aMonitor).then(finish);
+ });
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+ });
+
+ aDebuggee.performRequests(1, CONTENT_TYPE_SJS + "?fmt=html-long");
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_page-nav.js b/browser/devtools/netmonitor/test/browser_net_page-nav.js
new file mode 100644
index 000000000..690a3b8c1
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_page-nav.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if page navigation ("close", "navigate", etc.) triggers an appropriate
+ * action in the network monitor.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ testNavigate(() => testNavigateBack(() => testClose(() => finish())));
+
+ function testNavigate(aCallback) {
+ info("Navigating forward...");
+
+ aMonitor.panelWin.once("NetMonitor:TargetWillNavigate", () => {
+ is(aDebuggee.location, SIMPLE_URL,
+ "Target started navigating to the correct location.");
+
+ aMonitor.panelWin.once("NetMonitor:TargetNavigate", () => {
+ is(aDebuggee.location, NAVIGATE_URL,
+ "Target finished navigating to the correct location.");
+
+ aCallback();
+ });
+ });
+
+ aDebuggee.location = NAVIGATE_URL;
+ }
+
+ function testNavigateBack(aCallback) {
+ info("Navigating backward...");
+
+ aMonitor.panelWin.once("NetMonitor:TargetWillNavigate", () => {
+ is(aDebuggee.location, NAVIGATE_URL,
+ "Target started navigating back to the previous location.");
+
+ aMonitor.panelWin.once("NetMonitor:TargetNavigate", () => {
+ is(aDebuggee.location, SIMPLE_URL,
+ "Target finished navigating back to the previous location.");
+
+ aCallback();
+ });
+ });
+
+ aDebuggee.location = SIMPLE_URL;
+ }
+
+ function testClose(aCallback) {
+ info("Closing...");
+
+ aMonitor.once("destroyed", () => {
+ ok(!aMonitor._controller.client,
+ "There shouldn't be a client available after destruction.");
+ ok(!aMonitor._controller.tabClient,
+ "There shouldn't be a tabClient available after destruction.");
+ ok(!aMonitor._controller.webConsoleClient,
+ "There shouldn't be a webConsoleClient available after destruction.");
+
+ aCallback();
+ });
+
+ removeTab(aTab);
+ }
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_pane-collapse.js b/browser/devtools/netmonitor/test/browser_net_pane-collapse.js
new file mode 100644
index 000000000..6434aa259
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_pane-collapse.js
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the network monitor panes collapse properly.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, Prefs, NetMonitorView } = aMonitor.panelWin;
+ let detailsPane = document.getElementById("details-pane");
+ let detailsPaneToggleButton = document.getElementById("details-pane-toggle");
+
+ ok(detailsPane.hasAttribute("pane-collapsed") &&
+ detailsPaneToggleButton.hasAttribute("pane-collapsed"),
+ "The details pane should initially be hidden.");
+
+ NetMonitorView.toggleDetailsPane({ visible: true, animated: false });
+
+ let width = ~~(detailsPane.getAttribute("width"));
+ is(width, Prefs.networkDetailsWidth,
+ "The details pane has an incorrect width.");
+ is(detailsPane.style.marginLeft, "0px",
+ "The details pane has an incorrect left margin.");
+ is(detailsPane.style.marginRight, "0px",
+ "The details pane has an incorrect right margin.");
+ ok(!detailsPane.hasAttribute("animated"),
+ "The details pane has an incorrect animated attribute.");
+ ok(!detailsPane.hasAttribute("pane-collapsed") &&
+ !detailsPaneToggleButton.hasAttribute("pane-collapsed"),
+ "The details pane should at this point be visible.");
+
+ NetMonitorView.toggleDetailsPane({ visible: false, animated: true });
+
+ let margin = -(width + 1) + "px";
+ is(width, Prefs.networkDetailsWidth,
+ "The details pane has an incorrect width after collapsing.");
+ is(detailsPane.style.marginLeft, margin,
+ "The details pane has an incorrect left margin after collapsing.");
+ is(detailsPane.style.marginRight, margin,
+ "The details pane has an incorrect right margin after collapsing.");
+ ok(detailsPane.hasAttribute("animated"),
+ "The details pane has an incorrect attribute after an animated collapsing.");
+ ok(detailsPane.hasAttribute("pane-collapsed") &&
+ detailsPaneToggleButton.hasAttribute("pane-collapsed"),
+ "The details pane should not be visible after collapsing.");
+
+ NetMonitorView.toggleDetailsPane({ visible: true, animated: false });
+
+ is(width, Prefs.networkDetailsWidth,
+ "The details pane has an incorrect width after uncollapsing.");
+ is(detailsPane.style.marginLeft, "0px",
+ "The details pane has an incorrect left margin after uncollapsing.");
+ is(detailsPane.style.marginRight, "0px",
+ "The details pane has an incorrect right margin after uncollapsing.");
+ ok(!detailsPane.hasAttribute("animated"),
+ "The details pane has an incorrect attribute after an unanimated uncollapsing.");
+ ok(!detailsPane.hasAttribute("pane-collapsed") &&
+ !detailsPaneToggleButton.hasAttribute("pane-collapsed"),
+ "The details pane should be visible again after uncollapsing.");
+
+ teardown(aMonitor).then(finish);
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_pane-toggle.js b/browser/devtools/netmonitor/test/browser_net_pane-toggle.js
new file mode 100644
index 000000000..552c39cda
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_pane-toggle.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if toggling the details pane works as expected.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("disabled"), true,
+ "The pane toggle button should be disabled when the frontend is opened.");
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("pane-collapsed"), true,
+ "The pane toggle button should indicate that the details pane is " +
+ "collapsed when the frontend is opened.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should be hidden when the frontend is opened.");
+ is(RequestsMenu.selectedItem, null,
+ "There should be no selected item in the requests menu.");
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("disabled"), false,
+ "The pane toggle button should be enabled after the first request.");
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("pane-collapsed"), true,
+ "The pane toggle button should still indicate that the details pane is " +
+ "collapsed after the first request.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should still be hidden after the first request.");
+ is(RequestsMenu.selectedItem, null,
+ "There should still be no selected item in the requests menu.");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("disabled"), false,
+ "The pane toggle button should still be enabled after being pressed.");
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("pane-collapsed"), false,
+ "The pane toggle button should now indicate that the details pane is " +
+ "not collapsed anymore after being pressed.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should not be hidden after toggle button was pressed.");
+ isnot(RequestsMenu.selectedItem, null,
+ "There should be a selected item in the requests menu.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be selected in the requests menu.");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("disabled"), false,
+ "The pane toggle button should still be enabled after being pressed again.");
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("pane-collapsed"), true,
+ "The pane toggle button should now indicate that the details pane is " +
+ "collapsed after being pressed again.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should now be hidden after the toggle button was pressed again.");
+ is(RequestsMenu.selectedItem, null,
+ "There should now be no selected item in the requests menu.");
+
+ teardown(aMonitor).then(finish);
+ });
+
+ aDebuggee.location.reload();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_post-data-01.js b/browser/devtools/netmonitor/test/browser_net_post-data-01.js
new file mode 100644
index 000000000..1e23adeb3
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_post-data-01.js
@@ -0,0 +1,153 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the POST requests display the correct information in the UI.
+ */
+
+function test() {
+ initNetMonitor(POST_DATA_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu, NetworkDetails } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+ NetworkDetails._params.lazyEmpty = false;
+
+ waitForNetworkEvents(aMonitor, 0, 2).then(() => {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
+ "POST", SIMPLE_SJS + "?foo=bar&baz=42&type=urlencoded", {
+ status: 200,
+ statusText: "Och Aye",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
+ "POST", SIMPLE_SJS + "?foo=bar&baz=42&type=multipart", {
+ status: 200,
+ statusText: "Och Aye",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
+ time: true
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[2]);
+
+ testParamsTab("urlencoded")
+ .then(() => {
+ RequestsMenu.selectedIndex = 1;
+ return testParamsTab("multipart");
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+
+ function testParamsTab(aType) {
+ let tab = document.querySelectorAll("#details-pane tab")[2];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
+
+ is(tab.getAttribute("selected"), "true",
+ "The params tab in the network details pane should be selected.");
+
+ function checkVisibility(aBox) {
+ is(tabpanel.querySelector("#request-params-box")
+ .hasAttribute("hidden"), !aBox.contains("params"),
+ "The request params box doesn't have the indended visibility.");
+ is(tabpanel.querySelector("#request-post-data-textarea-box")
+ .hasAttribute("hidden"), !aBox.contains("textarea"),
+ "The request post data textarea box doesn't have the indended visibility.");
+ }
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
+ "There should be 2 param scopes displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+ "The empty notice should not be displayed in this tabpanel.");
+
+ let queryScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+ let postScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
+
+ is(queryScope.querySelector(".name").getAttribute("value"),
+ L10N.getStr("paramsQueryString"),
+ "The query scope doesn't have the correct title.");
+
+ is(postScope.querySelector(".name").getAttribute("value"),
+ L10N.getStr(aType == "urlencoded" ? "paramsFormData" : "paramsPostPayload"),
+ "The post scope doesn't have the correct title.");
+
+ is(queryScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
+ "foo", "The first query param name was incorrect.");
+ is(queryScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
+ "\"bar\"", "The first query param value was incorrect.");
+ is(queryScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
+ "baz", "The second query param name was incorrect.");
+ is(queryScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
+ "\"42\"", "The second query param value was incorrect.");
+ is(queryScope.querySelectorAll(".variables-view-variable .name")[2].getAttribute("value"),
+ "type", "The third query param name was incorrect.");
+ is(queryScope.querySelectorAll(".variables-view-variable .value")[2].getAttribute("value"),
+ "\"" + aType + "\"", "The third query param value was incorrect.");
+
+ if (aType == "urlencoded") {
+ checkVisibility("params");
+
+ is(tabpanel.querySelectorAll(".variables-view-variable").length, 5,
+ "There should be 5 param values displayed in this tabpanel.");
+ is(queryScope.querySelectorAll(".variables-view-variable").length, 3,
+ "There should be 3 param values displayed in the query scope.");
+ is(postScope.querySelectorAll(".variables-view-variable").length, 2,
+ "There should be 2 param values displayed in the post scope.");
+
+ is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
+ "foo", "The first post param name was incorrect.");
+ is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
+ "\"bar\"", "The first post param value was incorrect.");
+ is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
+ "baz", "The second post param name was incorrect.");
+ is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
+ "\"123\"", "The second post param value was incorrect.");
+
+ return Promise.resolve();
+ }
+ else {
+ checkVisibility("params textarea");
+
+ is(tabpanel.querySelectorAll(".variables-view-variable").length, 3,
+ "There should be 3 param values displayed in this tabpanel.");
+ is(queryScope.querySelectorAll(".variables-view-variable").length, 3,
+ "There should be 3 param values displayed in the query scope.");
+ is(postScope.querySelectorAll(".variables-view-variable").length, 0,
+ "There should be 0 param values displayed in the post scope.");
+
+ return NetMonitorView.editor("#request-post-data-textarea").then((aEditor) => {
+ ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"text\""),
+ "The text shown in the source editor is incorrect (1.1).");
+ ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"email\""),
+ "The text shown in the source editor is incorrect (2.1).");
+ ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"range\""),
+ "The text shown in the source editor is incorrect (3.1).");
+ ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"Custom field\""),
+ "The text shown in the source editor is incorrect (4.1).");
+ ok(aEditor.getText().contains("Some text..."),
+ "The text shown in the source editor is incorrect (2.2).");
+ ok(aEditor.getText().contains("42"),
+ "The text shown in the source editor is incorrect (3.2).");
+ ok(aEditor.getText().contains("Extra data"),
+ "The text shown in the source editor is incorrect (4.2).");
+ is(aEditor.getMode(), SourceEditor.MODES.TEXT,
+ "The mode active in the source editor is incorrect.");
+ });
+ }
+ }
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_post-data-02.js b/browser/devtools/netmonitor/test/browser_net_post-data-02.js
new file mode 100644
index 000000000..b3d200a9e
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_post-data-02.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the POST requests display the correct information in the UI,
+ * even for raw payloads without attached content-type headers.
+ */
+
+function test() {
+ initNetMonitor(POST_RAW_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu, NetworkDetails } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+ NetworkDetails._params.lazyEmpty = false;
+
+ waitForNetworkEvents(aMonitor, 0, 1).then(() => {
+ NetMonitorView.toggleDetailsPane({ visible: true }, 2)
+ RequestsMenu.selectedIndex = 0;
+
+ let tab = document.querySelectorAll("#details-pane tab")[2];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
+
+ is(tab.getAttribute("selected"), "true",
+ "The params tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelector("#request-params-box")
+ .hasAttribute("hidden"), false,
+ "The request params box doesn't have the indended visibility.");
+ is(tabpanel.querySelector("#request-post-data-textarea-box")
+ .hasAttribute("hidden"), true,
+ "The request post data textarea box doesn't have the indended visibility.");
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
+ "There should be 1 param scopes displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+ "The empty notice should not be displayed in this tabpanel.");
+
+ let postScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+ is(postScope.querySelector(".name").getAttribute("value"),
+ L10N.getStr("paramsFormData"),
+ "The post scope doesn't have the correct title.");
+
+ is(postScope.querySelectorAll(".variables-view-variable").length, 2,
+ "There should be 2 param values displayed in the post scope.");
+ is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
+ "foo", "The first query param name was incorrect.");
+ is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
+ "\"bar\"", "The first query param value was incorrect.");
+ is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
+ "baz", "The second query param name was incorrect.");
+ is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
+ "\"123\"", "The second query param value was incorrect.");
+
+ teardown(aMonitor).then(finish);
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_prefs-and-l10n.js b/browser/devtools/netmonitor/test/browser_net_prefs-and-l10n.js
new file mode 100644
index 000000000..ce0f31ff7
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_prefs-and-l10n.js
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the preferences and localization objects work correctly.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ ok(aMonitor.panelWin.L10N,
+ "Should have a localization object available on the panel window.");
+ ok(aMonitor.panelWin.Prefs,
+ "Should have a preferences object available on the panel window.");
+
+ function testL10N() {
+ let { L10N } = aMonitor.panelWin;
+
+ ok(L10N.stringBundle,
+ "The localization object should have a string bundle available.");
+
+ let bundleName = "chrome://browser/locale/devtools/netmonitor.properties";
+ let stringBundle = Services.strings.createBundle(bundleName);
+
+ is(L10N.getStr("netmonitor.label"),
+ stringBundle.GetStringFromName("netmonitor.label"),
+ "The getStr() method didn't return the expected string.");
+
+ is(L10N.getFormatStr("networkMenu.totalMS", "foo"),
+ stringBundle.formatStringFromName("networkMenu.totalMS", ["foo"], 1),
+ "The getFormatStr() method didn't return the expected string.");
+ }
+
+ function testPrefs() {
+ let { Prefs } = aMonitor.panelWin;
+
+ is(Prefs.root, "devtools.netmonitor",
+ "The preferences object should have a correct root path.");
+
+ is(Prefs.networkDetailsWidth,
+ Services.prefs.getIntPref("devtools.netmonitor.panes-network-details-width"),
+ "Getting a pref should work correctly.");
+
+ let previousValue = Prefs.networkDetailsWidth;
+ let bogusValue = ~~(Math.random() * 100);
+ Prefs.networkDetailsWidth = bogusValue;
+ is(Prefs.networkDetailsWidth,
+ Services.prefs.getIntPref("devtools.netmonitor.panes-network-details-width"),
+ "Getting a pref after it has been modified should work correctly.");
+ is(Prefs.networkDetailsWidth, bogusValue,
+ "The pref wasn't updated correctly in the preferences object.");
+
+ Prefs.networkDetailsWidth = previousValue;
+ is(Prefs.networkDetailsWidth,
+ Services.prefs.getIntPref("devtools.netmonitor.panes-network-details-width"),
+ "Getting a pref after it has been modified again should work correctly.");
+ is(Prefs.networkDetailsWidth, previousValue,
+ "The pref wasn't updated correctly again in the preferences object.");
+ }
+
+ testL10N();
+ testPrefs();
+
+ teardown(aMonitor).then(finish);
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_prefs-reload.js b/browser/devtools/netmonitor/test/browser_net_prefs-reload.js
new file mode 100644
index 000000000..d5fd61c43
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_prefs-reload.js
@@ -0,0 +1,217 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the prefs that should survive across tool reloads work.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ // This test reopens the network monitor a bunch of times, for different
+ // hosts (bottom, side, window). This seems to be slow on debug builds.
+ requestLongerTimeout(3);
+
+ let prefsToCheck = {
+ networkDetailsWidth: {
+ newValue: ~~(Math.random() * 200 + 100),
+ validate: ($) => ~~$("#details-pane").getAttribute("width"),
+ modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("width", aValue)
+ },
+ networkDetailsHeight: {
+ newValue: ~~(Math.random() * 300 + 100),
+ validate: ($) => ~~$("#details-pane").getAttribute("height"),
+ modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("height", aValue)
+ },
+ /* add more prefs here... */
+ };
+
+ function storeFirstPrefValues() {
+ info("Caching initial pref values.");
+
+ for (let name in prefsToCheck) {
+ let currentValue = aMonitor.panelWin.Prefs[name];
+ prefsToCheck[name].firstValue = currentValue;
+ }
+ }
+
+ function validateFirstPrefValues() {
+ info("Validating current pref values to the UI elements.");
+
+ for (let name in prefsToCheck) {
+ let currentValue = aMonitor.panelWin.Prefs[name];
+ let firstValue = prefsToCheck[name].firstValue;
+ let validate = prefsToCheck[name].validate;
+
+ is(currentValue, firstValue,
+ "Pref " + name + " should be equal to first value: " + firstValue);
+ is(currentValue, validate(aMonitor.panelWin.$),
+ "Pref " + name + " should validate: " + currentValue);
+ }
+ }
+
+ function modifyFrontend() {
+ info("Modifying UI elements to the specified new values.");
+
+ for (let name in prefsToCheck) {
+ let currentValue = aMonitor.panelWin.Prefs[name];
+ let firstValue = prefsToCheck[name].firstValue;
+ let newValue = prefsToCheck[name].newValue;
+ let validate = prefsToCheck[name].validate;
+ let modifyFrontend = prefsToCheck[name].modifyFrontend;
+
+ modifyFrontend(aMonitor.panelWin.$, newValue);
+ info("Modified UI element affecting " + name + " to: " + newValue);
+
+ is(currentValue, firstValue,
+ "Pref " + name + " should still be equal to first value: " + firstValue);
+ isnot(currentValue, newValue,
+ "Pref " + name + " should't yet be equal to second value: " + newValue);
+ is(newValue, validate(aMonitor.panelWin.$),
+ "The UI element affecting " + name + " should validate: " + newValue);
+ }
+ }
+
+ function validateNewPrefValues() {
+ info("Invalidating old pref values to the modified UI elements.");
+
+ for (let name in prefsToCheck) {
+ let currentValue = aMonitor.panelWin.Prefs[name];
+ let firstValue = prefsToCheck[name].firstValue;
+ let newValue = prefsToCheck[name].newValue;
+ let validate = prefsToCheck[name].validate;
+
+ isnot(currentValue, firstValue,
+ "Pref " + name + " should't be equal to first value: " + firstValue);
+ is(currentValue, newValue,
+ "Pref " + name + " should now be equal to second value: " + newValue);
+ is(newValue, validate(aMonitor.panelWin.$),
+ "The UI element affecting " + name + " should validate: " + newValue);
+ }
+ }
+
+ function resetFrontend() {
+ info("Resetting UI elements to the cached initial pref values.");
+
+ for (let name in prefsToCheck) {
+ let currentValue = aMonitor.panelWin.Prefs[name];
+ let firstValue = prefsToCheck[name].firstValue;
+ let newValue = prefsToCheck[name].newValue;
+ let validate = prefsToCheck[name].validate;
+ let modifyFrontend = prefsToCheck[name].modifyFrontend;
+
+ modifyFrontend(aMonitor.panelWin.$, firstValue);
+ info("Modified UI element affecting " + name + " to: " + firstValue);
+
+ isnot(currentValue, firstValue,
+ "Pref " + name + " should't yet be equal to first value: " + firstValue);
+ is(currentValue, newValue,
+ "Pref " + name + " should still be equal to second value: " + newValue);
+ is(firstValue, validate(aMonitor.panelWin.$),
+ "The UI element affecting " + name + " should validate: " + firstValue);
+ }
+ }
+
+ function testBottom() {
+ info("Testing prefs reload for a bottom host.");
+ storeFirstPrefValues();
+
+ // Validate and modify while toolbox is on the bottom.
+ validateFirstPrefValues();
+ modifyFrontend();
+
+ return restartNetMonitor(aMonitor)
+ .then(([,, aNewMonitor]) => {
+ aMonitor = aNewMonitor;
+
+ // Revalidate and reset frontend while toolbox is on the bottom.
+ validateNewPrefValues();
+ resetFrontend();
+
+ return restartNetMonitor(aMonitor);
+ })
+ .then(([,, aNewMonitor]) => {
+ aMonitor = aNewMonitor;
+
+ // Revalidate.
+ validateFirstPrefValues();
+ });
+ }
+
+ function testSide() {
+ info("Moving toolbox to the side...");
+
+ return aMonitor._toolbox.switchHost(Toolbox.HostType.SIDE)
+ .then(() => {
+ info("Testing prefs reload for a side host.");
+ storeFirstPrefValues();
+
+ // Validate and modify frontend while toolbox is on the side.
+ validateFirstPrefValues();
+ modifyFrontend();
+
+ return restartNetMonitor(aMonitor);
+ })
+ .then(([,, aNewMonitor]) => {
+ aMonitor = aNewMonitor;
+
+ // Revalidate and reset frontend while toolbox is on the side.
+ validateNewPrefValues();
+ resetFrontend();
+
+ return restartNetMonitor(aMonitor);
+ })
+ .then(([,, aNewMonitor]) => {
+ aMonitor = aNewMonitor;
+
+ // Revalidate.
+ validateFirstPrefValues();
+ });
+ }
+
+ function testWindow() {
+ info("Moving toolbox into a window...");
+
+ return aMonitor._toolbox.switchHost(Toolbox.HostType.WINDOW)
+ .then(() => {
+ info("Testing prefs reload for a window host.");
+ storeFirstPrefValues();
+
+ // Validate and modify frontend while toolbox is in a window.
+ validateFirstPrefValues();
+ modifyFrontend();
+
+ return restartNetMonitor(aMonitor);
+ })
+ .then(([,, aNewMonitor]) => {
+ aMonitor = aNewMonitor;
+
+ // Revalidate and reset frontend while toolbox is in a window.
+ validateNewPrefValues();
+ resetFrontend();
+
+ return restartNetMonitor(aMonitor);
+ })
+ .then(([,, aNewMonitor]) => {
+ aMonitor = aNewMonitor;
+
+ // Revalidate.
+ validateFirstPrefValues();
+ });
+ }
+
+ function cleanupAndFinish() {
+ info("Moving toolbox back to the bottom...");
+
+ aMonitor._toolbox.switchHost(Toolbox.HostType.BOTTOM)
+ .then(() => teardown(aMonitor))
+ .then(finish);
+ }
+
+ testBottom()
+ .then(testSide)
+ .then(testWindow)
+ .then(cleanupAndFinish);
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_req-resp-bodies.js b/browser/devtools/netmonitor/test/browser_net_req-resp-bodies.js
new file mode 100644
index 000000000..1f1a55a16
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_req-resp-bodies.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if request and response body logging stays on after opening the console.
+ */
+
+function test() {
+ initNetMonitor(JSON_LONG_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ function verifyRequest(aOffset) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOffset),
+ "GET", CONTENT_TYPE_SJS + "?fmt=json-long", {
+ status: 200,
+ statusText: "OK",
+ type: "json",
+ fullMimeType: "text/json; charset=utf-8",
+ size: L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(85975/1024, 2)),
+ time: true
+ });
+ }
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequest(0);
+
+ aMonitor._toolbox.once("webconsole-selected", () => {
+ aMonitor._toolbox.once("netmonitor-selected", () => {
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ verifyRequest(1);
+ teardown(aMonitor).then(finish);
+ });
+
+ // Perform another batch of requests.
+ aDebuggee.performRequests();
+ });
+
+ // Reload debugee.
+ aDebuggee.location.reload();
+ });
+
+ // Switch back to the netmonitor.
+ aMonitor._toolbox.selectTool("netmonitor");
+ });
+
+ // Switch to the webconsole.
+ aMonitor._toolbox.selectTool("webconsole");
+ });
+
+ // Perform first batch of requests.
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_simple-init.js b/browser/devtools/netmonitor/test/browser_net_simple-init.js
new file mode 100644
index 000000000..9f444bb49
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_simple-init.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Simple check if the network monitor starts up and shuts down properly.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ is(aTab.linkedBrowser.contentWindow.wrappedJSObject.location, SIMPLE_URL,
+ "The current tab's location is the correct one.");
+ is(aDebuggee.location, SIMPLE_URL,
+ "The current debuggee's location is the correct one.");
+
+ function checkIfInitialized(aTag) {
+ info("Checking if initialization is ok (" + aTag + ").");
+
+ ok(aMonitor._view,
+ "The network monitor view object exists (" + aTag + ").");
+ ok(aMonitor._view._isInitialized,
+ "The network monitor view object exists and is initialized (" + aTag + ").");
+
+ ok(aMonitor._controller,
+ "The network monitor controller object exists (" + aTag + ").");
+ ok(aMonitor._controller._isInitialized,
+ "The network monitor controller object exists and is initialized (" + aTag + ").");
+
+ ok(aMonitor.isReady,
+ "The network monitor panel appears to be ready (" + aTag + ").");
+
+ ok(aMonitor._controller.client,
+ "There should be a client available at this point (" + aTag + ").");
+ ok(aMonitor._controller.tabClient,
+ "There should be a tabClient available at this point (" + aTag + ").");
+ ok(aMonitor._controller.webConsoleClient,
+ "There should be a webConsoleClient available at this point (" + aTag + ").");
+ }
+
+ function checkIfDestroyed(aTag) {
+ info("Checking if destruction is ok.");
+
+ ok(!aMonitor._controller.client,
+ "There shouldn't be a client available after destruction (" + aTag + ").");
+ ok(!aMonitor._controller.tabClient,
+ "There shouldn't be a tabClient available after destruction (" + aTag + ").");
+ ok(!aMonitor._controller.webConsoleClient,
+ "There shouldn't be a webConsoleClient available after destruction (" + aTag + ").");
+ }
+
+ executeSoon(() => {
+ checkIfInitialized(1);
+
+ aMonitor._controller.startupNetMonitor()
+ .then(() => {
+ info("Starting up again shouldn't do anything special.");
+ checkIfInitialized(2);
+ return aMonitor._controller.connect();
+ })
+ .then(() => {
+ info("Connecting again shouldn't do anything special.");
+ checkIfInitialized(3);
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ registerCleanupFunction(() => {
+ checkIfDestroyed(1);
+
+ aMonitor._controller.shutdownNetMonitor()
+ .then(() => {
+ info("Shutting down again shouldn't do anything special.");
+ checkIfDestroyed(2);
+ return aMonitor._controller.disconnect();
+ })
+ .then(() => {
+ info("Disconnecting again shouldn't do anything special.");
+ checkIfDestroyed(3);
+ });
+ });
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_simple-request-data.js b/browser/devtools/netmonitor/test/browser_net_simple-request-data.js
new file mode 100644
index 000000000..d9efa5eeb
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_simple-request-data.js
@@ -0,0 +1,237 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if requests render correct information in the menu UI.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_SJS).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1)
+ .then(() => teardown(aMonitor))
+ .then(finish);
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
+ is(RequestsMenu.selectedItem, null,
+ "There shouldn't be any selected item in the requests menu.");
+ is(RequestsMenu.itemCount, 1,
+ "The requests menu should not be empty after the first request.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should still be hidden after the first request.");
+
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+ let target = requestItem.target;
+
+ is(typeof requestItem.value, "string",
+ "The attached request id is incorrect.");
+ isnot(requestItem.value, "",
+ "The attached request id should not be empty.");
+
+ is(typeof requestItem.attachment.startedDeltaMillis, "number",
+ "The attached startedDeltaMillis is incorrect.");
+ is(requestItem.attachment.startedDeltaMillis, 0,
+ "The attached startedDeltaMillis should be zero.");
+
+ is(typeof requestItem.attachment.startedMillis, "number",
+ "The attached startedMillis is incorrect.");
+ isnot(requestItem.attachment.startedMillis, 0,
+ "The attached startedMillis should not be zero.");
+
+ is(requestItem.attachment.requestHeaders, undefined,
+ "The requestHeaders should not yet be set.");
+ is(requestItem.attachment.requestCookies, undefined,
+ "The requestCookies should not yet be set.");
+ is(requestItem.attachment.requestPostData, undefined,
+ "The requestPostData should not yet be set.");
+
+ is(requestItem.attachment.responseHeaders, undefined,
+ "The responseHeaders should not yet be set.");
+ is(requestItem.attachment.responseCookies, undefined,
+ "The responseCookies should not yet be set.");
+
+ is(requestItem.attachment.httpVersion, undefined,
+ "The httpVersion should not yet be set.");
+ is(requestItem.attachment.status, undefined,
+ "The status should not yet be set.");
+ is(requestItem.attachment.statusText, undefined,
+ "The statusText should not yet be set.");
+
+ is(requestItem.attachment.headersSize, undefined,
+ "The headersSize should not yet be set.");
+ is(requestItem.attachment.contentSize, undefined,
+ "The contentSize should not yet be set.");
+
+ is(requestItem.attachment.mimeType, undefined,
+ "The mimeType should not yet be set.");
+ is(requestItem.attachment.responseContent, undefined,
+ "The responseContent should not yet be set.");
+
+ is(requestItem.attachment.totalTime, undefined,
+ "The totalTime should not yet be set.");
+ is(requestItem.attachment.eventTimings, undefined,
+ "The eventTimings should not yet be set.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:RequestHeaders", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ ok(requestItem.attachment.requestHeaders,
+ "There should be a requestHeaders attachment available.");
+ ok(requestItem.attachment.requestHeaders.headers.length >= 6,
+ "The requestHeaders attachment has an incorrect |headers| property.");
+ // Can't test for an exact total number of headers, because it seems to
+ // vary across pgo/non-pgo builds.
+ isnot(requestItem.attachment.requestHeaders.headersSize, 0,
+ "The requestHeaders attachment 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(requestItem, "GET", SIMPLE_SJS);
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:RequestCookies", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ ok(requestItem.attachment.requestCookies,
+ "There should be a requestCookies attachment available.");
+ is(requestItem.attachment.requestCookies.cookies.length, 0,
+ "The requestCookies attachment has an incorrect |cookies| property.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:RequestPostData", () => {
+ ok(false, "Trap listener: this request doesn't have any post data.")
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:ResponseHeaders", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ ok(requestItem.attachment.responseHeaders,
+ "There should be a responseHeaders attachment available.");
+ is(requestItem.attachment.responseHeaders.headers.length, 6,
+ "The responseHeaders attachment has an incorrect |headers| property.");
+ is(requestItem.attachment.responseHeaders.headersSize, 173,
+ "The responseHeaders attachment has an incorrect |headersSize| property.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:ResponseCookies", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ ok(requestItem.attachment.responseCookies,
+ "There should be a responseCookies attachment available.");
+ is(requestItem.attachment.responseCookies.cookies.length, 0,
+ "The responseCookies attachment has an incorrect |cookies| property.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdating:ResponseStart", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ is(requestItem.attachment.httpVersion, "HTTP/1.1",
+ "The httpVersion attachment has an incorrect value.");
+ is(requestItem.attachment.status, "200",
+ "The status attachment has an incorrect value.");
+ is(requestItem.attachment.statusText, "Och Aye",
+ "The statusText attachment has an incorrect value.");
+ is(requestItem.attachment.headersSize, 173,
+ "The headersSize attachment has an incorrect value.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
+ status: "200",
+ statusText: "Och Aye"
+ });
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdating:ResponseContent", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ is(requestItem.attachment.contentSize, "12",
+ "The contentSize attachment has an incorrect value.");
+ is(requestItem.attachment.mimeType, "text/plain; charset=utf-8",
+ "The mimeType attachment has an incorrect value.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
+ });
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:ResponseContent", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ ok(requestItem.attachment.responseContent,
+ "There should be a responseContent attachment available.");
+ is(requestItem.attachment.responseContent.content.mimeType, "text/plain; charset=utf-8",
+ "The responseContent attachment has an incorrect |content.mimeType| property.");
+ is(requestItem.attachment.responseContent.content.text, "Hello world!",
+ "The responseContent attachment has an incorrect |content.text| property.");
+ is(requestItem.attachment.responseContent.content.size, 12,
+ "The responseContent attachment has an incorrect |content.size| property.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
+ });
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdating:EventTimings", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ is(typeof requestItem.attachment.totalTime, "number",
+ "The attached totalTime is incorrect.");
+ ok(requestItem.attachment.totalTime >= 0,
+ "The attached totalTime should be positive.");
+
+ is(typeof requestItem.attachment.endedMillis, "number",
+ "The attached endedMillis is incorrect.");
+ ok(requestItem.attachment.endedMillis >= 0,
+ "The attached endedMillis should be positive.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
+ time: true
+ });
+ });
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:EventTimings", () => {
+ let requestItem = RequestsMenu.getItemAtIndex(0);
+
+ ok(requestItem.attachment.eventTimings,
+ "There should be a eventTimings attachment available.");
+ is(typeof requestItem.attachment.eventTimings.timings.blocked, "number",
+ "The eventTimings attachment has an incorrect |timings.blocked| property.");
+ is(typeof requestItem.attachment.eventTimings.timings.dns, "number",
+ "The eventTimings attachment has an incorrect |timings.dns| property.");
+ is(typeof requestItem.attachment.eventTimings.timings.connect, "number",
+ "The eventTimings attachment has an incorrect |timings.connect| property.");
+ is(typeof requestItem.attachment.eventTimings.timings.send, "number",
+ "The eventTimings attachment has an incorrect |timings.send| property.");
+ is(typeof requestItem.attachment.eventTimings.timings.wait, "number",
+ "The eventTimings attachment has an incorrect |timings.wait| property.");
+ is(typeof requestItem.attachment.eventTimings.timings.receive, "number",
+ "The eventTimings attachment has an incorrect |timings.receive| property.");
+ is(typeof requestItem.attachment.eventTimings.totalTime, "number",
+ "The eventTimings attachment has an incorrect |totalTime| property.");
+
+ verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
+ time: true
+ });
+ });
+
+ aDebuggee.location.reload();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_simple-request-details.js b/browser/devtools/netmonitor/test/browser_net_simple-request-details.js
new file mode 100644
index 000000000..c43afb222
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_simple-request-details.js
@@ -0,0 +1,239 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if requests render correct information in the details UI.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_SJS).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu, NetworkDetails } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ is(RequestsMenu.selectedItem, null,
+ "There shouldn't be any selected item in the requests menu.");
+ is(RequestsMenu.itemCount, 1,
+ "The requests menu should not be empty after the first request.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should still be hidden after the first request.");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.getElementById("details-pane-toggle"));
+
+ isnot(RequestsMenu.selectedItem, null,
+ "There should be a selected item in the requests menu.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be selected in the requests menu.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should not be hidden after toggle button was pressed.");
+
+ testHeadersTab();
+ testCookiesTab();
+ testParamsTab();
+ testResponseTab()
+ .then(() => {
+ testTimingsTab();
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ function testHeadersTab() {
+ let tab = document.querySelectorAll("#details-pane tab")[0];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[0];
+
+ is(tab.getAttribute("selected"), "true",
+ "The headers tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelector("#headers-summary-url-value").getAttribute("value"),
+ SIMPLE_SJS, "The url summary value is incorrect.");
+ is(tabpanel.querySelector("#headers-summary-url-value").getAttribute("tooltiptext"),
+ SIMPLE_SJS, "The url summary tooltiptext is incorrect.");
+ is(tabpanel.querySelector("#headers-summary-method-value").getAttribute("value"),
+ "GET", "The method summary value is incorrect.");
+ is(tabpanel.querySelector("#headers-summary-status-circle").getAttribute("code"),
+ "200", "The status summary code is incorrect.");
+ is(tabpanel.querySelector("#headers-summary-status-value").getAttribute("value"),
+ "200 Och Aye", "The status summary value is incorrect.");
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
+ "There should be 2 header scopes displayed in this tabpanel.");
+ ok(tabpanel.querySelectorAll(".variable-or-property").length >= 12,
+ "There should be at least 12 header values displayed in this tabpanel.");
+ // Can't test for an exact total number of headers, because it seems to
+ // vary across pgo/non-pgo builds.
+
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+ "The empty notice should not be displayed in this tabpanel.");
+
+ let responseScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+ let requestScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
+
+ is(responseScope.querySelector(".name").getAttribute("value"),
+ L10N.getStr("responseHeaders") + " (" +
+ L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(173/1024, 3)) + ")",
+ "The response headers scope doesn't have the correct title.");
+
+ ok(requestScope.querySelector(".name").getAttribute("value").contains(
+ L10N.getStr("requestHeaders") + " (0"),
+ "The request headers scope doesn't have the correct title.");
+ // Can't test for full request headers title because the size may
+ // vary across platforms ("User-Agent" header differs). We're pretty
+ // sure it's smaller than 1 MB though, so it starts with a 0.
+
+ is(responseScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
+ "Connection", "The first response header name was incorrect.");
+ is(responseScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
+ "\"close\"", "The first response header value was incorrect.");
+ is(responseScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
+ "Content-Length", "The second response header name was incorrect.");
+ is(responseScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
+ "\"12\"", "The second response header value was incorrect.");
+ is(responseScope.querySelectorAll(".variables-view-variable .name")[2].getAttribute("value"),
+ "Content-Type", "The third response header name was incorrect.");
+ is(responseScope.querySelectorAll(".variables-view-variable .value")[2].getAttribute("value"),
+ "\"text/plain; charset=utf-8\"", "The third response header value was incorrect.");
+ is(responseScope.querySelectorAll(".variables-view-variable .name")[5].getAttribute("value"),
+ "foo-bar", "The last response header name was incorrect.");
+ is(responseScope.querySelectorAll(".variables-view-variable .value")[5].getAttribute("value"),
+ "\"baz\"", "The last response header value was incorrect.");
+
+ is(requestScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
+ "Host", "The first request header name was incorrect.");
+ is(requestScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
+ "\"example.com\"", "The first request header value was incorrect.");
+ is(requestScope.querySelectorAll(".variables-view-variable .name")[5].getAttribute("value"),
+ "Connection", "The penultimate request header name was incorrect.");
+ is(requestScope.querySelectorAll(".variables-view-variable .value")[5].getAttribute("value"),
+ "\"keep-alive\"", "The penultimate request header value was incorrect.");
+
+ let lastReqHeaderName = requestScope.querySelectorAll(".variables-view-variable .name")[6];
+ let lastReqHeaderValue = requestScope.querySelectorAll(".variables-view-variable .value")[6];
+ if (lastReqHeaderName && lastReqHeaderValue) {
+ is(lastReqHeaderName.getAttribute("value"),
+ "Cache-Control", "The last request header name was incorrect.");
+ is(lastReqHeaderValue.getAttribute("value"),
+ "\"max-age=0\"", "The last request header value was incorrect.");
+ } else {
+ info("The number of request headers was 6 instead of 7. Technically, " +
+ "not a failure in this particular test, but needs investigation.");
+ }
+ }
+
+ function testCookiesTab() {
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[1]);
+
+ let tab = document.querySelectorAll("#details-pane tab")[1];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[1];
+
+ is(tab.getAttribute("selected"), "true",
+ "The cookies tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 0,
+ "There should be no cookie scopes displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variable-or-property").length, 0,
+ "There should be no cookie values displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 1,
+ "The empty notice should be displayed in this tabpanel.");
+ }
+
+ function testParamsTab() {
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[2]);
+
+ let tab = document.querySelectorAll("#details-pane tab")[2];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
+
+ is(tab.getAttribute("selected"), "true",
+ "The params tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 0,
+ "There should be no param scopes displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variable-or-property").length, 0,
+ "There should be no param values displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 1,
+ "The empty notice should be displayed in this tabpanel.");
+
+ is(tabpanel.querySelector("#request-params-box")
+ .hasAttribute("hidden"), false,
+ "The request params box should not be hidden.");
+ is(tabpanel.querySelector("#request-post-data-textarea-box")
+ .hasAttribute("hidden"), true,
+ "The request post data textarea box should be hidden.");
+ }
+
+ function testResponseTab() {
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[3]);
+
+ let tab = document.querySelectorAll("#details-pane tab")[3];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
+
+ is(tab.getAttribute("selected"), "true",
+ "The response tab in the network details pane should be selected.");
+
+ is(tabpanel.querySelector("#response-content-info-header")
+ .hasAttribute("hidden"), true,
+ "The response info header should be hidden.");
+ is(tabpanel.querySelector("#response-content-json-box")
+ .hasAttribute("hidden"), true,
+ "The response content json box should be hidden.");
+ is(tabpanel.querySelector("#response-content-textarea-box")
+ .hasAttribute("hidden"), false,
+ "The response content textarea box should not be hidden.");
+ is(tabpanel.querySelector("#response-content-image-box")
+ .hasAttribute("hidden"), true,
+ "The response content image box should be hidden.");
+
+ return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+ is(aEditor.getText(), "Hello world!",
+ "The text shown in the source editor is incorrect.");
+ is(aEditor.getMode(), SourceEditor.MODES.TEXT,
+ "The mode active in the source editor is incorrect.");
+ });
+ }
+
+ function testTimingsTab() {
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[4]);
+
+ let tab = document.querySelectorAll("#details-pane tab")[4];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[4];
+
+ is(tab.getAttribute("selected"), "true",
+ "The timings tab in the network details pane should be selected.");
+
+ ok(tabpanel.querySelector("#timings-summary-blocked .requests-menu-timings-total")
+ .getAttribute("value").match(/[0-9]+/),
+ "The blocked timing info does not appear to be correct.");
+
+ ok(tabpanel.querySelector("#timings-summary-dns .requests-menu-timings-total")
+ .getAttribute("value").match(/[0-9]+/),
+ "The dns timing info does not appear to be correct.");
+
+ ok(tabpanel.querySelector("#timings-summary-connect .requests-menu-timings-total")
+ .getAttribute("value").match(/[0-9]+/),
+ "The connect timing info does not appear to be correct.");
+
+ ok(tabpanel.querySelector("#timings-summary-send .requests-menu-timings-total")
+ .getAttribute("value").match(/[0-9]+/),
+ "The send timing info does not appear to be correct.");
+
+ ok(tabpanel.querySelector("#timings-summary-wait .requests-menu-timings-total")
+ .getAttribute("value").match(/[0-9]+/),
+ "The wait timing info does not appear to be correct.");
+
+ ok(tabpanel.querySelector("#timings-summary-receive .requests-menu-timings-total")
+ .getAttribute("value").match(/[0-9]+/),
+ "The receive timing info does not appear to be correct.");
+ }
+
+ aDebuggee.location.reload();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_simple-request.js b/browser/devtools/netmonitor/test/browser_net_simple-request.js
new file mode 100644
index 000000000..2544faf6b
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_simple-request.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if requests are handled correctly.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("disabled"), true,
+ "The pane toggle button should be disabled when the frontend is opened.");
+ is(document.querySelector("#requests-menu-empty-notice")
+ .hasAttribute("hidden"), false,
+ "An empty notice should be displayed when the frontend is opened.");
+ is(RequestsMenu.itemCount, 0,
+ "The requests menu should be empty when the frontend is opened.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should be hidden when the frontend is opened.");
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("disabled"), false,
+ "The pane toggle button should be enabled after the first request.");
+ is(document.querySelector("#requests-menu-empty-notice")
+ .hasAttribute("hidden"), true,
+ "The empty notice should be hidden after the first request.");
+ is(RequestsMenu.itemCount, 1,
+ "The requests menu should not be empty after the first request.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should still be hidden after the first request.");
+
+ aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
+ is(document.querySelector("#details-pane-toggle")
+ .hasAttribute("disabled"), false,
+ "The pane toggle button should be still be enabled after a reload.");
+ is(document.querySelector("#requests-menu-empty-notice")
+ .hasAttribute("hidden"), true,
+ "The empty notice should be still hidden after a reload.");
+ is(RequestsMenu.itemCount, 1,
+ "The requests menu should not be empty after a reload.");
+ is(NetMonitorView.detailsPaneHidden, true,
+ "The details pane should still be hidden after a reload.");
+
+ teardown(aMonitor).then(finish);
+ });
+
+ aDebuggee.location.reload();
+ });
+
+ aDebuggee.location.reload();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_sort-01.js b/browser/devtools/netmonitor/test/browser_net_sort-01.js
new file mode 100644
index 000000000..a57a5326d
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_sort-01.js
@@ -0,0 +1,248 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if the sorting mechanism works correctly.
+ */
+
+function test() {
+ initNetMonitor(STATUS_CODES_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 5).then(() => {
+ testContents([0, 1, 2, 3, 4])
+ .then(() => {
+ info("Testing swap(0, 0)");
+ RequestsMenu.swapItemsAtIndices(0, 0);
+ RequestsMenu.refreshZebra();
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing swap(0, 1)");
+ RequestsMenu.swapItemsAtIndices(0, 1);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 0, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing swap(0, 2)");
+ RequestsMenu.swapItemsAtIndices(0, 2);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 2, 0, 3, 4]);
+ })
+ .then(() => {
+ info("Testing swap(0, 3)");
+ RequestsMenu.swapItemsAtIndices(0, 3);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 2, 3, 0, 4]);
+ })
+ .then(() => {
+ info("Testing swap(0, 4)");
+ RequestsMenu.swapItemsAtIndices(0, 4);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 2, 3, 4, 0]);
+ })
+ .then(() => {
+ info("Testing swap(1, 0)");
+ RequestsMenu.swapItemsAtIndices(1, 0);
+ RequestsMenu.refreshZebra();
+ return testContents([0, 2, 3, 4, 1]);
+ })
+ .then(() => {
+ info("Testing swap(1, 1)");
+ RequestsMenu.swapItemsAtIndices(1, 1);
+ RequestsMenu.refreshZebra();
+ return testContents([0, 2, 3, 4, 1]);
+ })
+ .then(() => {
+ info("Testing swap(1, 2)");
+ RequestsMenu.swapItemsAtIndices(1, 2);
+ RequestsMenu.refreshZebra();
+ return testContents([0, 1, 3, 4, 2]);
+ })
+ .then(() => {
+ info("Testing swap(1, 3)");
+ RequestsMenu.swapItemsAtIndices(1, 3);
+ RequestsMenu.refreshZebra();
+ return testContents([0, 3, 1, 4, 2]);
+ })
+ .then(() => {
+ info("Testing swap(1, 4)");
+ RequestsMenu.swapItemsAtIndices(1, 4);
+ RequestsMenu.refreshZebra();
+ return testContents([0, 3, 4, 1, 2]);
+ })
+ .then(() => {
+ info("Testing swap(2, 0)");
+ RequestsMenu.swapItemsAtIndices(2, 0);
+ RequestsMenu.refreshZebra();
+ return testContents([2, 3, 4, 1, 0]);
+ })
+ .then(() => {
+ info("Testing swap(2, 1)");
+ RequestsMenu.swapItemsAtIndices(2, 1);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 3, 4, 2, 0]);
+ })
+ .then(() => {
+ info("Testing swap(2, 2)");
+ RequestsMenu.swapItemsAtIndices(2, 2);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 3, 4, 2, 0]);
+ })
+ .then(() => {
+ info("Testing swap(2, 3)");
+ RequestsMenu.swapItemsAtIndices(2, 3);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 2, 4, 3, 0]);
+ })
+ .then(() => {
+ info("Testing swap(2, 4)");
+ RequestsMenu.swapItemsAtIndices(2, 4);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 4, 2, 3, 0]);
+ })
+ .then(() => {
+ info("Testing swap(3, 0)");
+ RequestsMenu.swapItemsAtIndices(3, 0);
+ RequestsMenu.refreshZebra();
+ return testContents([1, 4, 2, 0, 3]);
+ })
+ .then(() => {
+ info("Testing swap(3, 1)");
+ RequestsMenu.swapItemsAtIndices(3, 1);
+ RequestsMenu.refreshZebra();
+ return testContents([3, 4, 2, 0, 1]);
+ })
+ .then(() => {
+ info("Testing swap(3, 2)");
+ RequestsMenu.swapItemsAtIndices(3, 2);
+ RequestsMenu.refreshZebra();
+ return testContents([2, 4, 3, 0, 1]);
+ })
+ .then(() => {
+ info("Testing swap(3, 3)");
+ RequestsMenu.swapItemsAtIndices(3, 3);
+ RequestsMenu.refreshZebra();
+ return testContents([2, 4, 3, 0, 1]);
+ })
+ .then(() => {
+ info("Testing swap(3, 4)");
+ RequestsMenu.swapItemsAtIndices(3, 4);
+ RequestsMenu.refreshZebra();
+ return testContents([2, 3, 4, 0, 1]);
+ })
+ .then(() => {
+ info("Testing swap(4, 0)");
+ RequestsMenu.swapItemsAtIndices(4, 0);
+ RequestsMenu.refreshZebra();
+ return testContents([2, 3, 0, 4, 1]);
+ })
+ .then(() => {
+ info("Testing swap(4, 1)");
+ RequestsMenu.swapItemsAtIndices(4, 1);
+ RequestsMenu.refreshZebra();
+ return testContents([2, 3, 0, 1, 4]);
+ })
+ .then(() => {
+ info("Testing swap(4, 2)");
+ RequestsMenu.swapItemsAtIndices(4, 2);
+ RequestsMenu.refreshZebra();
+ return testContents([4, 3, 0, 1, 2]);
+ })
+ .then(() => {
+ info("Testing swap(4, 3)");
+ RequestsMenu.swapItemsAtIndices(4, 3);
+ RequestsMenu.refreshZebra();
+ return testContents([3, 4, 0, 1, 2]);
+ })
+ .then(() => {
+ info("Testing swap(4, 4)");
+ RequestsMenu.swapItemsAtIndices(4, 4);
+ RequestsMenu.refreshZebra();
+ return testContents([3, 4, 0, 1, 2]);
+ })
+ .then(() => {
+ info("Clearing sort.");
+ RequestsMenu.sortBy();
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ function testContents([a, b, c, d, e]) {
+ is(RequestsMenu.orderedItems.length, 5,
+ "There should be a total of 5 items in the requests menu.");
+ is(RequestsMenu.visibleItems.length, 5,
+ "There should be a total of 5 visbile items in the requests menu.");
+
+ is(RequestsMenu.getItemAtIndex(0), RequestsMenu.orderedItems[0],
+ "The requests menu items aren't ordered correctly. First item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(1), RequestsMenu.orderedItems[1],
+ "The requests menu items aren't ordered correctly. Second item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(2), RequestsMenu.orderedItems[2],
+ "The requests menu items aren't ordered correctly. Third item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(3), RequestsMenu.orderedItems[3],
+ "The requests menu items aren't ordered correctly. Fourth item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(4), RequestsMenu.orderedItems[4],
+ "The requests menu items aren't ordered correctly. Fifth item is misplaced.");
+
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(a),
+ "GET", STATUS_CODES_SJS + "?sts=100", {
+ status: 101,
+ statusText: "Switching Protocols",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(b),
+ "GET", STATUS_CODES_SJS + "?sts=200", {
+ status: 202,
+ statusText: "Created",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(c),
+ "GET", STATUS_CODES_SJS + "?sts=300", {
+ status: 303,
+ statusText: "See Other",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(d),
+ "GET", STATUS_CODES_SJS + "?sts=400", {
+ status: 404,
+ statusText: "Not Found",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(e),
+ "GET", STATUS_CODES_SJS + "?sts=500", {
+ status: 501,
+ statusText: "Not Implemented",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+
+ return Promise.resolve(null);
+ }
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_sort-02.js b/browser/devtools/netmonitor/test/browser_net_sort-02.js
new file mode 100644
index 000000000..b2e9cfe46
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_sort-02.js
@@ -0,0 +1,249 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if sorting columns in the network table works correctly.
+ */
+
+function test() {
+ initNetMonitor(SORTING_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ // It seems that this test may be slow on debug builds. This could be because
+ // of the heavy dom manipulation associated with sorting.
+ requestLongerTimeout(2);
+
+ let { $, L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 5).then(() => {
+ EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
+
+ isnot(RequestsMenu.selectedItem, null,
+ "There should be a selected item in the requests menu.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be selected in the requests menu.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should not be hidden after toggle button was pressed.");
+
+ testHeaders();
+ testContents([0, 2, 4, 3, 1])
+ .then(() => {
+ info("Testing status sort, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
+ testHeaders("status", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing status sort, descending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
+ testHeaders("status", "descending");
+ return testContents([4, 3, 2, 1, 0]);
+ })
+ .then(() => {
+ info("Testing status sort, ascending. Checking sort loops correctly.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
+ testHeaders("status", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing method sort, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-method-button"));
+ testHeaders("method", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing method sort, descending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-method-button"));
+ testHeaders("method", "descending");
+ return testContents([4, 3, 2, 1, 0]);
+ })
+ .then(() => {
+ info("Testing method sort, ascending. Checking sort loops correctly.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-method-button"));
+ testHeaders("method", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing file sort, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-file-button"));
+ testHeaders("file", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing file sort, descending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-file-button"));
+ testHeaders("file", "descending");
+ return testContents([4, 3, 2, 1, 0]);
+ })
+ .then(() => {
+ info("Testing file sort, ascending. Checking sort loops correctly.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-file-button"));
+ testHeaders("file", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing type sort, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-type-button"));
+ testHeaders("type", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing type sort, descending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-type-button"));
+ testHeaders("type", "descending");
+ return testContents([4, 3, 2, 1, 0]);
+ })
+ .then(() => {
+ info("Testing type sort, ascending. Checking sort loops correctly.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-type-button"));
+ testHeaders("type", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing size sort, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
+ testHeaders("size", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing size sort, descending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
+ testHeaders("size", "descending");
+ return testContents([4, 3, 2, 1, 0]);
+ })
+ .then(() => {
+ info("Testing size sort, ascending. Checking sort loops correctly.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
+ testHeaders("size", "ascending");
+ return testContents([0, 1, 2, 3, 4]);
+ })
+ .then(() => {
+ info("Testing waterfall sort, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-waterfall-button"));
+ testHeaders("waterfall", "ascending");
+ return testContents([0, 2, 4, 3, 1]);
+ })
+ .then(() => {
+ info("Testing waterfall sort, descending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-waterfall-button"));
+ testHeaders("waterfall", "descending");
+ return testContents([4, 2, 0, 1, 3]);
+ })
+ .then(() => {
+ info("Testing waterfall sort, ascending. Checking sort loops correctly.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-waterfall-button"));
+ testHeaders("waterfall", "ascending");
+ return testContents([0, 2, 4, 3, 1]);
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ function testHeaders(aSortType, aDirection) {
+ let doc = aMonitor.panelWin.document;
+ let target = doc.querySelector("#requests-menu-" + aSortType + "-button");
+ let headers = doc.querySelectorAll(".requests-menu-header-button");
+
+ for (let header of headers) {
+ if (header != target) {
+ is(header.hasAttribute("sorted"), false,
+ "The " + header.id + " header should not have a 'sorted' attribute.");
+ is(header.hasAttribute("tooltiptext"), false,
+ "The " + header.id + " header should not have a 'tooltiptext' attribute.");
+ } else {
+ is(header.getAttribute("sorted"), aDirection,
+ "The " + header.id + " header has an incorrect 'sorted' attribute.");
+ is(header.getAttribute("tooltiptext"), aDirection == "ascending"
+ ? L10N.getStr("networkMenu.sortedAsc")
+ : L10N.getStr("networkMenu.sortedDesc"),
+ "The " + header.id + " has an incorrect 'tooltiptext' attribute.");
+ }
+ }
+ }
+
+ function testContents([a, b, c, d, e]) {
+ isnot(RequestsMenu.selectedItem, null,
+ "There should still be a selected item after sorting.");
+ is(RequestsMenu.selectedIndex, a,
+ "The first item should be still selected after sorting.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should still be visible after sorting.");
+
+ is(RequestsMenu.orderedItems.length, 5,
+ "There should be a total of 5 items in the requests menu.");
+ is(RequestsMenu.visibleItems.length, 5,
+ "There should be a total of 5 visbile items in the requests menu.");
+
+ is(RequestsMenu.getItemAtIndex(0), RequestsMenu.orderedItems[0],
+ "The requests menu items aren't ordered correctly. First item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(1), RequestsMenu.orderedItems[1],
+ "The requests menu items aren't ordered correctly. Second item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(2), RequestsMenu.orderedItems[2],
+ "The requests menu items aren't ordered correctly. Third item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(3), RequestsMenu.orderedItems[3],
+ "The requests menu items aren't ordered correctly. Fourth item is misplaced.");
+ is(RequestsMenu.getItemAtIndex(4), RequestsMenu.orderedItems[4],
+ "The requests menu items aren't ordered correctly. Fifth item is misplaced.");
+
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(a),
+ "GET1", SORTING_SJS + "?index=1", {
+ fuzzyUrl: true,
+ status: 101,
+ statusText: "Meh",
+ type: "1",
+ fullMimeType: "text/1",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(b),
+ "GET2", SORTING_SJS + "?index=2", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "Meh",
+ type: "2",
+ fullMimeType: "text/2",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(c),
+ "GET3", SORTING_SJS + "?index=3", {
+ fuzzyUrl: true,
+ status: 300,
+ statusText: "Meh",
+ type: "3",
+ fullMimeType: "text/3",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(d),
+ "GET4", SORTING_SJS + "?index=4", {
+ fuzzyUrl: true,
+ status: 400,
+ statusText: "Meh",
+ type: "4",
+ fullMimeType: "text/4",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
+ time: true
+ });
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(e),
+ "GET5", SORTING_SJS + "?index=5", {
+ fuzzyUrl: true,
+ status: 500,
+ statusText: "Meh",
+ type: "5",
+ fullMimeType: "text/5",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
+ time: true
+ });
+
+ return Promise.resolve(null);
+ }
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_sort-03.js b/browser/devtools/netmonitor/test/browser_net_sort-03.js
new file mode 100644
index 000000000..c6f9214bc
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_sort-03.js
@@ -0,0 +1,177 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if sorting columns in the network table works correctly with new requests.
+ */
+
+function test() {
+ initNetMonitor(SORTING_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ // It seems that this test may be slow on debug builds. This could be because
+ // of the heavy dom manipulation associated with sorting.
+ requestLongerTimeout(2);
+
+ let { $, L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ waitForNetworkEvents(aMonitor, 5).then(() => {
+ EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
+
+ isnot(RequestsMenu.selectedItem, null,
+ "There should be a selected item in the requests menu.");
+ is(RequestsMenu.selectedIndex, 0,
+ "The first item should be selected in the requests menu.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should not be hidden after toggle button was pressed.");
+
+ testHeaders();
+ testContents([0, 2, 4, 3, 1], 0)
+ .then(() => {
+ info("Testing status sort, ascending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
+ testHeaders("status", "ascending");
+ return testContents([0, 1, 2, 3, 4], 0);
+ })
+ .then(() => {
+ info("Performing more requests.");
+ aDebuggee.performRequests();
+ return waitForNetworkEvents(aMonitor, 5);
+ })
+ .then(() => {
+ info("Testing status sort again, ascending.");
+ testHeaders("status", "ascending");
+ return testContents([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0);
+ })
+ .then(() => {
+ info("Testing status sort, descending.");
+ EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-status-button"));
+ testHeaders("status", "descending");
+ return testContents([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 9);
+ })
+ .then(() => {
+ info("Performing more requests.");
+ aDebuggee.performRequests();
+ return waitForNetworkEvents(aMonitor, 5);
+ })
+ .then(() => {
+ info("Testing status sort again, descending.");
+ testHeaders("status", "descending");
+ return testContents([14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 12);
+ })
+ .then(() => {
+ return teardown(aMonitor);
+ })
+ .then(finish);
+ });
+
+ function testHeaders(aSortType, aDirection) {
+ let doc = aMonitor.panelWin.document;
+ let target = doc.querySelector("#requests-menu-" + aSortType + "-button");
+ let headers = doc.querySelectorAll(".requests-menu-header-button");
+
+ for (let header of headers) {
+ if (header != target) {
+ is(header.hasAttribute("sorted"), false,
+ "The " + header.id + " header should not have a 'sorted' attribute.");
+ is(header.hasAttribute("tooltiptext"), false,
+ "The " + header.id + " header should not have a 'tooltiptext' attribute.");
+ } else {
+ is(header.getAttribute("sorted"), aDirection,
+ "The " + header.id + " header has an incorrect 'sorted' attribute.");
+ is(header.getAttribute("tooltiptext"), aDirection == "ascending"
+ ? L10N.getStr("networkMenu.sortedAsc")
+ : L10N.getStr("networkMenu.sortedDesc"),
+ "The " + header.id + " has an incorrect 'tooltiptext' attribute.");
+ }
+ }
+ }
+
+ function testContents(aOrder, aSelection) {
+ isnot(RequestsMenu.selectedItem, null,
+ "There should still be a selected item after sorting.");
+ is(RequestsMenu.selectedIndex, aSelection,
+ "The first item should be still selected after sorting.");
+ is(NetMonitorView.detailsPaneHidden, false,
+ "The details pane should still be visible after sorting.");
+
+ is(RequestsMenu.orderedItems.length, aOrder.length,
+ "There should be a specific number of items in the requests menu.");
+ is(RequestsMenu.visibleItems.length, aOrder.length,
+ "There should be a specific number of visbile items in the requests menu.");
+
+ for (let i = 0; i < aOrder.length; i++) {
+ is(RequestsMenu.getItemAtIndex(i), RequestsMenu.orderedItems[i],
+ "The requests menu items aren't ordered correctly. Misplaced item " + i + ".");
+ }
+
+ for (let i = 0, len = aOrder.length / 5; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i]),
+ "GET1", SORTING_SJS + "?index=1", {
+ fuzzyUrl: true,
+ status: 101,
+ statusText: "Meh",
+ type: "1",
+ fullMimeType: "text/1",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
+ time: true
+ });
+ }
+ for (let i = 0, len = aOrder.length / 5; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len]),
+ "GET2", SORTING_SJS + "?index=2", {
+ fuzzyUrl: true,
+ status: 200,
+ statusText: "Meh",
+ type: "2",
+ fullMimeType: "text/2",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
+ time: true
+ });
+ }
+ for (let i = 0, len = aOrder.length / 5; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 2]),
+ "GET3", SORTING_SJS + "?index=3", {
+ fuzzyUrl: true,
+ status: 300,
+ statusText: "Meh",
+ type: "3",
+ fullMimeType: "text/3",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ }
+ for (let i = 0, len = aOrder.length / 5; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 3]),
+ "GET4", SORTING_SJS + "?index=4", {
+ fuzzyUrl: true,
+ status: 400,
+ statusText: "Meh",
+ type: "4",
+ fullMimeType: "text/4",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
+ time: true
+ });
+ }
+ for (let i = 0, len = aOrder.length / 5; i < len; i++) {
+ verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 4]),
+ "GET5", SORTING_SJS + "?index=5", {
+ fuzzyUrl: true,
+ status: 500,
+ statusText: "Meh",
+ type: "5",
+ fullMimeType: "text/5",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
+ time: true
+ });
+ }
+
+ return Promise.resolve(null);
+ }
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_status-codes.js b/browser/devtools/netmonitor/test/browser_net_status-codes.js
new file mode 100644
index 000000000..0e62f8071
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_status-codes.js
@@ -0,0 +1,155 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if requests display the correct status code and text in the UI.
+ */
+
+function test() {
+ initNetMonitor(STATUS_CODES_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu, NetworkDetails } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+ NetworkDetails._params.lazyEmpty = false;
+
+ waitForNetworkEvents(aMonitor, 5).then(() => {
+ let requestItems = [];
+
+ verifyRequestItemTarget(requestItems[0] = RequestsMenu.getItemAtIndex(0),
+ "GET", STATUS_CODES_SJS + "?sts=100", {
+ status: 101,
+ statusText: "Switching Protocols",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
+ time: true
+ });
+ verifyRequestItemTarget(requestItems[1] = RequestsMenu.getItemAtIndex(1),
+ "GET", STATUS_CODES_SJS + "?sts=200", {
+ status: 202,
+ statusText: "Created",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ verifyRequestItemTarget(requestItems[2] = RequestsMenu.getItemAtIndex(2),
+ "GET", STATUS_CODES_SJS + "?sts=300", {
+ status: 303,
+ statusText: "See Other",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
+ time: true
+ });
+ verifyRequestItemTarget(requestItems[3] = RequestsMenu.getItemAtIndex(3),
+ "GET", STATUS_CODES_SJS + "?sts=400", {
+ status: 404,
+ statusText: "Not Found",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+ verifyRequestItemTarget(requestItems[4] = RequestsMenu.getItemAtIndex(4),
+ "GET", STATUS_CODES_SJS + "?sts=500", {
+ status: 501,
+ statusText: "Not Implemented",
+ type: "plain",
+ fullMimeType: "text/plain; charset=utf-8",
+ size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
+ time: true
+ });
+
+ // Test summaries...
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[0]);
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[0].target);
+ testSummary("GET", STATUS_CODES_SJS + "?sts=100", "101", "Switching Protocols");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[1].target);
+ testSummary("GET", STATUS_CODES_SJS + "?sts=200", "202", "Created");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[2].target);
+ testSummary("GET", STATUS_CODES_SJS + "?sts=300", "303", "See Other");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[3].target);
+ testSummary("GET", STATUS_CODES_SJS + "?sts=400", "404", "Not Found");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[4].target);
+ testSummary("GET", STATUS_CODES_SJS + "?sts=500", "501", "Not Implemented");
+
+ // Test params...
+ EventUtils.sendMouseEvent({ type: "mousedown" },
+ document.querySelectorAll("#details-pane tab")[2]);
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[0].target);
+ testParamsTab("\"100\"");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[1].target);
+ testParamsTab("\"200\"");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[2].target);
+ testParamsTab("\"300\"");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[3].target);
+ testParamsTab("\"400\"");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[4].target);
+ testParamsTab("\"500\"");
+
+ // We're done here.
+ teardown(aMonitor).then(finish);
+
+ function testSummary(aMethod, aUrl, aStatus, aStatusText) {
+ let tab = document.querySelectorAll("#details-pane tab")[0];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[0];
+
+ is(tabpanel.querySelector("#headers-summary-url-value").getAttribute("value"),
+ aUrl, "The url summary value is incorrect.");
+ is(tabpanel.querySelector("#headers-summary-method-value").getAttribute("value"),
+ aMethod, "The method summary value is incorrect.");
+ is(tabpanel.querySelector("#headers-summary-status-circle").getAttribute("code"),
+ aStatus, "The status summary code is incorrect.");
+ is(tabpanel.querySelector("#headers-summary-status-value").getAttribute("value"),
+ aStatus + " " + aStatusText, "The status summary value is incorrect.");
+ }
+
+ function testParamsTab(aStatusParamValue) {
+ let tab = document.querySelectorAll("#details-pane tab")[2];
+ let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
+
+ is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
+ "There should be 1 param scope displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variable-or-property").length, 1,
+ "There should be 1 param value displayed in this tabpanel.");
+ is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+ "The empty notice should not be displayed in this tabpanel.");
+
+ let paramsScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+
+ is(paramsScope.querySelector(".name").getAttribute("value"),
+ L10N.getStr("paramsQueryString"),
+ "The params scope doesn't have the correct title.");
+
+ is(paramsScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
+ "sts", "The param name was incorrect.");
+ is(paramsScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
+ aStatusParamValue, "The param value was incorrect.");
+
+ is(tabpanel.querySelector("#request-params-box")
+ .hasAttribute("hidden"), false,
+ "The request params box should not be hidden.");
+ is(tabpanel.querySelector("#request-post-data-textarea-box")
+ .hasAttribute("hidden"), true,
+ "The request post data textarea box should be hidden.");
+ }
+ });
+
+ aDebuggee.performRequests();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/browser_net_timeline_ticks.js b/browser/devtools/netmonitor/test/browser_net_timeline_ticks.js
new file mode 100644
index 000000000..a56bff992
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_timeline_ticks.js
@@ -0,0 +1,135 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if timeline correctly displays interval divisions.
+ */
+
+function test() {
+ initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+ info("Starting test... ");
+
+ let { document, L10N, NetMonitorView } = aMonitor.panelWin;
+ let { RequestsMenu } = NetMonitorView;
+
+ RequestsMenu.lazyUpdate = false;
+
+ ok(document.querySelector("#requests-menu-waterfall-label"),
+ "An timeline label should be displayed when the frontend is opened.");
+ ok(document.querySelectorAll(".requests-menu-timings-division").length == 0,
+ "No tick labels should be displayed when the frontend is opened.");
+
+ ok(!RequestsMenu._canvas,
+ "No canvas should be created when the frontend is opened.");
+ ok(!RequestsMenu._ctx,
+ "No 2d context should be created when the frontend is opened.");
+
+ waitForNetworkEvents(aMonitor, 1).then(() => {
+ ok(!document.querySelector("#requests-menu-waterfall-label"),
+ "The timeline label should be hidden after the first request.");
+ ok(document.querySelectorAll(".requests-menu-timings-division").length >= 3,
+ "There should be at least 3 tick labels in the network requests header.");
+
+ is(document.querySelectorAll(".requests-menu-timings-division")[0]
+ .getAttribute("value"), L10N.getFormatStr("networkMenu.divisionMS", 0),
+ "The first tick label has an incorrect value");
+ is(document.querySelectorAll(".requests-menu-timings-division")[1]
+ .getAttribute("value"), L10N.getFormatStr("networkMenu.divisionMS", 80),
+ "The second tick label has an incorrect value");
+ is(document.querySelectorAll(".requests-menu-timings-division")[2]
+ .getAttribute("value"), L10N.getFormatStr("networkMenu.divisionMS", 160),
+ "The third tick label has an incorrect value");
+
+ is(document.querySelectorAll(".requests-menu-timings-division")[0]
+ .style.transform, "translateX(0px)",
+ "The first tick label has an incorrect translation");
+ is(document.querySelectorAll(".requests-menu-timings-division")[1]
+ .style.transform, "translateX(80px)",
+ "The second tick label has an incorrect translation");
+ is(document.querySelectorAll(".requests-menu-timings-division")[2]
+ .style.transform, "translateX(160px)",
+ "The third tick label has an incorrect translation");
+
+ ok(RequestsMenu._canvas,
+ "A canvas should be created after the first request.");
+ ok(RequestsMenu._ctx,
+ "A 2d context should be created after the first request.");
+
+ let imageData = RequestsMenu._ctx.getImageData(0, 0, 161, 1);
+ ok(imageData, "The image data should have been created.");
+
+ let data = imageData.data;
+ ok(data, "The image data should contain a pixel array.");
+
+ ok( hasPixelAt(0), "The tick at 0 is should not be empty.");
+ ok(!hasPixelAt(1), "The tick at 1 is should be empty.");
+ ok(!hasPixelAt(19), "The tick at 19 is should be empty.");
+ ok( hasPixelAt(20), "The tick at 20 is should not be empty.");
+ ok(!hasPixelAt(21), "The tick at 21 is should be empty.");
+ ok(!hasPixelAt(39), "The tick at 39 is should be empty.");
+ ok( hasPixelAt(40), "The tick at 40 is should not be empty.");
+ ok(!hasPixelAt(41), "The tick at 41 is should be empty.");
+ ok(!hasPixelAt(59), "The tick at 59 is should be empty.");
+ ok( hasPixelAt(60), "The tick at 60 is should not be empty.");
+ ok(!hasPixelAt(61), "The tick at 61 is should be empty.");
+ ok(!hasPixelAt(79), "The tick at 79 is should be empty.");
+ ok( hasPixelAt(80), "The tick at 80 is should not be empty.");
+ ok(!hasPixelAt(81), "The tick at 81 is should be empty.");
+ ok(!hasPixelAt(159), "The tick at 159 is should be empty.");
+ ok( hasPixelAt(160), "The tick at 160 is should not be empty.");
+ ok(!hasPixelAt(161), "The tick at 161 is should be empty.");
+
+ ok(isPixelBrighterAtThan(0, 20),
+ "The tick at 0 should be brighter than the one at 20");
+ ok(isPixelBrighterAtThan(40, 20),
+ "The tick at 40 should be brighter than the one at 20");
+ ok(isPixelBrighterAtThan(40, 60),
+ "The tick at 40 should be brighter than the one at 60");
+ ok(isPixelBrighterAtThan(80, 60),
+ "The tick at 80 should be brighter than the one at 60");
+
+ ok(isPixelBrighterAtThan(80, 100),
+ "The tick at 80 should be brighter than the one at 100");
+ ok(isPixelBrighterAtThan(120, 100),
+ "The tick at 120 should be brighter than the one at 100");
+ ok(isPixelBrighterAtThan(120, 140),
+ "The tick at 120 should be brighter than the one at 140");
+ ok(isPixelBrighterAtThan(160, 140),
+ "The tick at 160 should be brighter than the one at 140");
+
+ ok(isPixelEquallyBright(20, 60),
+ "The tick at 20 should be equally bright to the one at 60");
+ ok(isPixelEquallyBright(100, 140),
+ "The tick at 100 should be equally bright to the one at 140");
+
+ ok(isPixelEquallyBright(40, 120),
+ "The tick at 40 should be equally bright to the one at 120");
+
+ ok(isPixelEquallyBright(0, 80),
+ "The tick at 80 should be equally bright to the one at 160");
+ ok(isPixelEquallyBright(80, 160),
+ "The tick at 80 should be equally bright to the one at 160");
+
+ function hasPixelAt(x) {
+ let i = (x | 0) * 4;
+ return data[i] && data[i + 1] && data[i + 2] && data[i + 3];
+ }
+
+ function isPixelBrighterAtThan(x1, x2) {
+ let i = (x1 | 0) * 4;
+ let j = (x2 | 0) * 4;
+ return data[i + 3] > data [j + 3];
+ }
+
+ function isPixelEquallyBright(x1, x2) {
+ let i = (x1 | 0) * 4;
+ let j = (x2 | 0) * 4;
+ return data[i + 3] == data [j + 3];
+ }
+
+ teardown(aMonitor).then(finish);
+ });
+
+ aDebuggee.location.reload();
+ });
+}
diff --git a/browser/devtools/netmonitor/test/head.js b/browser/devtools/netmonitor/test/head.js
new file mode 100644
index 000000000..dca1dc3cc
--- /dev/null
+++ b/browser/devtools/netmonitor/test/head.js
@@ -0,0 +1,283 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+let { Promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
+let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+let TargetFactory = devtools.TargetFactory;
+let Toolbox = devtools.Toolbox;
+
+const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";
+
+const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
+const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
+const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
+const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
+const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
+const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
+const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
+const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
+const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
+const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
+const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
+const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
+const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";
+const CUSTOM_GET_URL = EXAMPLE_URL + "html_custom-get-page.html";
+
+const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
+const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
+const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
+const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
+
+const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
+
+// All tests are asynchronous.
+waitForExplicitFinish();
+
+// Enable logging for all the relevant tests.
+let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
+Services.prefs.setBoolPref("devtools.debugger.log", true);
+
+registerCleanupFunction(() => {
+ info("finish() was called, cleaning up...");
+ Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
+});
+
+function addTab(aUrl, aWindow) {
+ info("Adding tab: " + aUrl);
+
+ let deferred = Promise.defer();
+ let targetWindow = aWindow || window;
+ let targetBrowser = targetWindow.gBrowser;
+
+ targetWindow.focus();
+ let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
+ let browser = tab.linkedBrowser;
+
+ browser.addEventListener("load", function onLoad() {
+ browser.removeEventListener("load", onLoad, true);
+ deferred.resolve(tab);
+ }, true);
+
+ return deferred.promise;
+}
+
+function removeTab(aTab, aWindow) {
+ info("Removing tab.");
+
+ let targetWindow = aWindow || window;
+ let targetBrowser = targetWindow.gBrowser;
+
+ targetBrowser.removeTab(aTab);
+}
+
+function initNetMonitor(aUrl, aWindow) {
+ info("Initializing a network monitor pane.");
+
+ return addTab(aUrl).then((aTab) => {
+ info("Net tab added successfully: " + aUrl);
+
+ let deferred = Promise.defer();
+ let debuggee = aTab.linkedBrowser.contentWindow.wrappedJSObject;
+ let target = TargetFactory.forTab(aTab);
+
+ gDevTools.showToolbox(target, "netmonitor").then((aToolbox) => {
+ info("Netork monitor pane shown successfully.");
+
+ let monitor = aToolbox.getCurrentPanel();
+ deferred.resolve([aTab, debuggee, monitor]);
+ });
+
+ return deferred.promise;
+ });
+}
+
+function restartNetMonitor(aMonitor, aNewUrl) {
+ info("Restarting the specified network monitor.");
+
+ let deferred = Promise.defer();
+ let tab = aMonitor.target.tab;
+ let url = aNewUrl || tab.linkedBrowser.contentWindow.wrappedJSObject.location.href;
+
+ aMonitor.once("destroyed", () => initNetMonitor(url).then(deferred.resolve));
+ removeTab(tab);
+
+ return deferred.promise;
+}
+
+function teardown(aMonitor) {
+ info("Destroying the specified network monitor.");
+
+ let deferred = Promise.defer();
+ let tab = aMonitor.target.tab;
+
+ aMonitor.once("destroyed", () => executeSoon(deferred.resolve));
+ removeTab(tab);
+
+ return deferred.promise;
+}
+
+function waitForNetworkEvents(aMonitor, aGetRequests, aPostRequests = 0) {
+ let deferred = Promise.defer();
+
+ let panel = aMonitor.panelWin;
+ let genericEvents = 0;
+ let postEvents = 0;
+
+ function onGenericEvent() {
+ genericEvents++;
+ maybeResolve();
+ }
+
+ function onPostEvent() {
+ postEvents++;
+ maybeResolve();
+ }
+
+ function maybeResolve() {
+ info("> Network events progress: " +
+ genericEvents + "/" + ((aGetRequests + aPostRequests) * 13) + ", " +
+ postEvents + "/" + (aPostRequests * 2));
+
+ // There are 15 updates which need to be fired for a request to be
+ // considered finished. RequestPostData isn't fired for non-POST requests.
+ if (genericEvents == (aGetRequests + aPostRequests) * 13 &&
+ postEvents == aPostRequests * 2) {
+
+ panel.off("NetMonitor:NetworkEventUpdating:RequestHeaders", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdated:RequestHeaders", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdating:RequestCookies", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdating:RequestPostData", onPostEvent);
+ panel.off("NetMonitor:NetworkEventUpdated:RequestPostData", onPostEvent);
+ panel.off("NetMonitor:NetworkEventUpdated:RequestCookies", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdating:ResponseHeaders", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdated:ResponseHeaders", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdating:ResponseCookies", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdated:ResponseCookies", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdating:ResponseStart", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdating:ResponseContent", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdated:ResponseContent", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdating:EventTimings", onGenericEvent);
+ panel.off("NetMonitor:NetworkEventUpdated:EventTimings", onGenericEvent);
+
+ executeSoon(deferred.resolve);
+ }
+ }
+
+ panel.on("NetMonitor:NetworkEventUpdating:RequestHeaders", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdated:RequestHeaders", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdating:RequestCookies", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdating:RequestPostData", onPostEvent);
+ panel.on("NetMonitor:NetworkEventUpdated:RequestPostData", onPostEvent);
+ panel.on("NetMonitor:NetworkEventUpdated:RequestCookies", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdating:ResponseHeaders", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdated:ResponseHeaders", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdating:ResponseCookies", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdated:ResponseCookies", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdating:ResponseStart", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdating:ResponseContent", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdated:ResponseContent", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdating:EventTimings", onGenericEvent);
+ panel.on("NetMonitor:NetworkEventUpdated:EventTimings", onGenericEvent);
+
+ return deferred.promise;
+}
+
+function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
+ info("> Verifying: " + aMethod + " " + aUrl + " " + aData.toSource());
+ info("> Request: " + aRequestItem.attachment.toSource());
+
+ let requestsMenu = aRequestItem.ownerView;
+ let widgetIndex = requestsMenu.indexOfItem(aRequestItem);
+ let visibleIndex = requestsMenu.orderedVisibleItems.indexOf(aRequestItem);
+
+ info("Widget index of item: " + widgetIndex);
+ info("Visible index of item: " + visibleIndex);
+
+ let { fuzzyUrl, status, statusText, type, fullMimeType, size, time } = aData;
+ let { attachment, target } = aRequestItem
+
+ let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
+ let name = uri.fileName || "/";
+ let query = uri.query;
+ let hostPort = uri.hostPort;
+
+ if (fuzzyUrl) {
+ ok(attachment.method.startsWith(aMethod), "The attached method is incorrect.");
+ ok(attachment.url.startsWith(aUrl), "The attached url is incorrect.");
+ } else {
+ is(attachment.method, aMethod, "The attached method is incorrect.");
+ is(attachment.url, aUrl, "The attached url is incorrect.");
+ }
+
+ is(target.querySelector(".requests-menu-method").getAttribute("value"),
+ aMethod, "The displayed method is incorrect.");
+
+ if (fuzzyUrl) {
+ ok(target.querySelector(".requests-menu-file").getAttribute("value").startsWith(
+ name + (query ? "?" + query : "")), "The displayed file is incorrect.");
+ ok(target.querySelector(".requests-menu-file").getAttribute("tooltiptext").startsWith(
+ name + (query ? "?" + query : "")), "The tooltip file is incorrect.");
+ } else {
+ is(target.querySelector(".requests-menu-file").getAttribute("value"),
+ name + (query ? "?" + query : ""), "The displayed file is incorrect.");
+ is(target.querySelector(".requests-menu-file").getAttribute("tooltiptext"),
+ name + (query ? "?" + query : ""), "The tooltip file is incorrect.");
+ }
+
+ is(target.querySelector(".requests-menu-domain").getAttribute("value"),
+ hostPort, "The displayed domain is incorrect.");
+ is(target.querySelector(".requests-menu-domain").getAttribute("tooltiptext"),
+ hostPort, "The tooltip domain is incorrect.");
+
+ if (status !== undefined) {
+ let value = target.querySelector(".requests-menu-status").getAttribute("code");
+ let tooltip = target.querySelector(".requests-menu-status-and-method").getAttribute("tooltiptext");
+ info("Displayed status: " + value);
+ info("Tooltip status: " + tooltip);
+ is(value, status, "The displayed status is incorrect.");
+ is(tooltip, status + " " + statusText, "The tooltip status is incorrect.");
+ }
+ if (type !== undefined) {
+ let value = target.querySelector(".requests-menu-type").getAttribute("value");
+ let tooltip = target.querySelector(".requests-menu-type").getAttribute("tooltiptext");
+ info("Displayed type: " + value);
+ info("Tooltip type: " + tooltip);
+ is(value, type, "The displayed type is incorrect.");
+ is(tooltip, fullMimeType, "The tooltip type is incorrect.");
+ }
+ if (size !== undefined) {
+ let value = target.querySelector(".requests-menu-size").getAttribute("value");
+ let tooltip = target.querySelector(".requests-menu-size").getAttribute("tooltiptext");
+ info("Displayed size: " + value);
+ info("Tooltip size: " + tooltip);
+ is(value, size, "The displayed size is incorrect.");
+ is(tooltip, size, "The tooltip size is incorrect.");
+ }
+ if (time !== undefined) {
+ let value = target.querySelector(".requests-menu-timings-total").getAttribute("value");
+ let tooltip = target.querySelector(".requests-menu-timings-total").getAttribute("tooltiptext");
+ info("Displayed time: " + value);
+ info("Tooltip time: " + tooltip);
+ ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is incorrect.");
+ ok(~~(tooltip.match(/[0-9]+/)) >= 0, "The tooltip time is incorrect.");
+ }
+
+ if (visibleIndex != -1) {
+ if (visibleIndex % 2 == 0) {
+ ok(aRequestItem.target.hasAttribute("even"),
+ "Unexpected 'even' attribute for " + aRequestItem.value);
+ ok(!aRequestItem.target.hasAttribute("odd"),
+ "Unexpected 'odd' attribute for " + aRequestItem.value);
+ } else {
+ ok(!aRequestItem.target.hasAttribute("even"),
+ "Unexpected 'even' attribute for " + aRequestItem.value);
+ ok(aRequestItem.target.hasAttribute("odd"),
+ "Unexpected 'odd' attribute for " + aRequestItem.value);
+ }
+ }
+}
diff --git a/browser/devtools/netmonitor/test/html_content-type-test-page.html b/browser/devtools/netmonitor/test/html_content-type-test-page.html
new file mode 100644
index 000000000..506ba21c1
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_content-type-test-page.html
@@ -0,0 +1,43 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Content type test</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests() {
+ get("sjs_content-type-test-server.sjs?fmt=xml", function() {
+ get("sjs_content-type-test-server.sjs?fmt=css", function() {
+ get("sjs_content-type-test-server.sjs?fmt=js", function() {
+ get("sjs_content-type-test-server.sjs?fmt=json", function() {
+ get("sjs_content-type-test-server.sjs?fmt=bogus", function() {
+ get("test-image.png", function() {
+ // Done.
+ });
+ });
+ });
+ });
+ });
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_custom-get-page.html b/browser/devtools/netmonitor/test/html_custom-get-page.html
new file mode 100644
index 000000000..b01ae09eb
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_custom-get-page.html
@@ -0,0 +1,39 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Performing a custom number of GETs</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ // Use a count parameter to defeat caching.
+ var count = 0;
+
+ function performRequests(aTotal, aUrl, aTimeout = 0) {
+ if (!aTotal) {
+ return;
+ }
+ get(aUrl || "request_" + (count++), function() {
+ setTimeout(performRequests.bind(this, --aTotal, aUrl, aTimeout), aTimeout);
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_cyrillic-test-page.html b/browser/devtools/netmonitor/test/html_cyrillic-test-page.html
new file mode 100644
index 000000000..b9a0dc9d0
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_cyrillic-test-page.html
@@ -0,0 +1,34 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Cyrillic type test</p>
+ <p>Братан, ты вообще качаешься?</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests() {
+ get("sjs_content-type-test-server.sjs?fmt=txt", function() {
+ // Done.
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_filter-test-page.html b/browser/devtools/netmonitor/test/html_filter-test-page.html
new file mode 100644
index 000000000..6719991d9
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_filter-test-page.html
@@ -0,0 +1,55 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Filtering test</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ // Use a random parameter to defeat caching.
+ xhr.open("GET", aAddress + "&" + Math.random(), true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests(aOptions) {
+ var options = JSON.parse(aOptions);
+ get("sjs_content-type-test-server.sjs?fmt=html&res=" + options.htmlContent, function() {
+ get("sjs_content-type-test-server.sjs?fmt=css", function() {
+ get("sjs_content-type-test-server.sjs?fmt=js", function() {
+ if (!options.getMedia) {
+ return;
+ }
+ get("sjs_content-type-test-server.sjs?fmt=font", function() {
+ get("sjs_content-type-test-server.sjs?fmt=image", function() {
+ get("sjs_content-type-test-server.sjs?fmt=audio", function() {
+ get("sjs_content-type-test-server.sjs?fmt=video", function() {
+ if (!options.getFlash) {
+ return;
+ }
+ get("sjs_content-type-test-server.sjs?fmt=flash", function() {
+ // Done.
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_infinite-get-page.html b/browser/devtools/netmonitor/test/html_infinite-get-page.html
new file mode 100644
index 000000000..882dc57de
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_infinite-get-page.html
@@ -0,0 +1,36 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Infinite GETs</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ // Use a count parameter to defeat caching.
+ var count = 0;
+
+ (function performRequests() {
+ get("request_" + (count++), function() {
+ setTimeout(performRequests, 50);
+ });
+ })();
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_json-long-test-page.html b/browser/devtools/netmonitor/test/html_json-long-test-page.html
new file mode 100644
index 000000000..4889d76c7
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_json-long-test-page.html
@@ -0,0 +1,33 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>JSON long string test</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests() {
+ get("sjs_content-type-test-server.sjs?fmt=json-long", function() {
+ // Done.
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_json-malformed-test-page.html b/browser/devtools/netmonitor/test/html_json-malformed-test-page.html
new file mode 100644
index 000000000..3c47c797f
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_json-malformed-test-page.html
@@ -0,0 +1,33 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>JSON malformed test</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests() {
+ get("sjs_content-type-test-server.sjs?fmt=json-malformed", function() {
+ // Done.
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_jsonp-test-page.html b/browser/devtools/netmonitor/test/html_jsonp-test-page.html
new file mode 100644
index 000000000..7cf0c6bbb
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_jsonp-test-page.html
@@ -0,0 +1,33 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>JSONP test</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests() {
+ get("sjs_content-type-test-server.sjs?fmt=jsonp&jsonp=$_0123Fun", function() {
+ // Done.
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_navigate-test-page.html b/browser/devtools/netmonitor/test/html_navigate-test-page.html
new file mode 100644
index 000000000..69284120a
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_navigate-test-page.html
@@ -0,0 +1,13 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Navigation test</p>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_post-data-test-page.html b/browser/devtools/netmonitor/test/html_post-data-test-page.html
new file mode 100644
index 000000000..4be478226
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_post-data-test-page.html
@@ -0,0 +1,72 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ <style>
+ input {
+ display: block;
+ margin: 12px;
+ }
+ </style>
+ </head>
+
+ <body>
+ <p>POST data test</p>
+ <form enctype="multipart/form-data" method="post" name="form-name">
+ <input type="text" name="text" placeholder="text" value="Some text..."/>
+ <input type="email" name="email" placeholder="email"/>
+ <input type="range" name="range" value="42"/>
+ <input type="button" value="Post me!" onclick="window.form()">
+ </form>
+
+ <script type="text/javascript">
+ function post(aAddress, aMessage, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("POST", aAddress, true);
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ var data = "";
+ for (var i in aMessage) {
+ data += "&" + i + "=" + aMessage[i];
+ }
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(data);
+ }
+
+ function form(aAddress, aForm, aCallback) {
+ var formData = new FormData(document.forms.namedItem(aForm));
+ formData.append("Custom field", "Extra data");
+
+ var xhr = new XMLHttpRequest();
+ xhr.open("POST", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(formData);
+ }
+
+ function performRequests() {
+ var url = "sjs_simple-test-server.sjs";
+ var url1 = url + "?foo=bar&baz=42&type=urlencoded";
+ var url2 = url + "?foo=bar&baz=42&type=multipart";
+
+ post(url1, { foo: "bar", baz: 123 }, function() {
+ form(url2, "form-name", function() {
+ // Done.
+ });
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_post-raw-test-page.html b/browser/devtools/netmonitor/test/html_post-raw-test-page.html
new file mode 100644
index 000000000..b3148a77e
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_post-raw-test-page.html
@@ -0,0 +1,34 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>POST raw test</p>
+
+ <script type="text/javascript">
+ function post(aAddress, aMessage, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("POST", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(aMessage);
+ }
+
+ function performRequests() {
+ var rawData = "Content-Type: application/x-www-form-urlencoded\r\n\r\nfoo=bar&baz=123";
+ post("sjs_simple-test-server.sjs", rawData, function() {
+ // Done.
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_simple-test-page.html b/browser/devtools/netmonitor/test/html_simple-test-page.html
new file mode 100644
index 000000000..a8eae55bf
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_simple-test-page.html
@@ -0,0 +1,13 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Simple test</p>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_sorting-test-page.html b/browser/devtools/netmonitor/test/html_sorting-test-page.html
new file mode 100644
index 000000000..9326ded2d
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_sorting-test-page.html
@@ -0,0 +1,42 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Sorting test</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aIndex, aCallback) {
+ var xhr = new XMLHttpRequest();
+ // Use a random parameter to defeat caching.
+ xhr.open("GET" + aIndex, aAddress + "?index=" + aIndex + "&" + Math.random(), true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests() {
+ get("sjs_sorting-test-server.sjs", 1, function() {
+ get("sjs_sorting-test-server.sjs", 5, function() {
+ get("sjs_sorting-test-server.sjs", 2, function() {
+ get("sjs_sorting-test-server.sjs", 4, function() {
+ get("sjs_sorting-test-server.sjs", 3, function() {
+ // Done.
+ });
+ });
+ });
+ });
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/html_status-codes-test-page.html b/browser/devtools/netmonitor/test/html_status-codes-test-page.html
new file mode 100644
index 000000000..f19570e71
--- /dev/null
+++ b/browser/devtools/netmonitor/test/html_status-codes-test-page.html
@@ -0,0 +1,41 @@
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Network Monitor test page</title>
+ </head>
+
+ <body>
+ <p>Status codes test</p>
+
+ <script type="text/javascript">
+ function get(aAddress, aCallback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", aAddress, true);
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.DONE) {
+ aCallback();
+ }
+ };
+ xhr.send(null);
+ }
+
+ function performRequests() {
+ get("sjs_status-codes-test-server.sjs?sts=100", function() {
+ get("sjs_status-codes-test-server.sjs?sts=200", function() {
+ get("sjs_status-codes-test-server.sjs?sts=300", function() {
+ get("sjs_status-codes-test-server.sjs?sts=400", function() {
+ get("sjs_status-codes-test-server.sjs?sts=500", function() {
+ // Done.
+ });
+ });
+ });
+ });
+ });
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/browser/devtools/netmonitor/test/moz.build b/browser/devtools/netmonitor/test/moz.build
new file mode 100644
index 000000000..58ce5e273
--- /dev/null
+++ b/browser/devtools/netmonitor/test/moz.build
@@ -0,0 +1,5 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
diff --git a/browser/devtools/netmonitor/test/sjs_content-type-test-server.sjs b/browser/devtools/netmonitor/test/sjs_content-type-test-server.sjs
new file mode 100644
index 000000000..a0cb4ec65
--- /dev/null
+++ b/browser/devtools/netmonitor/test/sjs_content-type-test-server.sjs
@@ -0,0 +1,127 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { classes: Cc, interfaces: Ci } = Components;
+
+function handleRequest(request, response) {
+ response.processAsync();
+
+ let params = request.queryString.split("&");
+ let format = params.filter((s) => s.contains("fmt="))[0].split("=")[1];
+
+ Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
+ switch (format) {
+ case "txt": {
+ response.setStatusLine(request.httpVersion, 200, "DA DA DA");
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write("Братан, ты вообще качаешься?");
+ response.finish();
+ break;
+ }
+ case "xml": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/xml; charset=utf-8", false);
+ response.write("<label value='greeting'>Hello XML!</label>");
+ response.finish();
+ break;
+ }
+ case "html": {
+ let content = params.filter((s) => s.contains("res="))[0].split("=")[1];
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ response.write(content || "<p>Hello HTML!</p>");
+ response.finish();
+ break;
+ }
+ case "html-long": {
+ let str = new Array(102400 /* 100 KB in bytes */).join(".");
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ response.write("<p>" + str + "</p>");
+ response.finish();
+ break;
+ }
+ case "css": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/css; charset=utf-8", false);
+ response.write("body:pre { content: 'Hello CSS!' }");
+ response.finish();
+ break;
+ }
+ case "js": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/javascript; charset=utf-8", false);
+ response.write("function() { return 'Hello JS!'; }");
+ response.finish();
+ break;
+ }
+ case "json": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/json; charset=utf-8", false);
+ response.write("{ \"greeting\": \"Hello JSON!\" }");
+ response.finish();
+ break;
+ }
+ case "jsonp": {
+ let fun = params.filter((s) => s.contains("jsonp="))[0].split("=")[1];
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/json; charset=utf-8", false);
+ response.write(fun + "({ \"greeting\": \"Hello JSONP!\" })");
+ response.finish();
+ break;
+ }
+ case "json-long": {
+ let str = "{ \"greeting\": \"Hello long string JSON!\" },";
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/json; charset=utf-8", false);
+ response.write("[" + new Array(2048).join(str).slice(0, -1) + "]");
+ response.finish();
+ break;
+ }
+ case "json-malformed": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/json; charset=utf-8", false);
+ response.write("{ \"greeting\": \"Hello malformed JSON!\" },");
+ response.finish();
+ break;
+ }
+ case "font": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "font/woff", false);
+ response.finish();
+ break;
+ }
+ case "image": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "image/png", false);
+ response.finish();
+ break;
+ }
+ case "audio": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "audio/ogg", false);
+ response.finish();
+ break;
+ }
+ case "video": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "video/webm", false);
+ response.finish();
+ break;
+ }
+ case "flash": {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/x-shockwave-flash", false);
+ response.finish();
+ break;
+ }
+ default: {
+ response.setStatusLine(request.httpVersion, 404, "Not Found");
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ response.write("<blink>Not Found</blink>");
+ response.finish();
+ break;
+ }
+ }
+ }, 10, Ci.nsITimer.TYPE_ONE_SHOT); // Make sure this request takes a few ms.
+}
diff --git a/browser/devtools/netmonitor/test/sjs_simple-test-server.sjs b/browser/devtools/netmonitor/test/sjs_simple-test-server.sjs
new file mode 100644
index 000000000..15fe9f8ae
--- /dev/null
+++ b/browser/devtools/netmonitor/test/sjs_simple-test-server.sjs
@@ -0,0 +1,9 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, 200, "Och Aye");
+ response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
+ response.setHeader("Foo-Bar", "baz", false);
+ response.write("Hello world!");
+}
diff --git a/browser/devtools/netmonitor/test/sjs_sorting-test-server.sjs b/browser/devtools/netmonitor/test/sjs_sorting-test-server.sjs
new file mode 100644
index 000000000..fd31b3266
--- /dev/null
+++ b/browser/devtools/netmonitor/test/sjs_sorting-test-server.sjs
@@ -0,0 +1,18 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { classes: Cc, interfaces: Ci } = Components;
+
+function handleRequest(request, response) {
+ response.processAsync();
+
+ let params = request.queryString.split("&");
+ let index = params.filter((s) => s.contains("index="))[0].split("=")[1];
+
+ Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
+ response.setStatusLine(request.httpVersion, index == 1 ? 101 : index * 100, "Meh");
+ response.setHeader("Content-Type", "text/" + index, false);
+ response.write(new Array(index * 10).join(index)); // + 0.01 KB
+ response.finish();
+ }, 10, Ci.nsITimer.TYPE_ONE_SHOT); // Make sure this request takes a few ms.
+}
diff --git a/browser/devtools/netmonitor/test/sjs_status-codes-test-server.sjs b/browser/devtools/netmonitor/test/sjs_status-codes-test-server.sjs
new file mode 100644
index 000000000..bc07336ee
--- /dev/null
+++ b/browser/devtools/netmonitor/test/sjs_status-codes-test-server.sjs
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { classes: Cc, interfaces: Ci } = Components;
+
+function handleRequest(request, response) {
+ response.processAsync();
+
+ let params = request.queryString.split("&");
+ let status = params.filter((s) => s.contains("sts="))[0].split("=")[1];
+
+ Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
+ switch (status) {
+ case "100":
+ response.setStatusLine(request.httpVersion, 101, "Switching Protocols");
+ break;
+ case "200":
+ response.setStatusLine(request.httpVersion, 202, "Created");
+ break;
+ case "300":
+ response.setStatusLine(request.httpVersion, 303, "See Other");
+ break;
+ case "400":
+ response.setStatusLine(request.httpVersion, 404, "Not Found");
+ break;
+ case "500":
+ response.setStatusLine(request.httpVersion, 501, "Not Implemented");
+ break;
+ }
+ response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
+ response.write("Hello status code " + status + "!");
+ response.finish();
+ }, 10, Ci.nsITimer.TYPE_ONE_SHOT); // Make sure this request takes a few ms.
+}
diff --git a/browser/devtools/netmonitor/test/test-image.png b/browser/devtools/netmonitor/test/test-image.png
new file mode 100644
index 000000000..769c63634
--- /dev/null
+++ b/browser/devtools/netmonitor/test/test-image.png
Binary files differ