Bug 1499070 - Fix timestamp for evaluation result; r=Honza.
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Thu, 18 Oct 2018 09:41:53 +0000
changeset 490249 c645265aa5b827fac52c3692991cbd55558d5821
parent 490248 8a1bcc91affb90fbdb0f36d5c45d0629e4b43622
child 490250 5be96992e33cfdbd85374a419aeb1b8734a2edab
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersHonza
bugs1499070
milestone64.0a1
Bug 1499070 - Fix timestamp for evaluation result; r=Honza. When sending a command to the server, a timestamp is computed before evaluating the string, and is then sent back to the client in the packet. However, if top-level await, or somme :commands, the evaluation takes more time, which means the timestamp is now innacurate. For those cases, we update the timestamp before sending the packet to the client. Differential Revision: https://phabricator.services.mozilla.com/D8734
devtools/client/webconsole/components/JSTerm.js
devtools/client/webconsole/components/message-types/ConsoleCommand.js
devtools/client/webconsole/test/mochitest/browser_jsterm_await.js
devtools/client/webconsole/types.js
devtools/server/actors/webconsole.js
--- a/devtools/client/webconsole/components/JSTerm.js
+++ b/devtools/client/webconsole/components/JSTerm.js
@@ -545,16 +545,17 @@ class JSTerm extends Component {
     const inspectorSelection = this.hud.owner.getInspectorSelection();
     if (inspectorSelection && inspectorSelection.nodeFront) {
       selectedNodeActor = inspectorSelection.nodeFront.actorID;
     }
 
     const { ConsoleCommand } = require("devtools/client/webconsole/types");
     const cmdMessage = new ConsoleCommand({
       messageText: executeString,
+      timeStamp: Date.now(),
     });
     this.hud.proxy.dispatchMessageAdd(cmdMessage);
 
     let mappedExpressionRes = null;
     try {
       mappedExpressionRes = await this.hud.owner.getMappedExpression(executeString);
     } catch (e) {
       console.warn("Error when calling getMappedExpression", e);
--- a/devtools/client/webconsole/components/message-types/ConsoleCommand.js
+++ b/devtools/client/webconsole/components/message-types/ConsoleCommand.js
@@ -30,26 +30,28 @@ function ConsoleCommand(props) {
   } = props;
 
   const {
     indent,
     source,
     type,
     level,
     messageText,
+    timeStamp,
   } = message;
 
   // This uses a Custom Element to syntax highlight when possible. If it's not
   // (no CodeMirror editor), then it will just render text.
   const messageBody = createElement("syntax-highlighted", null, messageText);
   return Message({
     source,
     type,
     level,
     topLevelClasses: [],
     messageBody,
     serviceContainer,
     indent,
+    timeStamp,
     timestampsVisible,
   });
 }
 
 module.exports = ConsoleCommand;
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_await.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_await.js
@@ -34,16 +34,27 @@ async function performTests() {
   );
 
   // Check that the resulting promise of the async iife is not displayed.
   let messages = hud.ui.outputNode.querySelectorAll(".message .message-body");
   let messagesText = Array.from(messages).map(n => n.textContent).join(" - ");
   is(messagesText, `${simpleAwait} - Array [ "await1" ]`,
     "The output contains the the expected messages");
 
+  // Check that the timestamp of the result is accurate
+  const {
+    visibleMessages,
+    messagesById
+  } = hud.ui.consoleOutput.getStore().getState().messages;
+  const [commandId, resultId] = visibleMessages;
+  const delta = messagesById.get(resultId).timeStamp -
+    messagesById.get(commandId).timeStamp;
+  ok(delta >= 500,
+    `The result has a timestamp at least 500ms (${delta}ms) older than the command`);
+
   info("Check that assigning the result of a top-level await expression works");
   await executeAndWaitForResultMessage(
     `x = await new Promise(r => setTimeout(() => r("await2"), 500))`,
     `await2`,
   );
 
   let message = await executeAndWaitForResultMessage(
     `"-" + x + "-"`,
--- a/devtools/client/webconsole/types.js
+++ b/devtools/client/webconsole/types.js
@@ -17,16 +17,17 @@ exports.ConsoleCommand = function(props)
     allowRepeating: false,
     messageText: null,
     source: MESSAGE_SOURCE.JAVASCRIPT,
     type: MESSAGE_TYPE.COMMAND,
     level: MESSAGE_LEVEL.LOG,
     groupId: null,
     indent: 0,
     private: false,
+    timeStamp: null,
   }, props);
 };
 
 exports.ConsoleMessage = function(props) {
   return Object.assign({
     id: null,
     allowRepeating: true,
     source: null,
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -971,21 +971,24 @@ WebConsoleActor.prototype =
    *         `resultID` field, and potentially a promise in the `helperResult` or in the
    *         `awaitResult` field.
    *
    * @return object
    *         The response packet to send to with the unique id in the
    *         `resultID` field, with a sanitized helperResult field.
    */
   _waitForResultAndSend: async function(response) {
+    let updateTimestamp = false;
+
     // Wait for asynchronous command completion before sending back the response
     if (
       response.helperResult && typeof response.helperResult.then == "function"
     ) {
       response.helperResult = await response.helperResult;
+      updateTimestamp = true;
     } else if (response.awaitResult && typeof response.awaitResult.then === "function") {
       let result;
       try {
         result = await response.awaitResult;
       } catch (e) {
         // The promise was rejected. We let the engine handle this as it will report a
         // `uncaught exception` error.
         response.topLevelAwaitRejected = true;
@@ -995,16 +998,24 @@ WebConsoleActor.prototype =
         // `createValueGrip` expect a debuggee value, while here we have the raw object.
         // We need to call `makeDebuggeeValue` on it to make it work.
         const dbgResult = this.makeDebuggeeValue(result);
         response.result = this.createValueGrip(dbgResult);
       }
 
       // Remove the promise from the response object.
       delete response.awaitResult;
+
+      updateTimestamp = true;
+    }
+
+    if (updateTimestamp) {
+      // We need to compute the timestamp again as the one in the response was set before
+      // doing the evaluation, which is now innacurate since we waited for a bit.
+      response.timestamp = Date.now();
     }
 
     // Finally, send an unsolicited evaluationResult packet with
     // the normal return value
     this.conn.sendActorEvent(this.actorID, "evaluationResult", response);
   },
 
   /**