browser/devtools/netmonitor/test/head.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/devtools/netmonitor/test/head.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,365 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 +   http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +"use strict";
     1.7 +
     1.8 +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
     1.9 +
    1.10 +let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
    1.11 +let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
    1.12 +let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
    1.13 +let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
    1.14 +let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
    1.15 +let { CurlUtils } = Cu.import("resource:///modules/devtools/Curl.jsm", {});
    1.16 +let TargetFactory = devtools.TargetFactory;
    1.17 +let Toolbox = devtools.Toolbox;
    1.18 +
    1.19 +const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";
    1.20 +
    1.21 +const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
    1.22 +const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
    1.23 +const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
    1.24 +const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
    1.25 +const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
    1.26 +const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
    1.27 +const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
    1.28 +const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
    1.29 +const POST_RAW_WITH_HEADERS_URL = EXAMPLE_URL + "html_post-raw-with-headers-test-page.html";
    1.30 +const PARAMS_URL = EXAMPLE_URL + "html_params-test-page.html";
    1.31 +const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
    1.32 +const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
    1.33 +const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
    1.34 +const JSON_CUSTOM_MIME_URL = EXAMPLE_URL + "html_json-custom-mime-test-page.html";
    1.35 +const JSON_TEXT_MIME_URL = EXAMPLE_URL + "html_json-text-mime-test-page.html";
    1.36 +const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
    1.37 +const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
    1.38 +const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";
    1.39 +const CUSTOM_GET_URL = EXAMPLE_URL + "html_custom-get-page.html";
    1.40 +const SINGLE_GET_URL = EXAMPLE_URL + "html_single-get-page.html";
    1.41 +const STATISTICS_URL = EXAMPLE_URL + "html_statistics-test-page.html";
    1.42 +const CURL_URL = EXAMPLE_URL + "html_copy-as-curl.html";
    1.43 +const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html";
    1.44 +
    1.45 +const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
    1.46 +const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
    1.47 +const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
    1.48 +const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
    1.49 +
    1.50 +const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
    1.51 +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==";
    1.52 +
    1.53 +gDevTools.testing = true;
    1.54 +SimpleTest.registerCleanupFunction(() => {
    1.55 +  gDevTools.testing = false;
    1.56 +});
    1.57 +
    1.58 +// All tests are asynchronous.
    1.59 +waitForExplicitFinish();
    1.60 +
    1.61 +const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
    1.62 +// To enable logging for try runs, just set the pref to true.
    1.63 +Services.prefs.setBoolPref("devtools.debugger.log", false);
    1.64 +
    1.65 +// Always reset some prefs to their original values after the test finishes.
    1.66 +const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters");
    1.67 +
    1.68 +registerCleanupFunction(() => {
    1.69 +  info("finish() was called, cleaning up...");
    1.70 +
    1.71 +  Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
    1.72 +  Services.prefs.setCharPref("devtools.netmonitor.filters", gDefaultFilters);
    1.73 +});
    1.74 +
    1.75 +function addTab(aUrl, aWindow) {
    1.76 +  info("Adding tab: " + aUrl);
    1.77 +
    1.78 +  let deferred = promise.defer();
    1.79 +  let targetWindow = aWindow || window;
    1.80 +  let targetBrowser = targetWindow.gBrowser;
    1.81 +
    1.82 +  targetWindow.focus();
    1.83 +  let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
    1.84 +  let browser = tab.linkedBrowser;
    1.85 +
    1.86 +  browser.addEventListener("load", function onLoad() {
    1.87 +    browser.removeEventListener("load", onLoad, true);
    1.88 +    deferred.resolve(tab);
    1.89 +  }, true);
    1.90 +
    1.91 +  return deferred.promise;
    1.92 +}
    1.93 +
    1.94 +function removeTab(aTab, aWindow) {
    1.95 +  info("Removing tab.");
    1.96 +
    1.97 +  let targetWindow = aWindow || window;
    1.98 +  let targetBrowser = targetWindow.gBrowser;
    1.99 +
   1.100 +  targetBrowser.removeTab(aTab);
   1.101 +}
   1.102 +
   1.103 +function initNetMonitor(aUrl, aWindow) {
   1.104 +  info("Initializing a network monitor pane.");
   1.105 +
   1.106 +  return addTab(aUrl).then((aTab) => {
   1.107 +    info("Net tab added successfully: " + aUrl);
   1.108 +
   1.109 +    let deferred = promise.defer();
   1.110 +    let debuggee = aTab.linkedBrowser.contentWindow.wrappedJSObject;
   1.111 +    let target = TargetFactory.forTab(aTab);
   1.112 +
   1.113 +    gDevTools.showToolbox(target, "netmonitor").then((aToolbox) => {
   1.114 +      info("Netork monitor pane shown successfully.");
   1.115 +
   1.116 +      let monitor = aToolbox.getCurrentPanel();
   1.117 +      deferred.resolve([aTab, debuggee, monitor]);
   1.118 +    });
   1.119 +
   1.120 +    return deferred.promise;
   1.121 +  });
   1.122 +}
   1.123 +
   1.124 +function restartNetMonitor(aMonitor, aNewUrl) {
   1.125 +  info("Restarting the specified network monitor.");
   1.126 +
   1.127 +  let deferred = promise.defer();
   1.128 +  let tab = aMonitor.target.tab;
   1.129 +  let url = aNewUrl || tab.linkedBrowser.contentWindow.wrappedJSObject.location.href;
   1.130 +
   1.131 +  aMonitor.once("destroyed", () => initNetMonitor(url).then(deferred.resolve));
   1.132 +  removeTab(tab);
   1.133 +
   1.134 +  return deferred.promise;
   1.135 +}
   1.136 +
   1.137 +function teardown(aMonitor) {
   1.138 +  info("Destroying the specified network monitor.");
   1.139 +
   1.140 +  let deferred = promise.defer();
   1.141 +  let tab = aMonitor.target.tab;
   1.142 +
   1.143 +  aMonitor.once("destroyed", () => executeSoon(deferred.resolve));
   1.144 +  removeTab(tab);
   1.145 +
   1.146 +  return deferred.promise;
   1.147 +}
   1.148 +
   1.149 +function waitForNetworkEvents(aMonitor, aGetRequests, aPostRequests = 0) {
   1.150 +  let deferred = promise.defer();
   1.151 +
   1.152 +  let panel = aMonitor.panelWin;
   1.153 +  let genericEvents = 0;
   1.154 +  let postEvents = 0;
   1.155 +
   1.156 +  function onGenericEvent() {
   1.157 +    genericEvents++;
   1.158 +    maybeResolve();
   1.159 +  }
   1.160 +
   1.161 +  function onPostEvent() {
   1.162 +    postEvents++;
   1.163 +    maybeResolve();
   1.164 +  }
   1.165 +
   1.166 +  function maybeResolve() {
   1.167 +    info("> Network events progress: " +
   1.168 +      genericEvents + "/" + ((aGetRequests + aPostRequests) * 13) + ", " +
   1.169 +      postEvents + "/" + (aPostRequests * 2));
   1.170 +
   1.171 +    // There are 15 updates which need to be fired for a request to be
   1.172 +    // considered finished. RequestPostData isn't fired for non-POST requests.
   1.173 +    if (genericEvents == (aGetRequests + aPostRequests) * 13 &&
   1.174 +        postEvents == aPostRequests * 2) {
   1.175 +
   1.176 +      panel.off(panel.EVENTS.UPDATING_REQUEST_HEADERS, onGenericEvent);
   1.177 +      panel.off(panel.EVENTS.RECEIVED_REQUEST_HEADERS, onGenericEvent);
   1.178 +      panel.off(panel.EVENTS.UPDATING_REQUEST_COOKIES, onGenericEvent);
   1.179 +      panel.off(panel.EVENTS.RECEIVED_REQUEST_COOKIES, onGenericEvent);
   1.180 +      panel.off(panel.EVENTS.UPDATING_REQUEST_POST_DATA, onPostEvent);
   1.181 +      panel.off(panel.EVENTS.RECEIVED_REQUEST_POST_DATA, onPostEvent);
   1.182 +      panel.off(panel.EVENTS.UPDATING_RESPONSE_HEADERS, onGenericEvent);
   1.183 +      panel.off(panel.EVENTS.RECEIVED_RESPONSE_HEADERS, onGenericEvent);
   1.184 +      panel.off(panel.EVENTS.UPDATING_RESPONSE_COOKIES, onGenericEvent);
   1.185 +      panel.off(panel.EVENTS.RECEIVED_RESPONSE_COOKIES, onGenericEvent);
   1.186 +      panel.off(panel.EVENTS.STARTED_RECEIVING_RESPONSE, onGenericEvent);
   1.187 +      panel.off(panel.EVENTS.UPDATING_RESPONSE_CONTENT, onGenericEvent);
   1.188 +      panel.off(panel.EVENTS.RECEIVED_RESPONSE_CONTENT, onGenericEvent);
   1.189 +      panel.off(panel.EVENTS.UPDATING_EVENT_TIMINGS, onGenericEvent);
   1.190 +      panel.off(panel.EVENTS.RECEIVED_EVENT_TIMINGS, onGenericEvent);
   1.191 +
   1.192 +      executeSoon(deferred.resolve);
   1.193 +    }
   1.194 +  }
   1.195 +
   1.196 +  panel.on(panel.EVENTS.UPDATING_REQUEST_HEADERS, onGenericEvent);
   1.197 +  panel.on(panel.EVENTS.RECEIVED_REQUEST_HEADERS, onGenericEvent);
   1.198 +  panel.on(panel.EVENTS.UPDATING_REQUEST_COOKIES, onGenericEvent);
   1.199 +  panel.on(panel.EVENTS.RECEIVED_REQUEST_COOKIES, onGenericEvent);
   1.200 +  panel.on(panel.EVENTS.UPDATING_REQUEST_POST_DATA, onPostEvent);
   1.201 +  panel.on(panel.EVENTS.RECEIVED_REQUEST_POST_DATA, onPostEvent);
   1.202 +  panel.on(panel.EVENTS.UPDATING_RESPONSE_HEADERS, onGenericEvent);
   1.203 +  panel.on(panel.EVENTS.RECEIVED_RESPONSE_HEADERS, onGenericEvent);
   1.204 +  panel.on(panel.EVENTS.UPDATING_RESPONSE_COOKIES, onGenericEvent);
   1.205 +  panel.on(panel.EVENTS.RECEIVED_RESPONSE_COOKIES, onGenericEvent);
   1.206 +  panel.on(panel.EVENTS.STARTED_RECEIVING_RESPONSE, onGenericEvent);
   1.207 +  panel.on(panel.EVENTS.UPDATING_RESPONSE_CONTENT, onGenericEvent);
   1.208 +  panel.on(panel.EVENTS.RECEIVED_RESPONSE_CONTENT, onGenericEvent);
   1.209 +  panel.on(panel.EVENTS.UPDATING_EVENT_TIMINGS, onGenericEvent);
   1.210 +  panel.on(panel.EVENTS.RECEIVED_EVENT_TIMINGS, onGenericEvent);
   1.211 +
   1.212 +  return deferred.promise;
   1.213 +}
   1.214 +
   1.215 +function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
   1.216 +  info("> Verifying: " + aMethod + " " + aUrl + " " + aData.toSource());
   1.217 +  // This bloats log sizes significantly in automation (bug 992485)
   1.218 +  //info("> Request: " + aRequestItem.attachment.toSource());
   1.219 +
   1.220 +  let requestsMenu = aRequestItem.ownerView;
   1.221 +  let widgetIndex = requestsMenu.indexOfItem(aRequestItem);
   1.222 +  let visibleIndex = requestsMenu.visibleItems.indexOf(aRequestItem);
   1.223 +
   1.224 +  info("Widget index of item: " + widgetIndex);
   1.225 +  info("Visible index of item: " + visibleIndex);
   1.226 +
   1.227 +  let { fuzzyUrl, status, statusText, type, fullMimeType, size, time } = aData;
   1.228 +  let { attachment, target } = aRequestItem
   1.229 +
   1.230 +  let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
   1.231 +  let name = uri.fileName || "/";
   1.232 +  let query = uri.query;
   1.233 +  let hostPort = uri.hostPort;
   1.234 +
   1.235 +  if (fuzzyUrl) {
   1.236 +    ok(attachment.method.startsWith(aMethod), "The attached method is incorrect.");
   1.237 +    ok(attachment.url.startsWith(aUrl), "The attached url is incorrect.");
   1.238 +  } else {
   1.239 +    is(attachment.method, aMethod, "The attached method is incorrect.");
   1.240 +    is(attachment.url, aUrl, "The attached url is incorrect.");
   1.241 +  }
   1.242 +
   1.243 +  is(target.querySelector(".requests-menu-method").getAttribute("value"),
   1.244 +    aMethod, "The displayed method is incorrect.");
   1.245 +
   1.246 +  if (fuzzyUrl) {
   1.247 +    ok(target.querySelector(".requests-menu-file").getAttribute("value").startsWith(
   1.248 +      name + (query ? "?" + query : "")), "The displayed file is incorrect.");
   1.249 +    ok(target.querySelector(".requests-menu-file").getAttribute("tooltiptext").startsWith(
   1.250 +      name + (query ? "?" + query : "")), "The tooltip file is incorrect.");
   1.251 +  } else {
   1.252 +    is(target.querySelector(".requests-menu-file").getAttribute("value"),
   1.253 +      name + (query ? "?" + query : ""), "The displayed file is incorrect.");
   1.254 +    is(target.querySelector(".requests-menu-file").getAttribute("tooltiptext"),
   1.255 +      name + (query ? "?" + query : ""), "The tooltip file is incorrect.");
   1.256 +  }
   1.257 +
   1.258 +  is(target.querySelector(".requests-menu-domain").getAttribute("value"),
   1.259 +    hostPort, "The displayed domain is incorrect.");
   1.260 +  is(target.querySelector(".requests-menu-domain").getAttribute("tooltiptext"),
   1.261 +    hostPort, "The tooltip domain is incorrect.");
   1.262 +
   1.263 +  if (status !== undefined) {
   1.264 +    let value = target.querySelector(".requests-menu-status").getAttribute("code");
   1.265 +    let codeValue = target.querySelector(".requests-menu-status-code").getAttribute("value");
   1.266 +    let tooltip = target.querySelector(".requests-menu-status-and-method").getAttribute("tooltiptext");
   1.267 +    info("Displayed status: " + value);
   1.268 +    info("Displayed code: " + codeValue);
   1.269 +    info("Tooltip status: " + tooltip);
   1.270 +    is(value, status, "The displayed status is incorrect.");
   1.271 +    is(codeValue, status, "The displayed status code is incorrect.");
   1.272 +    is(tooltip, status + " " + statusText, "The tooltip status is incorrect.");
   1.273 +  }
   1.274 +  if (type !== undefined) {
   1.275 +    let value = target.querySelector(".requests-menu-type").getAttribute("value");
   1.276 +    let tooltip = target.querySelector(".requests-menu-type").getAttribute("tooltiptext");
   1.277 +    info("Displayed type: " + value);
   1.278 +    info("Tooltip type: " + tooltip);
   1.279 +    is(value, type, "The displayed type is incorrect.");
   1.280 +    is(tooltip, fullMimeType, "The tooltip type is incorrect.");
   1.281 +  }
   1.282 +  if (size !== undefined) {
   1.283 +    let value = target.querySelector(".requests-menu-size").getAttribute("value");
   1.284 +    let tooltip = target.querySelector(".requests-menu-size").getAttribute("tooltiptext");
   1.285 +    info("Displayed size: " + value);
   1.286 +    info("Tooltip size: " + tooltip);
   1.287 +    is(value, size, "The displayed size is incorrect.");
   1.288 +    is(tooltip, size, "The tooltip size is incorrect.");
   1.289 +  }
   1.290 +  if (time !== undefined) {
   1.291 +    let value = target.querySelector(".requests-menu-timings-total").getAttribute("value");
   1.292 +    let tooltip = target.querySelector(".requests-menu-timings-total").getAttribute("tooltiptext");
   1.293 +    info("Displayed time: " + value);
   1.294 +    info("Tooltip time: " + tooltip);
   1.295 +    ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is incorrect.");
   1.296 +    ok(~~(tooltip.match(/[0-9]+/)) >= 0, "The tooltip time is incorrect.");
   1.297 +  }
   1.298 +
   1.299 +  if (visibleIndex != -1) {
   1.300 +    if (visibleIndex % 2 == 0) {
   1.301 +      ok(aRequestItem.target.hasAttribute("even"),
   1.302 +        "Unexpected 'even' attribute for " + aRequestItem.value);
   1.303 +      ok(!aRequestItem.target.hasAttribute("odd"),
   1.304 +        "Unexpected 'odd' attribute for " + aRequestItem.value);
   1.305 +    } else {
   1.306 +      ok(!aRequestItem.target.hasAttribute("even"),
   1.307 +        "Unexpected 'even' attribute for " + aRequestItem.value);
   1.308 +      ok(aRequestItem.target.hasAttribute("odd"),
   1.309 +        "Unexpected 'odd' attribute for " + aRequestItem.value);
   1.310 +    }
   1.311 +  }
   1.312 +}
   1.313 +
   1.314 +/**
   1.315 + * Helper function for waiting for an event to fire before resolving a promise.
   1.316 + * Example: waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED);
   1.317 + *
   1.318 + * @param object subject
   1.319 + *        The event emitter object that is being listened to.
   1.320 + * @param string eventName
   1.321 + *        The name of the event to listen to.
   1.322 + * @return object
   1.323 + *        Returns a promise that resolves upon firing of the event.
   1.324 + */
   1.325 +function waitFor (subject, eventName) {
   1.326 +  let deferred = promise.defer();
   1.327 +  subject.once(eventName, deferred.resolve);
   1.328 +  return deferred.promise;
   1.329 +}
   1.330 +
   1.331 +/**
   1.332 + * Tests if a button for a filter of given type is the only one checked.
   1.333 + *
   1.334 + * @param string aFilterType
   1.335 + *        The type of the filter that should be the only one checked.
   1.336 + */
   1.337 +function testFilterButtons(aMonitor, aFilterType) {
   1.338 +  let doc = aMonitor.panelWin.document;
   1.339 +  let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
   1.340 +  let buttons = doc.querySelectorAll(".requests-menu-footer-button");
   1.341 +
   1.342 +  // Only target should be checked.
   1.343 +  let checkStatus = [(button == target) ? 1 : 0 for (button of buttons)]
   1.344 +  testFilterButtonsCustom(aMonitor, checkStatus);
   1.345 +}
   1.346 +
   1.347 +/**
   1.348 + * Tests if filter buttons have 'checked' attributes set correctly.
   1.349 + *
   1.350 + * @param array aIsChecked
   1.351 + *        An array specifying if a button at given index should have a
   1.352 + *        'checked' attribute. For example, if the third item of the array
   1.353 + *        evaluates to true, the third button should be checked.
   1.354 + */
   1.355 +function testFilterButtonsCustom(aMonitor, aIsChecked) {
   1.356 +  let doc = aMonitor.panelWin.document;
   1.357 +  let buttons = doc.querySelectorAll(".requests-menu-footer-button");
   1.358 +  for (let i = 0; i < aIsChecked.length; i++) {
   1.359 +    let button = buttons[i];
   1.360 +    if (aIsChecked[i]) {
   1.361 +      is(button.hasAttribute("checked"), true,
   1.362 +        "The " + button.id + " button should have a 'checked' attribute.");
   1.363 +    } else {
   1.364 +      is(button.hasAttribute("checked"), false,
   1.365 +        "The " + button.id + " button should not have a 'checked' attribute.");
   1.366 +    }
   1.367 +  }
   1.368 +}

mercurial