browser/devtools/netmonitor/test/head.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:03dd6b2907ba
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
3 "use strict";
4
5 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
6
7 let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
8 let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
9 let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
10 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
11 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
12 let { CurlUtils } = Cu.import("resource:///modules/devtools/Curl.jsm", {});
13 let TargetFactory = devtools.TargetFactory;
14 let Toolbox = devtools.Toolbox;
15
16 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";
17
18 const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
19 const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
20 const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
21 const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
22 const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
23 const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
24 const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
25 const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
26 const POST_RAW_WITH_HEADERS_URL = EXAMPLE_URL + "html_post-raw-with-headers-test-page.html";
27 const PARAMS_URL = EXAMPLE_URL + "html_params-test-page.html";
28 const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
29 const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
30 const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
31 const JSON_CUSTOM_MIME_URL = EXAMPLE_URL + "html_json-custom-mime-test-page.html";
32 const JSON_TEXT_MIME_URL = EXAMPLE_URL + "html_json-text-mime-test-page.html";
33 const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
34 const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
35 const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";
36 const CUSTOM_GET_URL = EXAMPLE_URL + "html_custom-get-page.html";
37 const SINGLE_GET_URL = EXAMPLE_URL + "html_single-get-page.html";
38 const STATISTICS_URL = EXAMPLE_URL + "html_statistics-test-page.html";
39 const CURL_URL = EXAMPLE_URL + "html_copy-as-curl.html";
40 const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html";
41
42 const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
43 const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
44 const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
45 const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
46
47 const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
48 const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
49
50 gDevTools.testing = true;
51 SimpleTest.registerCleanupFunction(() => {
52 gDevTools.testing = false;
53 });
54
55 // All tests are asynchronous.
56 waitForExplicitFinish();
57
58 const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
59 // To enable logging for try runs, just set the pref to true.
60 Services.prefs.setBoolPref("devtools.debugger.log", false);
61
62 // Always reset some prefs to their original values after the test finishes.
63 const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters");
64
65 registerCleanupFunction(() => {
66 info("finish() was called, cleaning up...");
67
68 Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
69 Services.prefs.setCharPref("devtools.netmonitor.filters", gDefaultFilters);
70 });
71
72 function addTab(aUrl, aWindow) {
73 info("Adding tab: " + aUrl);
74
75 let deferred = promise.defer();
76 let targetWindow = aWindow || window;
77 let targetBrowser = targetWindow.gBrowser;
78
79 targetWindow.focus();
80 let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
81 let browser = tab.linkedBrowser;
82
83 browser.addEventListener("load", function onLoad() {
84 browser.removeEventListener("load", onLoad, true);
85 deferred.resolve(tab);
86 }, true);
87
88 return deferred.promise;
89 }
90
91 function removeTab(aTab, aWindow) {
92 info("Removing tab.");
93
94 let targetWindow = aWindow || window;
95 let targetBrowser = targetWindow.gBrowser;
96
97 targetBrowser.removeTab(aTab);
98 }
99
100 function initNetMonitor(aUrl, aWindow) {
101 info("Initializing a network monitor pane.");
102
103 return addTab(aUrl).then((aTab) => {
104 info("Net tab added successfully: " + aUrl);
105
106 let deferred = promise.defer();
107 let debuggee = aTab.linkedBrowser.contentWindow.wrappedJSObject;
108 let target = TargetFactory.forTab(aTab);
109
110 gDevTools.showToolbox(target, "netmonitor").then((aToolbox) => {
111 info("Netork monitor pane shown successfully.");
112
113 let monitor = aToolbox.getCurrentPanel();
114 deferred.resolve([aTab, debuggee, monitor]);
115 });
116
117 return deferred.promise;
118 });
119 }
120
121 function restartNetMonitor(aMonitor, aNewUrl) {
122 info("Restarting the specified network monitor.");
123
124 let deferred = promise.defer();
125 let tab = aMonitor.target.tab;
126 let url = aNewUrl || tab.linkedBrowser.contentWindow.wrappedJSObject.location.href;
127
128 aMonitor.once("destroyed", () => initNetMonitor(url).then(deferred.resolve));
129 removeTab(tab);
130
131 return deferred.promise;
132 }
133
134 function teardown(aMonitor) {
135 info("Destroying the specified network monitor.");
136
137 let deferred = promise.defer();
138 let tab = aMonitor.target.tab;
139
140 aMonitor.once("destroyed", () => executeSoon(deferred.resolve));
141 removeTab(tab);
142
143 return deferred.promise;
144 }
145
146 function waitForNetworkEvents(aMonitor, aGetRequests, aPostRequests = 0) {
147 let deferred = promise.defer();
148
149 let panel = aMonitor.panelWin;
150 let genericEvents = 0;
151 let postEvents = 0;
152
153 function onGenericEvent() {
154 genericEvents++;
155 maybeResolve();
156 }
157
158 function onPostEvent() {
159 postEvents++;
160 maybeResolve();
161 }
162
163 function maybeResolve() {
164 info("> Network events progress: " +
165 genericEvents + "/" + ((aGetRequests + aPostRequests) * 13) + ", " +
166 postEvents + "/" + (aPostRequests * 2));
167
168 // There are 15 updates which need to be fired for a request to be
169 // considered finished. RequestPostData isn't fired for non-POST requests.
170 if (genericEvents == (aGetRequests + aPostRequests) * 13 &&
171 postEvents == aPostRequests * 2) {
172
173 panel.off(panel.EVENTS.UPDATING_REQUEST_HEADERS, onGenericEvent);
174 panel.off(panel.EVENTS.RECEIVED_REQUEST_HEADERS, onGenericEvent);
175 panel.off(panel.EVENTS.UPDATING_REQUEST_COOKIES, onGenericEvent);
176 panel.off(panel.EVENTS.RECEIVED_REQUEST_COOKIES, onGenericEvent);
177 panel.off(panel.EVENTS.UPDATING_REQUEST_POST_DATA, onPostEvent);
178 panel.off(panel.EVENTS.RECEIVED_REQUEST_POST_DATA, onPostEvent);
179 panel.off(panel.EVENTS.UPDATING_RESPONSE_HEADERS, onGenericEvent);
180 panel.off(panel.EVENTS.RECEIVED_RESPONSE_HEADERS, onGenericEvent);
181 panel.off(panel.EVENTS.UPDATING_RESPONSE_COOKIES, onGenericEvent);
182 panel.off(panel.EVENTS.RECEIVED_RESPONSE_COOKIES, onGenericEvent);
183 panel.off(panel.EVENTS.STARTED_RECEIVING_RESPONSE, onGenericEvent);
184 panel.off(panel.EVENTS.UPDATING_RESPONSE_CONTENT, onGenericEvent);
185 panel.off(panel.EVENTS.RECEIVED_RESPONSE_CONTENT, onGenericEvent);
186 panel.off(panel.EVENTS.UPDATING_EVENT_TIMINGS, onGenericEvent);
187 panel.off(panel.EVENTS.RECEIVED_EVENT_TIMINGS, onGenericEvent);
188
189 executeSoon(deferred.resolve);
190 }
191 }
192
193 panel.on(panel.EVENTS.UPDATING_REQUEST_HEADERS, onGenericEvent);
194 panel.on(panel.EVENTS.RECEIVED_REQUEST_HEADERS, onGenericEvent);
195 panel.on(panel.EVENTS.UPDATING_REQUEST_COOKIES, onGenericEvent);
196 panel.on(panel.EVENTS.RECEIVED_REQUEST_COOKIES, onGenericEvent);
197 panel.on(panel.EVENTS.UPDATING_REQUEST_POST_DATA, onPostEvent);
198 panel.on(panel.EVENTS.RECEIVED_REQUEST_POST_DATA, onPostEvent);
199 panel.on(panel.EVENTS.UPDATING_RESPONSE_HEADERS, onGenericEvent);
200 panel.on(panel.EVENTS.RECEIVED_RESPONSE_HEADERS, onGenericEvent);
201 panel.on(panel.EVENTS.UPDATING_RESPONSE_COOKIES, onGenericEvent);
202 panel.on(panel.EVENTS.RECEIVED_RESPONSE_COOKIES, onGenericEvent);
203 panel.on(panel.EVENTS.STARTED_RECEIVING_RESPONSE, onGenericEvent);
204 panel.on(panel.EVENTS.UPDATING_RESPONSE_CONTENT, onGenericEvent);
205 panel.on(panel.EVENTS.RECEIVED_RESPONSE_CONTENT, onGenericEvent);
206 panel.on(panel.EVENTS.UPDATING_EVENT_TIMINGS, onGenericEvent);
207 panel.on(panel.EVENTS.RECEIVED_EVENT_TIMINGS, onGenericEvent);
208
209 return deferred.promise;
210 }
211
212 function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
213 info("> Verifying: " + aMethod + " " + aUrl + " " + aData.toSource());
214 // This bloats log sizes significantly in automation (bug 992485)
215 //info("> Request: " + aRequestItem.attachment.toSource());
216
217 let requestsMenu = aRequestItem.ownerView;
218 let widgetIndex = requestsMenu.indexOfItem(aRequestItem);
219 let visibleIndex = requestsMenu.visibleItems.indexOf(aRequestItem);
220
221 info("Widget index of item: " + widgetIndex);
222 info("Visible index of item: " + visibleIndex);
223
224 let { fuzzyUrl, status, statusText, type, fullMimeType, size, time } = aData;
225 let { attachment, target } = aRequestItem
226
227 let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
228 let name = uri.fileName || "/";
229 let query = uri.query;
230 let hostPort = uri.hostPort;
231
232 if (fuzzyUrl) {
233 ok(attachment.method.startsWith(aMethod), "The attached method is incorrect.");
234 ok(attachment.url.startsWith(aUrl), "The attached url is incorrect.");
235 } else {
236 is(attachment.method, aMethod, "The attached method is incorrect.");
237 is(attachment.url, aUrl, "The attached url is incorrect.");
238 }
239
240 is(target.querySelector(".requests-menu-method").getAttribute("value"),
241 aMethod, "The displayed method is incorrect.");
242
243 if (fuzzyUrl) {
244 ok(target.querySelector(".requests-menu-file").getAttribute("value").startsWith(
245 name + (query ? "?" + query : "")), "The displayed file is incorrect.");
246 ok(target.querySelector(".requests-menu-file").getAttribute("tooltiptext").startsWith(
247 name + (query ? "?" + query : "")), "The tooltip file is incorrect.");
248 } else {
249 is(target.querySelector(".requests-menu-file").getAttribute("value"),
250 name + (query ? "?" + query : ""), "The displayed file is incorrect.");
251 is(target.querySelector(".requests-menu-file").getAttribute("tooltiptext"),
252 name + (query ? "?" + query : ""), "The tooltip file is incorrect.");
253 }
254
255 is(target.querySelector(".requests-menu-domain").getAttribute("value"),
256 hostPort, "The displayed domain is incorrect.");
257 is(target.querySelector(".requests-menu-domain").getAttribute("tooltiptext"),
258 hostPort, "The tooltip domain is incorrect.");
259
260 if (status !== undefined) {
261 let value = target.querySelector(".requests-menu-status").getAttribute("code");
262 let codeValue = target.querySelector(".requests-menu-status-code").getAttribute("value");
263 let tooltip = target.querySelector(".requests-menu-status-and-method").getAttribute("tooltiptext");
264 info("Displayed status: " + value);
265 info("Displayed code: " + codeValue);
266 info("Tooltip status: " + tooltip);
267 is(value, status, "The displayed status is incorrect.");
268 is(codeValue, status, "The displayed status code is incorrect.");
269 is(tooltip, status + " " + statusText, "The tooltip status is incorrect.");
270 }
271 if (type !== undefined) {
272 let value = target.querySelector(".requests-menu-type").getAttribute("value");
273 let tooltip = target.querySelector(".requests-menu-type").getAttribute("tooltiptext");
274 info("Displayed type: " + value);
275 info("Tooltip type: " + tooltip);
276 is(value, type, "The displayed type is incorrect.");
277 is(tooltip, fullMimeType, "The tooltip type is incorrect.");
278 }
279 if (size !== undefined) {
280 let value = target.querySelector(".requests-menu-size").getAttribute("value");
281 let tooltip = target.querySelector(".requests-menu-size").getAttribute("tooltiptext");
282 info("Displayed size: " + value);
283 info("Tooltip size: " + tooltip);
284 is(value, size, "The displayed size is incorrect.");
285 is(tooltip, size, "The tooltip size is incorrect.");
286 }
287 if (time !== undefined) {
288 let value = target.querySelector(".requests-menu-timings-total").getAttribute("value");
289 let tooltip = target.querySelector(".requests-menu-timings-total").getAttribute("tooltiptext");
290 info("Displayed time: " + value);
291 info("Tooltip time: " + tooltip);
292 ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is incorrect.");
293 ok(~~(tooltip.match(/[0-9]+/)) >= 0, "The tooltip time is incorrect.");
294 }
295
296 if (visibleIndex != -1) {
297 if (visibleIndex % 2 == 0) {
298 ok(aRequestItem.target.hasAttribute("even"),
299 "Unexpected 'even' attribute for " + aRequestItem.value);
300 ok(!aRequestItem.target.hasAttribute("odd"),
301 "Unexpected 'odd' attribute for " + aRequestItem.value);
302 } else {
303 ok(!aRequestItem.target.hasAttribute("even"),
304 "Unexpected 'even' attribute for " + aRequestItem.value);
305 ok(aRequestItem.target.hasAttribute("odd"),
306 "Unexpected 'odd' attribute for " + aRequestItem.value);
307 }
308 }
309 }
310
311 /**
312 * Helper function for waiting for an event to fire before resolving a promise.
313 * Example: waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED);
314 *
315 * @param object subject
316 * The event emitter object that is being listened to.
317 * @param string eventName
318 * The name of the event to listen to.
319 * @return object
320 * Returns a promise that resolves upon firing of the event.
321 */
322 function waitFor (subject, eventName) {
323 let deferred = promise.defer();
324 subject.once(eventName, deferred.resolve);
325 return deferred.promise;
326 }
327
328 /**
329 * Tests if a button for a filter of given type is the only one checked.
330 *
331 * @param string aFilterType
332 * The type of the filter that should be the only one checked.
333 */
334 function testFilterButtons(aMonitor, aFilterType) {
335 let doc = aMonitor.panelWin.document;
336 let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
337 let buttons = doc.querySelectorAll(".requests-menu-footer-button");
338
339 // Only target should be checked.
340 let checkStatus = [(button == target) ? 1 : 0 for (button of buttons)]
341 testFilterButtonsCustom(aMonitor, checkStatus);
342 }
343
344 /**
345 * Tests if filter buttons have 'checked' attributes set correctly.
346 *
347 * @param array aIsChecked
348 * An array specifying if a button at given index should have a
349 * 'checked' attribute. For example, if the third item of the array
350 * evaluates to true, the third button should be checked.
351 */
352 function testFilterButtonsCustom(aMonitor, aIsChecked) {
353 let doc = aMonitor.panelWin.document;
354 let buttons = doc.querySelectorAll(".requests-menu-footer-button");
355 for (let i = 0; i < aIsChecked.length; i++) {
356 let button = buttons[i];
357 if (aIsChecked[i]) {
358 is(button.hasAttribute("checked"), true,
359 "The " + button.id + " button should have a 'checked' attribute.");
360 } else {
361 is(button.hasAttribute("checked"), false,
362 "The " + button.id + " button should not have a 'checked' attribute.");
363 }
364 }
365 }

mercurial