Bug 1320110 - WebConsoleClient API calls should return promises r=ochameau
☠☠ backed out by c3e82ec27263 ☠ ☠
authorJarda Snajdr <jsnajdr@gmail.com>
Thu, 24 Nov 2016 16:12:25 +0100
changeset 324200 c816bcb8572d5e11f35da0a6407823fffb7c594f
parent 324199 b9e86e3c313f7345ccc5a9ba28e0201c92351cd8
child 324201 c3e82ec27263daed684363258c30fac825eb22b8
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersochameau
bugs1320110
milestone53.0a1
Bug 1320110 - WebConsoleClient API calls should return promises r=ochameau MozReview-Commit-ID: 1mmGGUgIwqA
devtools/client/webconsole/test/browser_console_netlogging.js
devtools/client/webconsole/test/browser_webconsole_netlogging.js
devtools/client/webconsole/test/head.js
devtools/shared/client/main.js
devtools/shared/webconsole/client.js
devtools/shared/webconsole/test/test_jsterm.html
--- a/devtools/client/webconsole/test/browser_console_netlogging.js
+++ b/devtools/client/webconsole/test/browser_console_netlogging.js
@@ -18,19 +18,18 @@ add_task(function* () {
 
   const hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI,
                                       "browserConsole");
   let request = yield finishedRequest;
 
   ok(request, "Page load was logged");
 
   let client = hud.ui.webConsoleClient;
-  let args = [request.actor];
-  const postData = yield getPacket(client, "getRequestPostData", args);
-  const responseContent = yield getPacket(client, "getResponseContent", args);
+  const postData = yield client.getRequestPostData(request.actor);
+  const responseContent = yield client.getResponseContent(request.actor);
 
   is(request.request.url, TEST_NETWORK_REQUEST_URI,
     "Logged network entry is page load");
   is(request.request.method, "GET", "Method is correct");
   ok(!postData.postData.text, "No request body was stored");
   ok(postData.postDataDiscarded, "Request body was discarded");
   ok(!responseContent.content.text, "No response body was stored");
   ok(responseContent.contentDiscarded || request.fromCache,
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging.js
@@ -34,19 +34,18 @@ add_task(function* testPageLoad() {
 
   let finishedRequest = waitForFinishedRequest(PAGE_REQUEST_PREDICATE);
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
   let request = yield finishedRequest;
 
   ok(request, "Page load was logged");
 
   let client = hud.ui.webConsoleClient;
-  let args = [request.actor];
-  const postData = yield getPacket(client, "getRequestPostData", args);
-  const responseContent = yield getPacket(client, "getResponseContent", args);
+  const postData = yield client.getRequestPostData(request.actor);
+  const responseContent = yield client.getResponseContent(request.actor);
 
   is(request.request.url, TEST_NETWORK_REQUEST_URI,
     "Logged network entry is page load");
   is(request.request.method, "GET", "Method is correct");
   ok(!postData.postData.text, "No request body was stored");
   ok(!postData.postDataDiscarded,
     "Request body was not discarded");
   is(responseContent.content.text.indexOf("<!DOCTYPE HTML>"), 0,
@@ -60,19 +59,18 @@ add_task(function* testXhrGet() {
 
   let finishedRequest = waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
   content.wrappedJSObject.testXhrGet();
   let request = yield finishedRequest;
 
   ok(request, "testXhrGet() was logged");
 
   let client = hud.ui.webConsoleClient;
-  let args = [request.actor];
-  const postData = yield getPacket(client, "getRequestPostData", args);
-  const responseContent = yield getPacket(client, "getResponseContent", args);
+  const postData = yield client.getRequestPostData(request.actor);
+  const responseContent = yield client.getResponseContent(request.actor);
 
   is(request.request.method, "GET", "Method is correct");
   ok(!postData.postData.text, "No request body was sent");
   ok(!postData.postDataDiscarded,
     "Request body was not discarded");
   is(responseContent.content.text, TEST_DATA_JSON_CONTENT,
     "Response is correct");
 
@@ -84,19 +82,18 @@ add_task(function* testXhrPost() {
 
   let finishedRequest = waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
   content.wrappedJSObject.testXhrPost();
   let request = yield finishedRequest;
 
   ok(request, "testXhrPost() was logged");
 
   let client = hud.ui.webConsoleClient;
-  let args = [request.actor];
-  const postData = yield getPacket(client, "getRequestPostData", args);
-  const responseContent = yield getPacket(client, "getResponseContent", args);
+  const postData = yield client.getRequestPostData(request.actor);
+  const responseContent = yield client.getResponseContent(request.actor);
 
   is(request.request.method, "POST", "Method is correct");
   is(postData.postData.text, "Hello world!", "Request body was logged");
   is(responseContent.content.text, TEST_DATA_JSON_CONTENT,
     "Response is correct");
 
   yield closeTabAndToolbox();
 });
@@ -115,19 +112,18 @@ add_task(function* testFormSubmission() 
     let form = content.document.querySelector("form");
     form.submit();
   }`);
   let request = yield finishedRequest;
 
   ok(request, "testFormSubmission() was logged");
 
   let client = hud.ui.webConsoleClient;
-  let args = [request.actor];
-  const postData = yield getPacket(client, "getRequestPostData", args);
-  const responseContent = yield getPacket(client, "getResponseContent", args);
+  const postData = yield client.getRequestPostData(request.actor);
+  const responseContent = yield client.getResponseContent(request.actor);
 
   is(request.request.method, "POST", "Method is correct");
   isnot(postData.postData.text
     .indexOf("Content-Type: application/x-www-form-urlencoded"), -1,
     "Content-Type is correct");
   isnot(postData.postData.text
     .indexOf("Content-Length: 20"), -1, "Content-length is correct");
   isnot(postData.postData.text
--- a/devtools/client/webconsole/test/head.js
+++ b/devtools/client/webconsole/test/head.js
@@ -1786,31 +1786,16 @@ function checkLinkToInspector(hasLinkToI
 }
 
 function getSourceActor(sources, URL) {
   let item = sources.getItemForAttachment(a => a.source.url === URL);
   return item && item.value;
 }
 
 /**
- * Make a request against an actor and resolve with the packet.
- * @param object client
- *   The client to use when making the request.
- * @param function requestType
- *   The client request function to run.
- * @param array args
- *   The arguments to pass into the function.
- */
-function getPacket(client, requestType, args) {
-  return new Promise(resolve => {
-    client[requestType](...args, packet => resolve(packet));
-  });
-}
-
-/**
  * Verify that clicking on a link from a popup notification message tries to
  * open the expected URL.
  */
 function simulateMessageLinkClick(element, expectedLink) {
   let deferred = promise.defer();
 
   // Invoke the click event and check if a new tab would
   // open to the correct page.
--- a/devtools/shared/client/main.js
+++ b/devtools/shared/client/main.js
@@ -731,16 +731,17 @@ DebuggerClient.prototype = {
     function listenerBulk(resp) {
       request.off("json-reply", listenerJson);
       request.off("bulk-reply", listenerBulk);
       deferred.resolve(resp);
     }
     request.on("json-reply", listenerJson);
     request.on("bulk-reply", listenerBulk);
     request.then = deferred.promise.then.bind(deferred.promise);
+    request.catch = deferred.promise.catch.bind(deferred.promise);
 
     return request;
   },
 
   /**
    * Transmit streaming data via a bulk request.
    *
    * This method initiates the bulk send process by queuing up the header data.
--- a/devtools/shared/webconsole/client.js
+++ b/devtools/shared/webconsole/client.js
@@ -177,40 +177,44 @@ WebConsoleClient.prototype = {
    * Retrieve the cached messages from the server.
    *
    * @see this.CACHED_MESSAGES
    * @param array types
    *        The array of message types you want from the server. See
    *        this.CACHED_MESSAGES for known types.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getCachedMessages: function (types, onResponse) {
     let packet = {
       to: this._actor,
       type: "getCachedMessages",
       messageTypes: types,
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Inspect the properties of an object.
    *
    * @param string actor
    *        The WebConsoleObjectActor ID to send the request to.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   inspectObjectProperties: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "inspectProperties",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Evaluate a JavaScript expression.
    *
    * @param string string
    *        The code you want to evaluate.
    * @param function onResponse
@@ -239,59 +243,71 @@ WebConsoleClient.prototype = {
    *        - url: the url to evaluate the script as. Defaults to
    *        "debugger eval code".
    *
    *        - selectedNodeActor: the NodeActor ID of the current
    *        selection in the Inspector, if such a selection
    *        exists. This is used by helper functions that can
    *        reference the currently selected node in the Inspector,
    *        like $0.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   evaluateJS: function (string, onResponse, options = {}) {
     let packet = {
       to: this._actor,
       type: "evaluateJS",
       text: string,
       bindObjectActor: options.bindObjectActor,
       frameActor: options.frameActor,
       url: options.url,
       selectedNodeActor: options.selectedNodeActor,
       selectedObjectActor: options.selectedObjectActor,
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Evaluate a JavaScript expression asynchronously.
    * See evaluateJS for parameter and response information.
    */
   evaluateJSAsync: function (string, onResponse, options = {}) {
     // Pre-37 servers don't support async evaluation.
     if (!this.traits.evaluateJSAsync) {
-      this.evaluateJS(string, onResponse, options);
-      return;
+      return this.evaluateJS(string, onResponse, options);
     }
 
     let packet = {
       to: this._actor,
       type: "evaluateJSAsync",
       text: string,
       bindObjectActor: options.bindObjectActor,
       frameActor: options.frameActor,
       url: options.url,
       selectedNodeActor: options.selectedNodeActor,
       selectedObjectActor: options.selectedObjectActor,
     };
 
-    this._client.request(packet, response => {
-      // Null check this in case the client has been detached while waiting
-      // for a response.
-      if (this.pendingEvaluationResults) {
-        this.pendingEvaluationResults.set(response.resultID, onResponse);
-      }
+    return new Promise((resolve, reject) => {
+      this._client.request(packet, response => {
+        // Null check this in case the client has been detached while waiting
+        // for a response.
+        if (this.pendingEvaluationResults) {
+          this.pendingEvaluationResults.set(response.resultID, resp => {
+            if (onResponse) {
+              onResponse(resp);
+            }
+            if (resp.error) {
+              reject(resp);
+            } else {
+              resolve(resp);
+            }
+          });
+        }
+      });
     });
   },
 
   /**
    * Handler for the actors's unsolicited evaluationResult packet.
    */
   onEvaluationResult: function (notification, packet) {
     // The client on the main thread can receive notification packets from
@@ -321,254 +337,285 @@ WebConsoleClient.prototype = {
    * @param string string
    *        The code you want to autocomplete.
    * @param number cursor
    *        Cursor location inside the string. Index starts from 0.
    * @param function onResponse
    *        The function invoked when the response is received.
    * @param string frameActor
    *        The id of the frame actor that made the call.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   autocomplete: function (string, cursor, onResponse, frameActor) {
     let packet = {
       to: this._actor,
       type: "autocomplete",
       text: string,
       cursor: cursor,
       frameActor: frameActor,
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Clear the cache of messages (page errors and console API calls).
+   *
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   clearMessagesCache: function () {
     let packet = {
       to: this._actor,
       type: "clearMessagesCache",
     };
-    this._client.request(packet);
+    return this._client.request(packet);
   },
 
   /**
    * Get Web Console-related preferences on the server.
    *
    * @param array preferences
    *        An array with the preferences you want to retrieve.
    * @param function [onResponse]
    *        Optional function to invoke when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getPreferences: function (preferences, onResponse) {
     let packet = {
       to: this._actor,
       type: "getPreferences",
       preferences: preferences,
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Set Web Console-related preferences on the server.
    *
    * @param object preferences
    *        An object with the preferences you want to change.
    * @param function [onResponse]
    *        Optional function to invoke when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   setPreferences: function (preferences, onResponse) {
     let packet = {
       to: this._actor,
       type: "setPreferences",
       preferences: preferences,
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the request headers from the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getRequestHeaders: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getRequestHeaders",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the request cookies from the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getRequestCookies: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getRequestCookies",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the request post data from the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getRequestPostData: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getRequestPostData",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the response headers from the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getResponseHeaders: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getResponseHeaders",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the response cookies from the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getResponseCookies: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getResponseCookies",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the response content from the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getResponseContent: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getResponseContent",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the timing information for the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getEventTimings: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getEventTimings",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Retrieve the security information for the given NetworkEventActor.
    *
    * @param string actor
    *        The NetworkEventActor ID.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   getSecurityInfo: function (actor, onResponse) {
     let packet = {
       to: actor,
       type: "getSecurityInfo",
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Send a HTTP request with the given data.
    *
    * @param string data
    *        The details of the HTTP request.
    * @param function onResponse
    *        The function invoked when the response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   sendHTTPRequest: function (data, onResponse) {
     let packet = {
       to: this._actor,
       type: "sendHTTPRequest",
       request: data
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Start the given Web Console listeners.
    *
    * @see this.LISTENERS
    * @param array listeners
    *        Array of listeners you want to start. See this.LISTENERS for
    *        known listeners.
    * @param function onResponse
    *        Function to invoke when the server response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   startListeners: function (listeners, onResponse) {
     let packet = {
       to: this._actor,
       type: "startListeners",
       listeners: listeners,
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Stop the given Web Console listeners.
    *
    * @see this.LISTENERS
    * @param array listeners
    *        Array of listeners you want to stop. See this.LISTENERS for
    *        known listeners.
    * @param function onResponse
    *        Function to invoke when the server response is received.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
    */
   stopListeners: function (listeners, onResponse) {
     let packet = {
       to: this._actor,
       type: "stopListeners",
       listeners: listeners,
     };
-    this._client.request(packet, onResponse);
+    return this._client.request(packet, onResponse);
   },
 
   /**
    * Return an instance of LongStringClient for the given long string grip.
    *
    * @param object grip
    *        The long string grip returned by the protocol.
    * @return object
--- a/devtools/shared/webconsole/test/test_jsterm.html
+++ b/devtools/shared/webconsole/test/test_jsterm.html
@@ -19,23 +19,21 @@ SimpleTest.waitForExplicitFinish();
 let gState;
 
 let {MAX_AUTOCOMPLETE_ATTEMPTS,MAX_AUTOCOMPLETIONS} = require("devtools/shared/webconsole/js-property-provider");
 
 // This test runs all of its assertions twice - once with
 // evaluateJS and once with evaluateJSAsync.
 let evaluatingSync = true;
 function evaluateJS(input, options = {}) {
-  return new Promise((resolve, reject) => {
-    if (evaluatingSync) {
-      gState.client.evaluateJS(input, resolve, options);
-    } else {
-      gState.client.evaluateJSAsync(input, resolve, options);
-    }
-  });
+  if (evaluatingSync) {
+    return gState.client.evaluateJS(input, null, options);
+  } else {
+    return gState.client.evaluateJSAsync(input, null, options);
+  }
 }
 
 function startTest()
 {
   removeEventListener("load", startTest);
 
   attachConsoleToTab(["PageError"], onAttach);
 }