From f9aac2edf0e5b86a3c805293a692f7f134426204 Mon Sep 17 00:00:00 2001 From: Jordan Santell Date: Mon, 2 Dec 2013 11:34:47 -0500 Subject: [PATCH] Bug 940538 - Convert network monitor to use Promise.jsm. r=benvie, r=vp --- .../netmonitor/netmonitor-controller.js | 19 +- .../devtools/netmonitor/netmonitor-panel.js | 2 +- .../devtools/netmonitor/netmonitor-view.js | 190 +++++++++++------- .../test/browser_net_content-type.js | 54 ++--- .../test/browser_net_cyrillic-01.js | 5 +- .../test/browser_net_cyrillic-02.js | 5 +- .../test/browser_net_json-malformed.js | 59 +++--- .../test/browser_net_json_custom_mime.js | 7 +- .../netmonitor/test/browser_net_jsonp.js | 7 +- .../test/browser_net_post-data-01.js | 16 +- .../test/browser_net_post-data-02.js | 62 +++--- .../netmonitor/test/browser_net_resend.js | 34 ++-- .../browser_net_simple-request-details.js | 53 ++--- browser/devtools/netmonitor/test/head.js | 20 +- 14 files changed, 318 insertions(+), 215 deletions(-) diff --git a/browser/devtools/netmonitor/netmonitor-controller.js b/browser/devtools/netmonitor/netmonitor-controller.js index 143bffe1e1d8..ba38e1758658 100644 --- a/browser/devtools/netmonitor/netmonitor-controller.js +++ b/browser/devtools/netmonitor/netmonitor-controller.js @@ -55,17 +55,30 @@ const EVENTS = { REQUEST_POST_PARAMS_DISPLAYED: "NetMonitor:RequestPostParamsAvailable", // When the response body is displayed in the UI. - RESPONSE_BODY_DISPLAYED: "NetMonitor:ResponseBodyAvailable" -} + RESPONSE_BODY_DISPLAYED: "NetMonitor:ResponseBodyAvailable", + + // When `onTabSelect` is fired and subsequently rendered + TAB_UPDATED: "NetMonitor:TabUpdated", + + // Fired when Sidebar is finished being populated + SIDEBAR_POPULATED: "NetMonitor:SidebarPopulated", + + // Fired when NetworkDetailsView is finished being populated + NETWORKDETAILSVIEW_POPULATED: "NetMonitor:NetworkDetailsViewPopulated", + + // Fired when NetworkDetailsView is finished being populated + CUSTOMREQUESTVIEW_POPULATED: "NetMonitor:CustomRequestViewPopulated" +}; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise; +Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource:///modules/devtools/shared/event-emitter.js"); Cu.import("resource:///modules/devtools/SideMenuWidget.jsm"); Cu.import("resource:///modules/devtools/VariablesView.jsm"); Cu.import("resource:///modules/devtools/VariablesViewController.jsm"); Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); +const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; const Editor = require("devtools/sourceeditor/editor"); diff --git a/browser/devtools/netmonitor/netmonitor-panel.js b/browser/devtools/netmonitor/netmonitor-panel.js index 5f5991e3bebc..1efb4c409282 100644 --- a/browser/devtools/netmonitor/netmonitor-panel.js +++ b/browser/devtools/netmonitor/netmonitor-panel.js @@ -6,7 +6,7 @@ "use strict"; const { Cc, Ci, Cu, Cr } = require("chrome"); -const promise = require("sdk/core/promise"); +const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); const EventEmitter = require("devtools/shared/event-emitter"); function NetMonitorPanel(iframeWindow, toolbox) { diff --git a/browser/devtools/netmonitor/netmonitor-view.js b/browser/devtools/netmonitor/netmonitor-view.js index 6cca63cfe007..54692152cec9 100644 --- a/browser/devtools/netmonitor/netmonitor-view.js +++ b/browser/devtools/netmonitor/netmonitor-view.js @@ -1382,15 +1382,19 @@ SidebarView.prototype = { * * @param object aData * The data source (this should be the attachment of a request item). + * @return object + * Returns a promise that resolves upon population of the subview. */ populate: function(aData) { - if (aData.isCustom) { - NetMonitorView.CustomRequest.populate(aData); - $("#details-pane").selectedIndex = 0; - } else { - NetMonitorView.NetworkDetails.populate(aData); - $("#details-pane").selectedIndex = 1; - } + let isCustom = aData.isCustom; + let view = isCustom ? + NetMonitorView.CustomRequest : + NetMonitorView.NetworkDetails; + + return view.populate(aData).then(() => { + $("#details-pane").selectedIndex = isCustom ? 0 : 1 + window.emit(EVENTS.SIDEBAR_POPULATED) + }); }, /** @@ -1414,6 +1418,8 @@ CustomRequestView.prototype = { * * @param object aData * The data source (this should be the attachment of a request item). + * @return object + * Returns a promise that resolves upon population the view. */ populate: function(aData) { $("#custom-url-value").value = aData.url; @@ -1421,15 +1427,22 @@ CustomRequestView.prototype = { $("#custom-headers-value").value = writeHeaderText(aData.requestHeaders.headers); + let view = this; + let postDataPromise = null; + if (aData.requestPostData) { let body = aData.requestPostData.postData.text; - gNetwork.getString(body).then(aString => { + postDataPromise = gNetwork.getString(body).then(aString => { $("#custom-postdata-value").value = aString; }); + } else { + postDataPromise = promise.resolve(); } - this.updateCustomQuery(aData.url); + return postDataPromise + .then(() => view.updateCustomQuery(aData.url)) + .then(() => window.emit(EVENTS.CUSTOMREQUESTVIEW_POPULATED)); }, /** @@ -1584,6 +1597,8 @@ NetworkDetailsView.prototype = { * * @param object aData * The data source (this should be the attachment of a request item). + * @return object + * Returns a promise that resolves upon population the view. */ populate: function(aData) { $("#request-params-box").setAttribute("flex", "1"); @@ -1601,6 +1616,9 @@ NetworkDetailsView.prototype = { this._dataSrc = { src: aData, populated: [] }; this._onTabSelect(); + window.emit(EVENTS.NETWORKDETAILSVIEW_POPULATED); + + return promise.resolve(); }, /** @@ -1609,35 +1627,38 @@ NetworkDetailsView.prototype = { _onTabSelect: function() { let { src, populated } = this._dataSrc || {}; let tab = this.widget.selectedIndex; + let view = this; // Make sure the data source is valid and don't populate the same tab twice. if (!src || populated[tab]) { return; } - switch (tab) { - case 0: // "Headers" - this._setSummary(src); - this._setResponseHeaders(src.responseHeaders); - this._setRequestHeaders(src.requestHeaders); - break; - case 1: // "Cookies" - this._setResponseCookies(src.responseCookies); - this._setRequestCookies(src.requestCookies); - break; - case 2: // "Params" - this._setRequestGetParams(src.url); - this._setRequestPostParams(src.requestHeaders, src.requestPostData); - break; - case 3: // "Response" - this._setResponseBody(src.url, src.responseContent); - break; - case 4: // "Timings" - this._setTimingsInformation(src.eventTimings); - break; - } - - populated[tab] = true; + Task.spawn(function*() { + switch (tab) { + case 0: // "Headers" + yield view._setSummary(src); + yield view._setResponseHeaders(src.responseHeaders); + yield view._setRequestHeaders(src.requestHeaders); + break; + case 1: // "Cookies" + yield view._setResponseCookies(src.responseCookies); + yield view._setRequestCookies(src.requestCookies); + break; + case 2: // "Params" + yield view._setRequestGetParams(src.url); + yield view._setRequestPostParams(src.requestHeaders, src.requestPostData); + break; + case 3: // "Response" + yield view._setResponseBody(src.url, src.responseContent); + break; + case 4: // "Timings" + yield view._setTimingsInformation(src.eventTimings); + break; + } + populated[tab] = true; + window.emit(EVENTS.TAB_UPDATED); + }); }, /** @@ -1684,11 +1705,14 @@ NetworkDetailsView.prototype = { * * @param object aResponse * The message received from the server. + * @return object + * A promise that resolves when request headers are set. */ _setRequestHeaders: function(aResponse) { if (aResponse && aResponse.headers.length) { - this._addHeaders(this._requestHeaders, aResponse); + return this._addHeaders(this._requestHeaders, aResponse); } + return promise.resolve(); }, /** @@ -1696,12 +1720,15 @@ NetworkDetailsView.prototype = { * * @param object aResponse * The message received from the server. + * @return object + * A promise that resolves when response headers are set. */ _setResponseHeaders: function(aResponse) { if (aResponse && aResponse.headers.length) { aResponse.headers.sort((a, b) => a.name > b.name); - this._addHeaders(this._responseHeaders, aResponse); + return this._addHeaders(this._responseHeaders, aResponse); } + return promise.resolve(); }, /** @@ -1711,6 +1738,8 @@ NetworkDetailsView.prototype = { * The type of headers to populate (request or response). * @param object aResponse * The message received from the server. + * @return object + * A promise that resolves when headers are added. */ _addHeaders: function(aName, aResponse) { let kb = aResponse.headersSize / 1024; @@ -1719,10 +1748,11 @@ NetworkDetailsView.prototype = { let headersScope = this._headers.addScope(aName + " (" + text + ")"); headersScope.expanded = true; - for (let header of aResponse.headers) { + return promise.all(aResponse.headers.map(header => { let headerVar = headersScope.addItem(header.name, {}, true); - gNetwork.getString(header.value).then(aString => headerVar.setGrip(aString)); - } + return gNetwork.getString(header.value) + .then(aString => headerVar.setGrip(aString)); + })); }, /** @@ -1730,12 +1760,15 @@ NetworkDetailsView.prototype = { * * @param object aResponse * The message received from the server. + * @return object + * A promise that is resolved when the request cookies are set. */ _setRequestCookies: function(aResponse) { if (aResponse && aResponse.cookies.length) { aResponse.cookies.sort((a, b) => a.name > b.name); - this._addCookies(this._requestCookies, aResponse); + return this._addCookies(this._requestCookies, aResponse); } + return promise.resolve(); }, /** @@ -1743,11 +1776,14 @@ NetworkDetailsView.prototype = { * * @param object aResponse * The message received from the server. + * @return object + * A promise that is resolved when the response cookies are set. */ _setResponseCookies: function(aResponse) { if (aResponse && aResponse.cookies.length) { - this._addCookies(this._responseCookies, aResponse); + return this._addCookies(this._responseCookies, aResponse); } + return promise.resolve(); }, /** @@ -1757,33 +1793,37 @@ NetworkDetailsView.prototype = { * The type of cookies to populate (request or response). * @param object aResponse * The message received from the server. + * @return object + * Returns a promise that resolves upon the adding of cookies. */ _addCookies: function(aName, aResponse) { let cookiesScope = this._cookies.addScope(aName); cookiesScope.expanded = true; - for (let cookie of aResponse.cookies) { + return promise.all(aResponse.cookies.map(cookie => { let cookieVar = cookiesScope.addItem(cookie.name, {}, true); - gNetwork.getString(cookie.value).then(aString => cookieVar.setGrip(aString)); + return gNetwork.getString(cookie.value).then(aString => { + cookieVar.setGrip(aString); - // By default the cookie name and value are shown. If this is the only - // information available, then nothing else is to be displayed. - let cookieProps = Object.keys(cookie); - if (cookieProps.length == 2) { - continue; - } + // By default the cookie name and value are shown. If this is the only + // information available, then nothing else is to be displayed. + let cookieProps = Object.keys(cookie); + if (cookieProps.length == 2) { + return; + } - // Display any other information other than the cookie name and value - // which may be available. - let rawObject = Object.create(null); - let otherProps = cookieProps.filter(e => e != "name" && e != "value"); - for (let prop of otherProps) { - rawObject[prop] = cookie[prop]; - } - cookieVar.populate(rawObject); - cookieVar.twisty = true; - cookieVar.expanded = true; - } + // Display any other information other than the cookie name and value + // which may be available. + let rawObject = Object.create(null); + let otherProps = cookieProps.filter(e => e != "name" && e != "value"); + for (let prop of otherProps) { + rawObject[prop] = cookie[prop]; + } + cookieVar.populate(rawObject); + cookieVar.twisty = true; + cookieVar.expanded = true; + }); + })); }, /** @@ -1806,12 +1846,14 @@ NetworkDetailsView.prototype = { * The "requestHeaders" message received from the server. * @param object aPostDataResponse * The "requestPostData" message received from the server. + * @return object + * A promise that is resolved when the request post params are set. */ _setRequestPostParams: function(aHeadersResponse, aPostDataResponse) { if (!aHeadersResponse || !aPostDataResponse) { - return; + return promise.resolve(); } - gNetwork.getString(aPostDataResponse.postData.text).then(aString => { + return gNetwork.getString(aPostDataResponse.postData.text).then(aString => { // Handle query strings (poor man's forms, e.g. "?foo=bar&baz=42"). let cType = aHeadersResponse.headers.filter(({ name }) => name == "Content-Type")[0]; let cString = cType ? cType.value : ""; @@ -1833,12 +1875,11 @@ NetworkDetailsView.prototype = { paramsScope.locked = true; $("#request-post-data-textarea-box").hidden = false; - NetMonitorView.editor("#request-post-data-textarea").then(aEditor => { + return NetMonitorView.editor("#request-post-data-textarea").then(aEditor => { aEditor.setText(aString); }); } - window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED); - }); + }).then(() => window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED)); }, /** @@ -1870,14 +1911,16 @@ NetworkDetailsView.prototype = { * The request's url. * @param object aResponse * The message received from the server. + * @return object + * A promise that is resolved when the response body is set */ _setResponseBody: function(aUrl, aResponse) { if (!aResponse) { - return; + return promise.resolve(); } let { mimeType, text, encoding } = aResponse.content; - gNetwork.getString(text).then(aString => { + return gNetwork.getString(text).then(aString => { // Handle json, which we tentatively identify by checking the MIME type // for "json" after any word boundary. This works for the standard // "application/json", and also for custom types like "x-bigcorp-json". @@ -1903,22 +1946,22 @@ NetworkDetailsView.prototype = { ? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1)) : L10N.getStr("jsonScopeName"); - this._json.controller.setSingleVariable({ + return this._json.controller.setSingleVariable({ label: jsonScopeName, rawObject: jsonObject, - }); + }).expanded; } // Malformed JSON. else { $("#response-content-textarea-box").hidden = false; - NetMonitorView.editor("#response-content-textarea").then(aEditor => { - aEditor.setMode(Editor.modes.js); - aEditor.setText(aString); - }); let infoHeader = $("#response-content-info-header"); infoHeader.setAttribute("value", parsingError); infoHeader.setAttribute("tooltiptext", parsingError); infoHeader.hidden = false; + return NetMonitorView.editor("#response-content-textarea").then(aEditor => { + aEditor.setMode(Editor.modes.js); + aEditor.setText(aString); + }); } } // Handle images. @@ -1948,7 +1991,7 @@ NetworkDetailsView.prototype = { // Handle anything else. else { $("#response-content-textarea-box").hidden = false; - NetMonitorView.editor("#response-content-textarea").then(aEditor => { + return NetMonitorView.editor("#response-content-textarea").then(aEditor => { aEditor.setMode(Editor.modes.text); aEditor.setText(aString); @@ -1964,8 +2007,7 @@ NetworkDetailsView.prototype = { } }); } - window.emit(EVENTS.RESPONSE_BODY_DISPLAYED); - }); + }).then(() => window.emit(EVENTS.RESPONSE_BODY_DISPLAYED)); }, /** diff --git a/browser/devtools/netmonitor/test/browser_net_content-type.js b/browser/devtools/netmonitor/test/browser_net_content-type.js index bbec1d7c0e06..75d6cc0f301a 100644 --- a/browser/devtools/netmonitor/test/browser_net_content-type.js +++ b/browser/devtools/netmonitor/test/browser_net_content-type.js @@ -75,31 +75,27 @@ function test() { 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); + Task.spawn(function*() { + yield waitForResponseBodyDisplayed(); + yield testResponseTab("xml"); + RequestsMenu.selectedIndex = 1; + yield waitForTabUpdated(); + yield testResponseTab("css"); + RequestsMenu.selectedIndex = 2; + yield waitForTabUpdated(); + yield testResponseTab("js"); + RequestsMenu.selectedIndex = 3; + yield waitForTabUpdated(); + yield testResponseTab("json"); + RequestsMenu.selectedIndex = 4; + yield waitForTabUpdated(); + yield testResponseTab("html"); + RequestsMenu.selectedIndex = 5; + yield waitForTabUpdated(); + yield testResponseTab("png"); + yield teardown(aMonitor); + finish(); + }); function testResponseTab(aType) { let tab = document.querySelectorAll("#details-pane tab")[3]; @@ -221,6 +217,14 @@ function test() { } } } + + function waitForTabUpdated () { + return waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED); + } + + function waitForResponseBodyDisplayed () { + return waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED); + } }); aDebuggee.performRequests(); diff --git a/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js b/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js index 31180dcf0551..3bf6a97f23a7 100644 --- a/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js +++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js @@ -26,7 +26,10 @@ function test() { EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - NetMonitorView.editor("#response-content-textarea").then((aEditor) => { + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() => + 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(), Editor.modes.text, diff --git a/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js b/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js index fd31e5fd8bf3..4fc8020d7241 100644 --- a/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js +++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js @@ -27,7 +27,10 @@ function test() { EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - NetMonitorView.editor("#response-content-textarea").then((aEditor) => { + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() => + NetMonitorView.editor("#response-content-textarea") + ).then((aEditor) => { is(aEditor.getText().indexOf("\u044F"), 302, // я "The text shown in the source editor is incorrect."); is(aEditor.getMode(), Editor.modes.html, diff --git a/browser/devtools/netmonitor/test/browser_net_json-malformed.js b/browser/devtools/netmonitor/test/browser_net_json-malformed.js index 4115ec3ed9b2..e1c75870d829 100644 --- a/browser/devtools/netmonitor/test/browser_net_json-malformed.js +++ b/browser/devtools/netmonitor/test/browser_net_json-malformed.js @@ -31,38 +31,41 @@ function test() { 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."); + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() => { + 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-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."); + 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(), Editor.modes.js, - "The mode active in the source editor is incorrect."); + 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(), Editor.modes.js, + "The mode active in the source editor is incorrect."); - teardown(aMonitor).then(finish); + teardown(aMonitor).then(finish); + }); }); }); diff --git a/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js b/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js index 0faa71490651..340c3307e2a4 100644 --- a/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js +++ b/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js @@ -30,8 +30,11 @@ function test() { EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - testResponseTab(); - teardown(aMonitor).then(finish); + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED) + .then(testResponseTab) + .then(() => teardown(aMonitor)) + .then(finish); function testResponseTab() { let tab = document.querySelectorAll("#details-pane tab")[3]; diff --git a/browser/devtools/netmonitor/test/browser_net_jsonp.js b/browser/devtools/netmonitor/test/browser_net_jsonp.js index a089bb58096f..f7b850d02eda 100644 --- a/browser/devtools/netmonitor/test/browser_net_jsonp.js +++ b/browser/devtools/netmonitor/test/browser_net_jsonp.js @@ -30,8 +30,11 @@ function test() { EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - testResponseTab(); - teardown(aMonitor).then(finish); + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED) + .then(testResponseTab) + .then(() => teardown(aMonitor)) + .then(finish); function testResponseTab() { let tab = document.querySelectorAll("#details-pane tab")[3]; diff --git a/browser/devtools/netmonitor/test/browser_net_post-data-01.js b/browser/devtools/netmonitor/test/browser_net_post-data-01.js index 0607279fdb0c..661606174d53 100644 --- a/browser/devtools/netmonitor/test/browser_net_post-data-01.js +++ b/browser/devtools/netmonitor/test/browser_net_post-data-01.js @@ -40,14 +40,14 @@ function test() { EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[2]); - testParamsTab("urlencoded") - .then(() => { - RequestsMenu.selectedIndex = 1; - return testParamsTab("multipart"); - }) - .then(() => { - return teardown(aMonitor); - }) + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; + waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => + testParamsTab("urlencoded") + ).then(() => { + RequestsMenu.selectedIndex = 1; + return waitFor(aMonitor.panelWin, TAB_UPDATED); + }).then(() => testParamsTab("multipart")) + .then(() => teardown(aMonitor)) .then(finish); function testParamsTab(aType) { diff --git a/browser/devtools/netmonitor/test/browser_net_post-data-02.js b/browser/devtools/netmonitor/test/browser_net_post-data-02.js index ea3c175e213e..3685cab8c85a 100644 --- a/browser/devtools/netmonitor/test/browser_net_post-data-02.js +++ b/browser/devtools/netmonitor/test/browser_net_post-data-02.js @@ -20,41 +20,43 @@ function test() { NetMonitorView.toggleDetailsPane({ visible: true }, 2) RequestsMenu.selectedIndex = 0; - let tab = document.querySelectorAll("#event-details-pane tab")[2]; - let tabpanel = document.querySelectorAll("#event-details-pane tabpanel")[2]; + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; + waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => { + let tab = document.querySelectorAll("#event-details-pane tab")[2]; + let tabpanel = document.querySelectorAll("#event-details-pane tabpanel")[2]; - is(tab.getAttribute("selected"), "true", - "The params tab in the network details pane should be selected."); + 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.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."); + 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."); + 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); + 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_resend.js b/browser/devtools/netmonitor/test/browser_net_resend.js index 2d9b52acd9b9..cb3f196e981e 100644 --- a/browser/devtools/netmonitor/test/browser_net_resend.js +++ b/browser/devtools/netmonitor/test/browser_net_resend.js @@ -21,6 +21,8 @@ function test() { let { NetMonitorView } = gPanelWin; let { RequestsMenu } = NetMonitorView; + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; + let CUSTOMREQUESTVIEW_POPULATED = aMonitor.panelWin.EVENTS.CUSTOMREQUESTVIEW_POPULATED; RequestsMenu.lazyUpdate = false; @@ -28,24 +30,28 @@ function test() { let origItem = RequestsMenu.getItemAtIndex(0); RequestsMenu.selectedItem = origItem; - // add a new custom request cloned from selected request - RequestsMenu.cloneSelectedRequest(); - testCustomForm(origItem.attachment); + waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => { + // add a new custom request cloned from selected request + RequestsMenu.cloneSelectedRequest(); + return waitFor(aMonitor.panelWin, CUSTOMREQUESTVIEW_POPULATED); + }).then(() => { + testCustomForm(origItem.attachment); - let customItem = RequestsMenu.selectedItem; - testCustomItem(customItem, origItem); + let customItem = RequestsMenu.selectedItem; + testCustomItem(customItem, origItem); - // edit the custom request - editCustomForm(() => { - testCustomItemChanged(customItem, origItem); + // edit the custom request + editCustomForm(() => { + testCustomItemChanged(customItem, origItem); - waitForNetworkEvents(aMonitor, 0, 1).then(() => { - let sentItem = RequestsMenu.selectedItem; - testSentRequest(sentItem.attachment, origItem.attachment); - finishUp(aMonitor); + waitForNetworkEvents(aMonitor, 0, 1).then(() => { + let sentItem = RequestsMenu.selectedItem; + testSentRequest(sentItem.attachment, origItem.attachment); + finishUp(aMonitor); + }); + // send the new request + RequestsMenu.sendCustomRequest(); }); - // send the new request - RequestsMenu.sendCustomRequest(); }); }); diff --git a/browser/devtools/netmonitor/test/browser_net_simple-request-details.js b/browser/devtools/netmonitor/test/browser_net_simple-request-details.js index 948025d3a1d7..af9850608c3e 100644 --- a/browser/devtools/netmonitor/test/browser_net_simple-request-details.js +++ b/browser/devtools/netmonitor/test/browser_net_simple-request-details.js @@ -11,10 +11,11 @@ function test() { let { document, L10N, Editor, NetMonitorView } = aMonitor.panelWin; let { RequestsMenu, NetworkDetails } = NetMonitorView; - + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; RequestsMenu.lazyUpdate = false; - waitForNetworkEvents(aMonitor, 1).then(() => { + Task.spawn(function () { + yield waitForNetworkEvents(aMonitor, 1); is(RequestsMenu.selectedItem, null, "There shouldn't be any selected item in the requests menu."); is(RequestsMenu.itemCount, 1, @@ -32,15 +33,14 @@ function test() { is(NetMonitorView.detailsPaneHidden, false, "The details pane should not be hidden after toggle button was pressed."); + yield waitFor(aMonitor.panelWin, TAB_UPDATED) testHeadersTab(); testCookiesTab(); testParamsTab(); - testResponseTab() - .then(() => { - testTimingsTab(); - return teardown(aMonitor); - }) - .then(finish); + yield testResponseTab(); + testTimingsTab(); + yield teardown(aMonitor); + finish(); }); function testHeadersTab() { @@ -172,26 +172,29 @@ function test() { 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]; + return Task.spawn(function () { + yield waitFor(aMonitor.panelWin, TAB_UPDATED); - is(tab.getAttribute("selected"), "true", - "The response tab in the network details pane should be selected."); + let tab = document.querySelectorAll("#details-pane tab")[3]; + let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3]; - 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."); + is(tab.getAttribute("selected"), "true", + "The response tab in the network details pane should be selected."); - return NetMonitorView.editor("#response-content-textarea").then((aEditor) => { + 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."); + + let aEditor = yield NetMonitorView.editor("#response-content-textarea"); is(aEditor.getText(), "Hello world!", "The text shown in the source editor is incorrect."); is(aEditor.getMode(), Editor.modes.text, diff --git a/browser/devtools/netmonitor/test/head.js b/browser/devtools/netmonitor/test/head.js index a9cf66420453..0fa11ec0704e 100644 --- a/browser/devtools/netmonitor/test/head.js +++ b/browser/devtools/netmonitor/test/head.js @@ -5,7 +5,8 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); -let { Promise: promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}); +let { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); +let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); let TargetFactory = devtools.TargetFactory; @@ -282,3 +283,20 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) { } } } + +/** + * Helper function for waiting for an event to fire before resolving a promise. + * Example: waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED); + * + * @param object subject + * The event emitter object that is being listened to. + * @param string eventName + * The name of the event to listen to. + * @return object + * Returns a promise that resolves upon firing of the event. + */ +function waitFor (subject, eventName) { + let deferred = promise.defer(); + subject.once(eventName, deferred.resolve); + return deferred.promise; +}