Bug 1379570 - Adapt the inspect command to the new console frontend. r=bgrins draft
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Tue, 11 Jul 2017 13:50:59 +0200
changeset 610372 9ed4ed85ca2fc451a396ba959d913f65603a763c
parent 609596 aff336ac161daa3ea350e59a288963edbd58ed39
child 637855 f5384d8f793ecc860c5464115321959d8d17d15b
push id68885
push userbmo:nchevobbe@mozilla.com
push dateTue, 18 Jul 2017 09:00:17 +0000
reviewersbgrins
bugs1379570
milestone56.0a1
Bug 1379570 - Adapt the inspect command to the new console frontend. r=bgrins MozReview-Commit-ID: LsT12pOJhvV
devtools/client/webconsole/jsterm.js
devtools/client/webconsole/new-console-output/components/grip-message-body.js
devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
devtools/client/webconsole/new-console-output/constants.js
devtools/client/webconsole/new-console-output/test/components/evaluation-result.test.js
devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/head.js
devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js
devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js
devtools/client/webconsole/new-console-output/test/fixtures/stubs/cssMessage.js
devtools/client/webconsole/new-console-output/test/fixtures/stubs/evaluationResult.js
devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js
devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
devtools/client/webconsole/new-console-output/test/mochitest/browser_jsterm_inspect.js
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_console_dir.js
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector.js
devtools/client/webconsole/new-console-output/test/mochitest/head.js
devtools/client/webconsole/new-console-output/types.js
devtools/client/webconsole/new-console-output/utils/messages.js
--- a/devtools/client/webconsole/jsterm.js
+++ b/devtools/client/webconsole/jsterm.js
@@ -337,17 +337,19 @@ JSTerm.prototype = {
       switch (helperResult.type) {
         case "clearOutput":
           this.clearOutput();
           break;
         case "clearHistory":
           this.clearHistory();
           break;
         case "inspectObject":
-          this.inspectObjectActor(helperResult.object);
+          if (!this.hud.NEW_CONSOLE_OUTPUT_ENABLED) {
+            this.inspectObjectActor(helperResult.object);
+          }
           break;
         case "error":
           try {
             errorMessage = l10n.getStr(helperResult.message);
           } catch (ex) {
             errorMessage = helperResult.message;
           }
           break;
@@ -356,19 +358,24 @@ JSTerm.prototype = {
           break;
         case "copyValueToClipboard":
           clipboardHelper.copyString(helperResult.value);
           break;
       }
     }
 
     // Hide undefined results coming from JSTerm helper functions.
-    if (!errorMessage && result && typeof result == "object" &&
-        result.type == "undefined" &&
-        helperResult && !helperHasRawOutput) {
+    if (!errorMessage
+        && result
+        && typeof result == "object"
+        && result.type == "undefined"
+        && helperResult
+        && !helperHasRawOutput
+        && !(this.hud.NEW_CONSOLE_OUTPUT_ENABLED && helperResult.type === "inspectObject")
+    ) {
       callback && callback();
       return;
     }
 
     if (this.hud.NEW_CONSOLE_OUTPUT_ENABLED) {
       this.hud.newConsoleOutput.dispatchMessageAdd(response, true).then(callback);
       return;
     }
--- a/devtools/client/webconsole/new-console-output/components/grip-message-body.js
+++ b/devtools/client/webconsole/new-console-output/components/grip-message-body.js
@@ -15,16 +15,17 @@ if (typeof define === "undefined") {
 // React
 const {
   createFactory,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { ObjectClient } = require("devtools/shared/client/main");
 const {
   MESSAGE_TYPE,
+  JSTERM_COMMANDS,
 } = require("../constants");
 
 const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
 const reps = require("devtools/client/shared/components/reps/reps");
 const { REPS, MODE } = reps;
 const ObjectInspector = createFactory(reps.ObjectInspector);
 const { Grip } = REPS;
 
@@ -40,16 +41,17 @@ GripMessageBody.propTypes = {
     createElement: PropTypes.func.isRequired,
     hudProxyClient: PropTypes.object.isRequired,
   }),
   userProvidedStyle: PropTypes.string,
   useQuotes: PropTypes.bool,
   escapeWhitespace: PropTypes.bool,
   loadedObjectProperties: PropTypes.object,
   type: PropTypes.string,
+  helperType: PropTypes.string,
 };
 
 GripMessageBody.defaultProps = {
   mode: MODE.LONG,
 };
 
 function GripMessageBody(props) {
   const {
@@ -57,17 +59,16 @@ function GripMessageBody(props) {
     messageId,
     grip,
     userProvidedStyle,
     serviceContainer,
     useQuotes,
     escapeWhitespace,
     mode = MODE.LONG,
     loadedObjectProperties,
-    type,
   } = props;
 
   let styleObject;
   if (userProvidedStyle && userProvidedStyle !== "") {
     styleObject = cleanupStyle(userProvidedStyle, serviceContainer.createElement);
   }
 
   let onDOMNodeMouseOver;
@@ -84,17 +85,17 @@ function GripMessageBody(props) {
         e.stopPropagation();
         serviceContainer.openNodeInInspector(object);
       }
       : null;
   }
 
   const objectInspectorProps = {
     // Auto-expand the ObjectInspector when the message is a console.dir one.
-    autoExpandDepth: type === MESSAGE_TYPE.DIR ? 1 : 0,
+    autoExpandDepth: shouldAutoExpandObjectInspector(props) ? 1 : 0,
     mode,
     // TODO: we disable focus since it's not currently working well in ObjectInspector.
     // Let's remove the property below when problem are fixed in OI.
     disabledFocus: true,
     roots: [{
       path: grip.actor || JSON.stringify(grip),
       contents: {
         value: grip
@@ -156,9 +157,21 @@ function cleanupStyle(userProvidedStyle,
     })
     .reduce((object, name) => {
       return Object.assign({
         [name]: dummy.style[name]
       }, object);
     }, {});
 }
 
+function shouldAutoExpandObjectInspector(props) {
+  const {
+    helperType,
+    type,
+  } = props;
+
+  return (
+    type === MESSAGE_TYPE.DIR
+    || helperType === JSTERM_COMMANDS.INSPECT
+  );
+}
+
 module.exports = GripMessageBody;
--- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
@@ -37,16 +37,17 @@ function EvaluationResult(props) {
     indent,
     timestampsVisible,
     loadedObjectProperties,
   } = props;
 
   const {
     source,
     type,
+    helperType,
     level,
     id: messageId,
     exceptionDocURL,
     frame,
     timeStamp,
     parameters,
     notes,
   } = message;
@@ -65,16 +66,18 @@ function EvaluationResult(props) {
     messageBody = GripMessageBody({
       dispatch,
       messageId,
       grip: parameters,
       serviceContainer,
       useQuotes: true,
       escapeWhitespace: false,
       loadedObjectProperties,
+      type,
+      helperType,
     });
   }
 
   const topLevelClasses = ["cm-s-mozilla"];
 
   return Message({
     source,
     type,
--- a/devtools/client/webconsole/new-console-output/constants.js
+++ b/devtools/client/webconsole/new-console-output/constants.js
@@ -78,10 +78,21 @@ const chromeRDPEnums = {
     LOG: "log",
     ERROR: "error",
     WARN: "warn",
     DEBUG: "debug",
     INFO: "info"
   }
 };
 
+const jstermCommands = {
+  JSTERM_COMMANDS: {
+    INSPECT: "inspectObject"
+  }
+};
+
 // Combine into a single constants object
-module.exports = Object.assign({}, actionTypes, prefs, chromeRDPEnums);
+module.exports = Object.assign({},
+  actionTypes,
+  chromeRDPEnums,
+  jstermCommands,
+  prefs,
+);
--- a/devtools/client/webconsole/new-console-output/test/components/evaluation-result.test.js
+++ b/devtools/client/webconsole/new-console-output/test/components/evaluation-result.test.js
@@ -44,16 +44,23 @@ describe("EvaluationResult component:", 
     const message = stubPreparedMessages.get("longString message Error");
     const wrapper = render(EvaluationResult({ message }));
 
     const text = wrapper.find(".message-body").text();
     expect(text.startsWith("Error: Long error Long error")).toBe(true);
     expect(wrapper.find(".message.error").length).toBe(1);
   });
 
+  it("renders an inspect command result", () => {
+    const message = stubPreparedMessages.get("inspect({a: 1})");
+    const wrapper = render(EvaluationResult({ message }));
+
+    expect(wrapper.find(".message-body").text()).toBe("Object { a: 1 }");
+  });
+
   it("displays a [Learn more] link", () => {
     const store = setupStore([]);
 
     const message = stubPreparedMessages.get("asdf()");
 
     serviceContainer.openLink = sinon.spy();
     const wrapper = mount(Provider({store},
       EvaluationResult({message, serviceContainer})
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/head.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/head.js
@@ -207,16 +207,22 @@ function getCleanedPacket(key, packet) {
       if (
         res.networkInfo.response
         && res.networkInfo.response.transferredSize !== undefined
       ) {
         res.networkInfo.response.transferredSize =
           existingPacket.networkInfo.response.transferredSize;
       }
     }
+
+    if (res.helperResult) {
+      if (res.helperResult.object) {
+        res.helperResult.object.actor = existingPacket.helperResult.object.actor;
+      }
+    }
   } else {
     res = packet;
   }
 
   cachedPackets[key] = res;
   return res;
 }
 
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js
@@ -140,17 +140,18 @@ p {
   padding-top: invalid value;
 }
 `);
 
 // Evaluation Result
 const evaluationResultCommands = [
   "new Date(0)",
   "asdf()",
-  "1 + @"
+  "1 + @",
+  "inspect({a: 1})"
 ];
 
 let evaluationResult = new Map(evaluationResultCommands.map(cmd => [cmd, cmd]));
 evaluationResult.set("longString message Error",
   `throw new Error("Long error ".repeat(10000))`);
 
 // Network Event
 
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js
@@ -14,16 +14,17 @@ const { ConsoleMessage } =
 let stubPreparedMessages = new Map();
 let stubPackets = new Map();
 stubPreparedMessages.set("console.log('foobar', 'test')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159894798,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "foobar",
     "test"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foobar\",\"test\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
@@ -40,16 +41,17 @@ stubPreparedMessages.set("console.log('f
 }));
 
 stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159896036,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     {
       "type": "undefined"
     }
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
@@ -67,16 +69,17 @@ stubPreparedMessages.set("console.log(un
 }));
 
 stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159897333,
   "type": "warn",
+  "helperType": null,
   "level": "warn",
   "messageText": null,
   "parameters": [
     "danger, will robinson!"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":null,\"parameters\":[\"danger, will robinson!\"],\"source\":\"console-api\",\"type\":\"warn\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -92,16 +95,17 @@ stubPreparedMessages.set("console.warn('
 }));
 
 stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159898667,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     {
       "type": "NaN"
     }
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"NaN\"}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
@@ -119,16 +123,17 @@ stubPreparedMessages.set("console.log(Na
 }));
 
 stubPreparedMessages.set("console.log(null)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159900151,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     {
       "type": "null"
     }
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"null\"}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
@@ -146,16 +151,17 @@ stubPreparedMessages.set("console.log(nu
 }));
 
 stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159901470,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "鼬"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"鼬\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -171,16 +177,17 @@ stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({
 }));
 
 stubPreparedMessages.set("console.clear()", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159902721,
   "type": "clear",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "Console was cleared."
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"source\":\"console-api\",\"type\":\"clear\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -196,16 +203,17 @@ stubPreparedMessages.set("console.clear(
 }));
 
 stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159903982,
   "type": "log",
+  "helperType": null,
   "level": "debug",
   "messageText": "bar: 1",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"debug\",\"messageText\":\"bar: 1\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 1,
@@ -219,16 +227,17 @@ stubPreparedMessages.set("console.count(
 }));
 
 stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159905182,
   "type": "assert",
+  "helperType": null,
   "level": "error",
   "messageText": null,
   "parameters": [
     {
       "type": "object",
       "actor": "server1.conn8.child1/obj31",
       "class": "Object",
       "extensible": true,
@@ -273,16 +282,17 @@ stubPreparedMessages.set("console.assert
 }));
 
 stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159906444,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "hello \nfrom \rthe \"string world!"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"hello \\nfrom \\rthe \\\"string world!\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -298,16 +308,17 @@ stubPreparedMessages.set("console.log('h
 }));
 
 stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159907704,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "úṇĩçödê țĕșť"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"úṇĩçödê țĕșť\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -323,16 +334,17 @@ stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMessage({
 }));
 
 stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159908948,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     {
       "type": "object",
       "actor": "server1.conn11.child1/obj31",
       "class": "Window",
       "extensible": true,
@@ -360,16 +372,17 @@ stubPreparedMessages.set("console.dirxml
 }));
 
 stubPreparedMessages.set("console.log('myarray', ['red', 'green', 'blue'])", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1493123239624,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "myarray",
     {
       "type": "object",
       "actor": "server1.conn0.child1/obj32",
       "class": "Array",
@@ -403,16 +416,17 @@ stubPreparedMessages.set("console.log('m
 }));
 
 stubPreparedMessages.set("console.log('myregex', /a.b.c/)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1493123770223,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "myregex",
     {
       "type": "object",
       "actor": "server1.conn0.child1/obj33",
       "class": "RegExp",
@@ -438,16 +452,17 @@ stubPreparedMessages.set("console.log('m
 }));
 
 stubPreparedMessages.set("console.table(['red', 'green', 'blue']);", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1493124761377,
   "type": "table",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     {
       "type": "object",
       "actor": "server1.conn0.child1/obj34",
       "class": "Array",
       "extensible": true,
@@ -480,16 +495,17 @@ stubPreparedMessages.set("console.table(
 }));
 
 stubPreparedMessages.set("console.log('myobject', {red: 'redValue', green: 'greenValue', blue: 'blueValue'});", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1493125748177,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "myobject",
     {
       "type": "object",
       "actor": "server1.conn0.child1/obj35",
       "class": "Object",
@@ -539,16 +555,17 @@ stubPreparedMessages.set("console.log('m
 }));
 
 stubPreparedMessages.set("console.map('mymap')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1493125410207,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "mymap",
     {
       "type": "object",
       "actor": "server1.conn0.child1/obj36",
       "class": "Map",
@@ -587,16 +604,17 @@ stubPreparedMessages.set("console.map('m
 }));
 
 stubPreparedMessages.set("console.trace()", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159910198,
   "type": "trace",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":3},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[],\"source\":\"console-api\",\"type\":\"trace\",\"userProvidedStyles\":[]}",
   "stacktrace": [
     {
       "columnNumber": 3,
       "filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
@@ -632,16 +650,17 @@ stubPreparedMessages.set("console.trace(
 }));
 
 stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159911476,
   "type": "nullMessage",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"nullMessage\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 2,
@@ -655,16 +674,17 @@ stubPreparedMessages.set("console.time('
 }));
 
 stubPreparedMessages.set("timerAlreadyExists", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1494362489620,
   "type": "time",
+  "helperType": null,
   "level": "warn",
   "messageText": "Timer “bar” already exists.",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Timer “bar” already exists.\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"time\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 3,
@@ -678,16 +698,17 @@ stubPreparedMessages.set("timerAlreadyEx
 }));
 
 stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159911478,
   "type": "timeEnd",
+  "helperType": null,
   "level": "log",
   "messageText": "bar: 1.36ms",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":4,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"bar: 1.36ms\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"timeEnd\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 4,
@@ -701,16 +722,17 @@ stubPreparedMessages.set("console.timeEn
 }));
 
 stubPreparedMessages.set("timerDoesntExist", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1494362489622,
   "type": "timeEnd",
+  "helperType": null,
   "level": "warn",
   "messageText": "Timer “bar” doesn’t exist.",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Timer “bar” doesn’t exist.\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"timeEnd\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 5,
@@ -724,16 +746,17 @@ stubPreparedMessages.set("timerDoesntExi
 }));
 
 stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159912655,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "bar"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -749,16 +772,17 @@ stubPreparedMessages.set("console.table(
 }));
 
 stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159913807,
   "type": "table",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     {
       "type": "object",
       "class": "Array",
       "extensible": true,
       "frozen": false,
@@ -790,16 +814,17 @@ stubPreparedMessages.set("console.table(
 }));
 
 stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159914984,
   "type": "startGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "bar"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"source\":\"console-api\",\"type\":\"startGroup\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -815,16 +840,17 @@ stubPreparedMessages.set("console.group(
 }));
 
 stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1492540770051,
   "type": "endGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 3,
@@ -838,16 +864,17 @@ stubPreparedMessages.set("console.groupE
 }));
 
 stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159916153,
   "type": "startGroupCollapsed",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "foo"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\"],\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -863,16 +890,17 @@ stubPreparedMessages.set("console.groupC
 }));
 
 stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1492540770585,
   "type": "endGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 3,
@@ -886,16 +914,17 @@ stubPreparedMessages.set("console.groupE
 }));
 
 stubPreparedMessages.set("console.group()", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159917524,
   "type": "startGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "<no group label>"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"<no group label>\"],\"source\":\"console-api\",\"type\":\"startGroup\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
@@ -911,16 +940,17 @@ stubPreparedMessages.set("console.group(
 }));
 
 stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1491902018685,
   "type": "endGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 3,
@@ -934,16 +964,17 @@ stubPreparedMessages.set("console.groupE
 }));
 
 stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1479159919144,
   "type": "log",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "foo",
     "bar"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}",
   "stacktrace": null,
@@ -963,16 +994,17 @@ stubPreparedMessages.set("console.log(%c
 }));
 
 stubPreparedMessages.set("console.group(%cfoo%cbar)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1491902018670,
   "type": "startGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "foo",
     "bar"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"source\":\"console-api\",\"type\":\"startGroup\",\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}",
   "stacktrace": null,
@@ -992,16 +1024,17 @@ stubPreparedMessages.set("console.group(
 }));
 
 stubPreparedMessages.set("console.groupEnd(%cfoo%cbar)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1492540772083,
   "type": "endGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":6,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 6,
@@ -1015,16 +1048,17 @@ stubPreparedMessages.set("console.groupE
 }));
 
 stubPreparedMessages.set("console.groupCollapsed(%cfoo%cbaz)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1491902018683,
   "type": "startGroupCollapsed",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     "foo",
     "baz"
   ],
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"baz\"],\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}",
   "stacktrace": null,
@@ -1044,16 +1078,17 @@ stubPreparedMessages.set("console.groupC
 }));
 
 stubPreparedMessages.set("console.groupEnd(%cfoo%cbaz)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1492540772669,
   "type": "endGroup",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":6,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
     "line": 6,
@@ -1067,16 +1102,17 @@ stubPreparedMessages.set("console.groupE
 }));
 
 stubPreparedMessages.set("console.dir({C, M, Y, K})", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "console-api",
   "timeStamp": 1499698054958,
   "type": "dir",
+  "helperType": null,
   "level": "log",
   "messageText": null,
   "parameters": [
     {
       "type": "object",
       "actor": "server1.conn0.child1/obj39",
       "class": "Object",
       "extensible": true,
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/cssMessage.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/cssMessage.js
@@ -14,16 +14,17 @@ const { ConsoleMessage } =
 let stubPreparedMessages = new Map();
 let stubPackets = new Map();
 stubPreparedMessages.set("Unknown property ‘such-unknown-property’.  Declaration dropped.", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "css",
   "timeStamp": 1479159920406,
   "type": "log",
+  "helperType": null,
   "level": "warn",
   "messageText": "Unknown property ‘such-unknown-property’.  Declaration dropped.",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":23},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Unknown property ‘such-unknown-property’.  Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
     "line": 3,
@@ -36,16 +37,17 @@ stubPreparedMessages.set("Unknown property ‘such-unknown-property’.  Declaration dropped.", new ConsoleMessage({
 }));
 
 stubPreparedMessages.set("Error in parsing value for ‘padding-top’.  Declaration dropped.", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "css",
   "timeStamp": 1479159920465,
   "type": "log",
+  "helperType": null,
   "level": "warn",
   "messageText": "Error in parsing value for ‘padding-top’.  Declaration dropped.",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":15},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Error in parsing value for ‘padding-top’.  Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
   "stacktrace": null,
   "frame": {
     "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
     "line": 3,
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/evaluationResult.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/evaluationResult.js
@@ -14,16 +14,17 @@ const { ConsoleMessage } =
 let stubPreparedMessages = new Map();
 let stubPackets = new Map();
 stubPreparedMessages.set("new Date(0)", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "javascript",
   "timeStamp": 1479159921364,
   "type": "result",
+  "helperType": null,
   "level": "log",
   "parameters": {
     "type": "object",
     "actor": "server1.conn0.child1/obj30",
     "class": "Date",
     "extensible": true,
     "frozen": false,
     "sealed": false,
@@ -42,16 +43,17 @@ stubPreparedMessages.set("new Date(0)", 
 }));
 
 stubPreparedMessages.set("asdf()", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "javascript",
   "timeStamp": 1479159921377,
   "type": "result",
+  "helperType": null,
   "level": "error",
   "messageText": "ReferenceError: asdf is not defined",
   "parameters": {
     "type": "undefined"
   },
   "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":{\"type\":\"undefined\"},\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
   "stacktrace": null,
   "frame": {
@@ -67,16 +69,17 @@ stubPreparedMessages.set("asdf()", new C
 }));
 
 stubPreparedMessages.set("1 + @", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "javascript",
   "timeStamp": 1479159921399,
   "type": "result",
+  "helperType": null,
   "level": "error",
   "messageText": "SyntaxError: illegal character",
   "parameters": {
     "type": "undefined"
   },
   "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":{\"type\":\"undefined\"},\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
   "stacktrace": null,
   "frame": {
@@ -86,22 +89,62 @@ stubPreparedMessages.set("1 + @", new Co
   },
   "groupId": null,
   "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Illegal_character?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0
 }));
 
+stubPreparedMessages.set("inspect({a: 1})", new ConsoleMessage({
+  "id": "1",
+  "allowRepeating": true,
+  "source": "javascript",
+  "timeStamp": 1499776070751,
+  "type": "result",
+  "helperType": "inspectObject",
+  "level": "log",
+  "parameters": {
+    "type": "object",
+    "actor": "server1.conn0.child1/obj35",
+    "class": "Object",
+    "extensible": true,
+    "frozen": false,
+    "sealed": false,
+    "ownPropertyLength": 1,
+    "preview": {
+      "kind": "Object",
+      "ownProperties": {
+        "a": {
+          "configurable": true,
+          "enumerable": true,
+          "writable": true,
+          "value": 1
+        }
+      },
+      "ownPropertiesLength": 1,
+      "safeGetterValues": {}
+    }
+  },
+  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj35\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"a\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":1}},\"ownPropertiesLength\":1,\"safeGetterValues\":{}}},\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
+  "stacktrace": null,
+  "frame": null,
+  "groupId": null,
+  "userProvidedStyles": null,
+  "notes": null,
+  "indent": 0
+}));
+
 stubPreparedMessages.set("longString message Error", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "javascript",
   "timeStamp": 1493108241073,
   "type": "result",
+  "helperType": null,
   "level": "error",
   "messageText": {
     "type": "longString",
     "initial": "Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon",
     "length": 110007,
     "actor": "server1.conn0.child1/longString37"
   },
   "parameters": {
@@ -205,16 +248,54 @@ stubPackets.set("1 + @", {
     "source": "debugger eval code",
     "line": 1,
     "column": 4
   },
   "helperResult": null,
   "notes": null
 });
 
+stubPackets.set("inspect({a: 1})", {
+  "from": "server1.conn0.child1/consoleActor2",
+  "input": "inspect({a: 1})",
+  "result": {
+    "type": "undefined"
+  },
+  "timestamp": 1499776070751,
+  "exception": null,
+  "frame": null,
+  "helperResult": {
+    "type": "inspectObject",
+    "input": "inspect({a: 1})",
+    "object": {
+      "type": "object",
+      "actor": "server1.conn0.child1/obj35",
+      "class": "Object",
+      "extensible": true,
+      "frozen": false,
+      "sealed": false,
+      "ownPropertyLength": 1,
+      "preview": {
+        "kind": "Object",
+        "ownProperties": {
+          "a": {
+            "configurable": true,
+            "enumerable": true,
+            "writable": true,
+            "value": 1
+          }
+        },
+        "ownPropertiesLength": 1,
+        "safeGetterValues": {}
+      }
+    }
+  },
+  "notes": null
+});
+
 stubPackets.set("longString message Error", {
   "from": "server1.conn0.child1/consoleActor2",
   "input": "throw new Error(\"Long error \".repeat(10000))",
   "result": {
     "type": "undefined"
   },
   "timestamp": 1493108241073,
   "exception": {
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js
@@ -14,16 +14,17 @@ const { ConsoleMessage } =
 let stubPreparedMessages = new Map();
 let stubPackets = new Map();
 stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "javascript",
   "timeStamp": 1476573167137,
   "type": "log",
+  "helperType": null,
   "level": "error",
   "messageText": "ReferenceError: asdf is not defined",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null}",
   "stacktrace": [
     {
       "filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
       "lineNumber": 3,
@@ -68,16 +69,17 @@ stubPreparedMessages.set("ReferenceError
 }));
 
 stubPreparedMessages.set("SyntaxError: redeclaration of let a", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "javascript",
   "timeStamp": 1487992945524,
   "type": "log",
+  "helperType": null,
   "level": "error",
   "messageText": "SyntaxError: redeclaration of let a",
   "parameters": null,
   "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":9},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"SyntaxError: redeclaration of let a\",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null}",
   "stacktrace": [
     {
       "filename": "resource://testing-common/content-task.js line 52 > eval",
       "lineNumber": 7,
@@ -112,16 +114,17 @@ stubPreparedMessages.set("SyntaxError: r
 }));
 
 stubPreparedMessages.set("TypeError longString message", new ConsoleMessage({
   "id": "1",
   "allowRepeating": true,
   "source": "javascript",
   "timeStamp": 1493109507061,
   "type": "log",
+  "helperType": null,
   "level": "error",
   "messageText": {
     "type": "longString",
     "initial": "Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon",
     "length": 110007,
     "actor": "server1.conn0.child1/longString30"
   },
   "parameters": null,
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -13,16 +13,17 @@ support-files =
   test-location-debugger-link.html
   test-location-styleeditor-link-1.css
   test-location-styleeditor-link-2.css
   test-location-styleeditor-link.html
   test-network-request.html
   test-stacktrace-location-debugger-link.html
   !/devtools/client/framework/test/shared-head.js
 
+[browser_jsterm_inspect.js]
 [browser_netmonitor_shows_reqs_in_webconsole.js]
 [browser_webconsole_batching.js]
 [browser_webconsole_console_dir.js]
 [browser_webconsole_console_group.js]
 [browser_webconsole_console_table.js]
 [browser_webconsole_context_menu_copy_entire_message.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
copy from devtools/client/webconsole/test/browser_jsterm_inspect.js
copy to devtools/client/webconsole/new-console-output/test/mochitest/browser_jsterm_inspect.js
--- a/devtools/client/webconsole/test/browser_jsterm_inspect.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_jsterm_inspect.js
@@ -2,46 +2,61 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Check that the inspect() jsterm helper function works.
 
 "use strict";
 
-const TEST_URI = "data:text/html;charset=utf8,<p>hello bug 869981";
+const TEST_URI = "data:text/html;charset=utf8,<p>test inspect() command";
 
-add_task(function* () {
-  yield loadTab(TEST_URI);
+add_task(async function () {
+  let toolbox = await openNewTabAndToolbox(TEST_URI, "webconsole");
+  let hud = toolbox.getCurrentPanel().hud;
 
-  let hud = yield openConsole();
   let jsterm = hud.jsterm;
 
-  /* Check that the window object is inspected */
-  jsterm.execute("testProp = 'testValue'");
+  info("Test `inspect(window)`");
+  // Add a global value so we can check it later.
+  await jsterm.execute("testProp = 'testValue'");
+  await jsterm.execute("inspect(window)");
 
-  let updated = jsterm.once("variablesview-updated");
-  jsterm.execute("inspect(window)");
-  let view = yield updated;
-  ok(view, "variables view object");
+  const inspectWindowNode = await waitFor(() =>
+    findInspectResultMessage(hud.ui.experimentalOutputNode, 1));
+
+  let objectInspectors = [...inspectWindowNode.querySelectorAll(".tree")];
+  is(objectInspectors.length, 1, "There is the expected number of object inspectors");
+
+  const [windowOi] = objectInspectors;
+  let windowOiNodes = windowOi.querySelectorAll(".node");
 
-  // The single variable view contains a scope with the variable name
-  // and unnamed subitem that contains the properties
-  let variable = view.getScopeAtIndex(0).get(undefined);
-  ok(variable, "variable object");
+  // The tree can be collapsed since the properties are fetched asynchronously.
+  if (windowOiNodes.length === 1) {
+    // If this is the case, we wait for the properties to be fetched and displayed.
+    await waitForNodeMutation(windowOi, {
+      childList: true
+    });
+    windowOiNodes = windowOi.querySelectorAll(".node");
+  }
 
-  yield findVariableViewProperties(variable, [
-    { name: "testProp", value: "testValue" },
-    { name: "document", value: /HTMLDocument \u2192 data:/ },
-  ], { webconsole: hud });
+  let propertiesNodes = [...windowOi.querySelectorAll(".object-label")];
+  const testPropertyLabelNode = propertiesNodes.find(el => el.textContent === "testProp");
+  ok(testPropertyLabelNode, "The testProp property label is displayed as expected");
+
+  const testPropertyValueNode = testPropertyLabelNode
+    .closest(".node")
+    .querySelector(".objectBox");
+  is(testPropertyValueNode.textContent, '"testValue"',
+    "The testProp property value is displayed as expected");
 
   /* Check that a primitive value can be inspected, too */
-  let updated2 = jsterm.once("variablesview-updated");
-  jsterm.execute("inspect(1)");
-  let view2 = yield updated2;
-  ok(view2, "variables view object");
+  info("Test `inspect(1)`");
+  await jsterm.execute("inspect(1)");
 
-  // Check the label of the scope - it should contain the value
-  let scope = view.getScopeAtIndex(0);
-  ok(scope, "variable object");
+  const inspectPrimitiveNode = await waitFor(() =>
+    findInspectResultMessage(hud.ui.experimentalOutputNode, 2));
+  is(inspectPrimitiveNode.textContent, 1, "The primitive is displayed as expected");
+});
 
-  is(scope.name, "1", "The value of the primitive var is correct");
-});
+function findInspectResultMessage(node, index) {
+  return node.querySelectorAll(".message.result")[index];
+}
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_console_dir.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_console_dir.js
@@ -88,18 +88,8 @@ add_task(async function () {
   propertiesNodes = [...objectOi.querySelectorAll(".object-label")]
     .map(el => el.textContent);
   is(JSON.stringify(propertiesNodes), JSON.stringify(objectPropertiesNames));
 });
 
 function findConsoleDir(node, index) {
   return node.querySelectorAll(".dir.message")[index];
 }
-
-function waitForNodeMutation(node, observeConfig = {}) {
-  return new Promise(resolve => {
-    const observer = new MutationObserver(mutations => {
-      resolve(mutations);
-      observer.disconnect();
-    });
-    observer.observe(node, observeConfig);
-  });
-}
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector.js
@@ -94,18 +94,8 @@ add_task(async function () {
 
   arrayOiNodes = arrayOi.querySelectorAll(".node");
   arrayOiNestedObject = arrayOiNodes[3];
   ok(arrayOiNestedObject.querySelector(".arrow").classList.contains("expanded"),
     "The object tree is still expanded");
 
   is(arrayOiNodes.length, 9, "There is the expected number of nodes in the tree");
 });
-
-function waitForNodeMutation(node, observeConfig = {}) {
-  return new Promise(resolve => {
-    const observer = new MutationObserver(mutations => {
-      resolve(mutations);
-      observer.disconnect();
-    });
-    observer.observe(node, observeConfig);
-  });
-}
--- a/devtools/client/webconsole/new-console-output/test/mochitest/head.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/head.js
@@ -1,15 +1,15 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 /* import-globals-from ../../../../framework/test/shared-head.js */
 /* exported WCUL10n, openNewTabAndConsole, waitForMessages, waitFor, findMessage,
-   openContextMenu, hideContextMenu, loadDocument */
+   openContextMenu, hideContextMenu, loadDocument, waitForNodeMutation */
 
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 // Load the shared-head file first.
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
@@ -181,8 +181,26 @@ function hideContextMenu(hud) {
 }
 
 function loadDocument(browser, url) {
   return new Promise(resolve => {
     browser.addEventListener("load", resolve, {capture: true, once: true});
     BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
   });
 }
+
+/**
+* Returns a promise that resolves when the node passed as an argument mutate
+* according to the passed configuration.
+*
+* @param {Node} node - The node to observe mutations on.
+* @param {Object} observeConfig - A configuration object for MutationObserver.observe.
+* @returns {Promise}
+*/
+function waitForNodeMutation(node, observeConfig = {}) {
+  return new Promise(resolve => {
+    const observer = new MutationObserver(mutations => {
+      resolve(mutations);
+      observer.disconnect();
+    });
+    observer.observe(node, observeConfig);
+  });
+}
--- a/devtools/client/webconsole/new-console-output/types.js
+++ b/devtools/client/webconsole/new-console-output/types.js
@@ -26,16 +26,17 @@ exports.ConsoleCommand = function (props
 
 exports.ConsoleMessage = function (props) {
   return Object.assign({
     id: null,
     allowRepeating: true,
     source: null,
     timeStamp: null,
     type: null,
+    helperType: null,
     level: null,
     messageText: null,
     parameters: null,
     repeatId: null,
     stacktrace: null,
     frame: null,
     groupId: null,
     exceptionDocURL: null,
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -36,210 +36,240 @@ function prepareMessage(packet, idGenera
  */
 function transformPacket(packet) {
   if (packet._type) {
     packet = convertCachedPacket(packet);
   }
 
   switch (packet.type) {
     case "consoleAPICall": {
-      let { message } = packet;
-
-      let parameters = message.arguments;
-      let type = message.level;
-      let level = getLevelFromType(type);
-      let messageText = null;
-      const timer = message.timer;
-
-      // Special per-type conversion.
-      switch (type) {
-        case "clear":
-          // We show a message to users when calls console.clear() is called.
-          parameters = [l10n.getStr("consoleCleared")];
-          break;
-        case "count":
-          // Chrome RDP doesn't have a special type for count.
-          type = MESSAGE_TYPE.LOG;
-          let {counter} = message;
-          let label = counter.label ? counter.label : l10n.getStr("noCounterLabel");
-          messageText = `${label}: ${counter.count}`;
-          parameters = null;
-          break;
-        case "time":
-          parameters = null;
-          if (timer && timer.error) {
-            messageText = l10n.getFormatStr(timer.error, [timer.name]);
-            level = MESSAGE_LEVEL.WARN;
-          } else {
-            // We don't show anything for console.time calls to match Chrome's behaviour.
-            type = MESSAGE_TYPE.NULL_MESSAGE;
-          }
-          break;
-        case "timeEnd":
-          parameters = null;
-          if (timer && timer.error) {
-            messageText = l10n.getFormatStr(timer.error, [timer.name]);
-            level = MESSAGE_LEVEL.WARN;
-          } else if (timer) {
-            // We show the duration to users when calls console.timeEnd() is called,
-            // if corresponding console.time() was called before.
-            let duration = Math.round(timer.duration * 100) / 100;
-            messageText = l10n.getFormatStr("timeEnd", [timer.name, duration]);
-          } else {
-            // If the `timer` property does not exists, we don't output anything.
-            type = MESSAGE_TYPE.NULL_MESSAGE;
-          }
-          break;
-        case "table":
-          const supportedClasses = [
-            "Array", "Object", "Map", "Set", "WeakMap", "WeakSet"];
-          if (
-            !Array.isArray(parameters) ||
-            parameters.length === 0 ||
-            !supportedClasses.includes(parameters[0].class)
-          ) {
-            // If the class of the first parameter is not supported,
-            // we handle the call as a simple console.log
-            type = "log";
-          }
-          break;
-        case "group":
-          type = MESSAGE_TYPE.START_GROUP;
-          if (parameters.length === 0) {
-            parameters = [l10n.getStr("noGroupLabel")];
-          }
-          break;
-        case "groupCollapsed":
-          type = MESSAGE_TYPE.START_GROUP_COLLAPSED;
-          if (parameters.length === 0) {
-            parameters = [l10n.getStr("noGroupLabel")];
-          }
-          break;
-        case "groupEnd":
-          type = MESSAGE_TYPE.END_GROUP;
-          parameters = null;
-          break;
-        case "dirxml":
-          // Handle console.dirxml calls as simple console.log
-          type = "log";
-          break;
-      }
-
-      const frame = message.filename ? {
-        source: message.filename,
-        line: message.lineNumber,
-        column: message.columnNumber,
-      } : null;
-
-      return new ConsoleMessage({
-        source: MESSAGE_SOURCE.CONSOLE_API,
-        type,
-        level,
-        parameters,
-        messageText,
-        stacktrace: message.stacktrace ? message.stacktrace : null,
-        frame,
-        timeStamp: message.timeStamp,
-        userProvidedStyles: message.styles,
-      });
+      return transformConsoleAPICallPacket(packet);
     }
 
     case "navigationMessage": {
-      let { message } = packet;
-      return new ConsoleMessage({
-        source: MESSAGE_SOURCE.CONSOLE_API,
-        type: MESSAGE_TYPE.LOG,
-        level: MESSAGE_LEVEL.LOG,
-        messageText: "Navigated to " + message.url,
-        timeStamp: message.timeStamp
-      });
+      return transformNavigationMessagePacket(packet);
     }
 
     case "logMessage": {
-      let { message } = packet;
-      return new ConsoleMessage({
-        source: MESSAGE_SOURCE.CONSOLE_API,
-        type: MESSAGE_TYPE.LOG,
-        level: MESSAGE_LEVEL.LOG,
-        messageText: message.message,
-        timeStamp: message.timeStamp
-      });
+      return transformLogMessagePacket(packet);
     }
 
     case "pageError": {
-      let { pageError } = packet;
-      let level = MESSAGE_LEVEL.ERROR;
-      if (pageError.warning || pageError.strict) {
-        level = MESSAGE_LEVEL.WARN;
-      } else if (pageError.info) {
-        level = MESSAGE_LEVEL.INFO;
-      }
-
-      const frame = pageError.sourceName ? {
-        source: pageError.sourceName,
-        line: pageError.lineNumber,
-        column: pageError.columnNumber
-      } : null;
-
-      let matchesCSS = /^(?:CSS|Layout)\b/.test(pageError.category);
-      let messageSource = matchesCSS ? MESSAGE_SOURCE.CSS
-                                     : MESSAGE_SOURCE.JAVASCRIPT;
-      return new ConsoleMessage({
-        source: messageSource,
-        type: MESSAGE_TYPE.LOG,
-        level,
-        messageText: pageError.errorMessage,
-        stacktrace: pageError.stacktrace ? pageError.stacktrace : null,
-        frame,
-        exceptionDocURL: pageError.exceptionDocURL,
-        timeStamp: pageError.timeStamp,
-        notes: pageError.notes,
-      });
+      return transformPageErrorPacket(packet);
     }
 
     case "networkEvent": {
-      let { networkEvent } = packet;
-
-      return new NetworkEventMessage({
-        actor: networkEvent.actor,
-        isXHR: networkEvent.isXHR,
-        request: networkEvent.request,
-        response: networkEvent.response,
-        timeStamp: networkEvent.timeStamp,
-        totalTime: networkEvent.totalTime,
-      });
+      return transformNetworkEventPacket(packet);
     }
 
     case "evaluationResult":
     default: {
-      let {
-        exceptionMessage: messageText,
-        exceptionDocURL,
-        frame,
-        result: parameters,
-        timestamp: timeStamp,
-        notes,
-      } = packet;
-
-      const level = messageText ? MESSAGE_LEVEL.ERROR : MESSAGE_LEVEL.LOG;
-      return new ConsoleMessage({
-        source: MESSAGE_SOURCE.JAVASCRIPT,
-        type: MESSAGE_TYPE.RESULT,
-        level,
-        messageText,
-        parameters,
-        exceptionDocURL,
-        frame,
-        timeStamp,
-        notes,
-      });
+      return transformEvaluationResultPacket(packet);
     }
   }
 }
 
+function transformConsoleAPICallPacket(packet) {
+  let { message } = packet;
+
+  let parameters = message.arguments;
+  let type = message.level;
+  let level = getLevelFromType(type);
+  let messageText = null;
+  const timer = message.timer;
+
+  // Special per-type conversion.
+  switch (type) {
+    case "clear":
+      // We show a message to users when calls console.clear() is called.
+      parameters = [l10n.getStr("consoleCleared")];
+      break;
+    case "count":
+      // Chrome RDP doesn't have a special type for count.
+      type = MESSAGE_TYPE.LOG;
+      let {counter} = message;
+      let label = counter.label ? counter.label : l10n.getStr("noCounterLabel");
+      messageText = `${label}: ${counter.count}`;
+      parameters = null;
+      break;
+    case "time":
+      parameters = null;
+      if (timer && timer.error) {
+        messageText = l10n.getFormatStr(timer.error, [timer.name]);
+        level = MESSAGE_LEVEL.WARN;
+      } else {
+        // We don't show anything for console.time calls to match Chrome's behaviour.
+        type = MESSAGE_TYPE.NULL_MESSAGE;
+      }
+      break;
+    case "timeEnd":
+      parameters = null;
+      if (timer && timer.error) {
+        messageText = l10n.getFormatStr(timer.error, [timer.name]);
+        level = MESSAGE_LEVEL.WARN;
+      } else if (timer) {
+        // We show the duration to users when calls console.timeEnd() is called,
+        // if corresponding console.time() was called before.
+        let duration = Math.round(timer.duration * 100) / 100;
+        messageText = l10n.getFormatStr("timeEnd", [timer.name, duration]);
+      } else {
+        // If the `timer` property does not exists, we don't output anything.
+        type = MESSAGE_TYPE.NULL_MESSAGE;
+      }
+      break;
+    case "table":
+      const supportedClasses = [
+        "Array", "Object", "Map", "Set", "WeakMap", "WeakSet"];
+      if (
+        !Array.isArray(parameters) ||
+        parameters.length === 0 ||
+        !supportedClasses.includes(parameters[0].class)
+      ) {
+        // If the class of the first parameter is not supported,
+        // we handle the call as a simple console.log
+        type = "log";
+      }
+      break;
+    case "group":
+      type = MESSAGE_TYPE.START_GROUP;
+      if (parameters.length === 0) {
+        parameters = [l10n.getStr("noGroupLabel")];
+      }
+      break;
+    case "groupCollapsed":
+      type = MESSAGE_TYPE.START_GROUP_COLLAPSED;
+      if (parameters.length === 0) {
+        parameters = [l10n.getStr("noGroupLabel")];
+      }
+      break;
+    case "groupEnd":
+      type = MESSAGE_TYPE.END_GROUP;
+      parameters = null;
+      break;
+    case "dirxml":
+      // Handle console.dirxml calls as simple console.log
+      type = "log";
+      break;
+  }
+
+  const frame = message.filename ? {
+    source: message.filename,
+    line: message.lineNumber,
+    column: message.columnNumber,
+  } : null;
+
+  return new ConsoleMessage({
+    source: MESSAGE_SOURCE.CONSOLE_API,
+    type,
+    level,
+    parameters,
+    messageText,
+    stacktrace: message.stacktrace ? message.stacktrace : null,
+    frame,
+    timeStamp: message.timeStamp,
+    userProvidedStyles: message.styles,
+  });
+}
+
+function transformNavigationMessagePacket(packet) {
+  let { message } = packet;
+  return new ConsoleMessage({
+    source: MESSAGE_SOURCE.CONSOLE_API,
+    type: MESSAGE_TYPE.LOG,
+    level: MESSAGE_LEVEL.LOG,
+    messageText: "Navigated to " + message.url,
+    timeStamp: message.timeStamp
+  });
+}
+
+function transformLogMessagePacket(packet) {
+  let { message } = packet;
+  return new ConsoleMessage({
+    source: MESSAGE_SOURCE.CONSOLE_API,
+    type: MESSAGE_TYPE.LOG,
+    level: MESSAGE_LEVEL.LOG,
+    messageText: message.message,
+    timeStamp: message.timeStamp
+  });
+}
+
+function transformPageErrorPacket(packet) {
+  let { pageError } = packet;
+  let level = MESSAGE_LEVEL.ERROR;
+  if (pageError.warning || pageError.strict) {
+    level = MESSAGE_LEVEL.WARN;
+  } else if (pageError.info) {
+    level = MESSAGE_LEVEL.INFO;
+  }
+
+  const frame = pageError.sourceName ? {
+    source: pageError.sourceName,
+    line: pageError.lineNumber,
+    column: pageError.columnNumber
+  } : null;
+
+  let matchesCSS = /^(?:CSS|Layout)\b/.test(pageError.category);
+  let messageSource = matchesCSS ? MESSAGE_SOURCE.CSS
+                                  : MESSAGE_SOURCE.JAVASCRIPT;
+  return new ConsoleMessage({
+    source: messageSource,
+    type: MESSAGE_TYPE.LOG,
+    level,
+    messageText: pageError.errorMessage,
+    stacktrace: pageError.stacktrace ? pageError.stacktrace : null,
+    frame,
+    exceptionDocURL: pageError.exceptionDocURL,
+    timeStamp: pageError.timeStamp,
+    notes: pageError.notes,
+  });
+}
+
+function transformNetworkEventPacket(packet) {
+  let { networkEvent } = packet;
+
+  return new NetworkEventMessage({
+    actor: networkEvent.actor,
+    isXHR: networkEvent.isXHR,
+    request: networkEvent.request,
+    response: networkEvent.response,
+    timeStamp: networkEvent.timeStamp,
+    totalTime: networkEvent.totalTime,
+  });
+}
+
+function transformEvaluationResultPacket(packet) {
+  let {
+    exceptionMessage: messageText,
+    exceptionDocURL,
+    frame,
+    result,
+    helperResult,
+    timestamp: timeStamp,
+    notes,
+  } = packet;
+
+  let parameters = helperResult && helperResult.object
+    ? helperResult.object
+    : result;
+
+  const level = messageText ? MESSAGE_LEVEL.ERROR : MESSAGE_LEVEL.LOG;
+  return new ConsoleMessage({
+    source: MESSAGE_SOURCE.JAVASCRIPT,
+    type: MESSAGE_TYPE.RESULT,
+    helperType: helperResult ? helperResult.type : null,
+    level,
+    messageText,
+    parameters,
+    exceptionDocURL,
+    frame,
+    timeStamp,
+    notes,
+  });
+}
+
 // Helpers
 function getRepeatId(message) {
   return JSON.stringify({
     frame: message.frame,
     groupId: message.groupId,
     indent: message.indent,
     level: message.level,
     messageText: message.messageText,