Bug 1385032 - add logErrorInPage to tab target in devtools; r?bgrins draft
authorTom Tromey <tom@tromey.com>
Fri, 07 Jul 2017 12:53:32 -0600
changeset 617575 dc91982c89772a03a91a1c66f6887b596b33837a
parent 617574 4de88c868d39d9da24acb8836d0b8e45a4457b4c
child 639843 eb958b770747af35d9399217c3d59b7e126f0ffe
push id71081
push userbmo:ttromey@mozilla.com
push dateFri, 28 Jul 2017 16:52:57 +0000
reviewersbgrins
bugs1385032
milestone56.0a1
Bug 1385032 - add logErrorInPage to tab target in devtools; r?bgrins This adds a method that can be called by the toolbox to log something to the web console. MozReview-Commit-ID: GpZtWwNVVGO
devtools/client/framework/target.js
devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_logErrorInPage.js
devtools/server/actors/tab.js
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -707,16 +707,36 @@ TabTarget.prototype = {
     this._url = null;
     this.threadActor = null;
   },
 
   toString: function () {
     let id = this._tab ? this._tab : (this._form && this._form.actor);
     return `TabTarget:${id}`;
   },
+
+  /**
+   * Log an error of some kind to the tab's console.
+   *
+   * @param {String} text
+   *                 The text to log.
+   * @param {String} category
+   *                 The category of the message.  @see nsIScriptError.
+   */
+  logErrorInPage: function (text, category) {
+    if (this.activeTab && this.activeTab.traits.logErrorInPage) {
+      let packet = {
+        to: this.form.actor,
+        type: "logErrorInPage",
+        text,
+        category,
+      };
+      this.client.request(packet);
+    }
+  },
 };
 
 /**
  * WebProgressListener for TabTarget.
  *
  * @param object target
  *        The TabTarget instance to work with.
  */
@@ -857,10 +877,14 @@ WorkerTarget.prototype = {
   },
 
   getTrait: function () {
     return undefined;
   },
 
   makeRemote: function () {
     return Promise.resolve();
-  }
+  },
+
+  logErrorInPage: function () {
+    // No-op.  See bug 1368680.
+  },
 };
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -35,16 +35,17 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_webconsole_filters.js]
 [browser_webconsole_filters_persist.js]
 [browser_webconsole_init.js]
 [browser_webconsole_input_focus.js]
 [browser_webconsole_keyboard_accessibility.js]
 [browser_webconsole_location_debugger_link.js]
 [browser_webconsole_location_scratchpad_link.js]
 [browser_webconsole_location_styleeditor_link.js]
+[browser_webconsole_logErrorInPage.js]
 [browser_webconsole_network_messages_click.js]
 [browser_webconsole_nodes_highlight.js]
 [browser_webconsole_nodes_select.js]
 [browser_webconsole_object_inspector.js]
 [browser_webconsole_observer_notifications.js]
 [browser_webconsole_shows_reqs_in_netmonitor.js]
 [browser_webconsole_stacktrace_location_debugger_link.js]
 [browser_webconsole_stacktrace_location_scratchpad_link.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_logErrorInPage.js
@@ -0,0 +1,20 @@
+/* -*- 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/ */
+
+"use strict";
+
+// Test that we can log a message to the web console from the toolbox.
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>test logErrorInPage";
+
+add_task(async function () {
+  const hud = await openNewTabAndConsole(TEST_URI);
+  const toolbox = hud.ui.newConsoleOutput.toolbox;
+
+  toolbox.target.logErrorInPage("beware the octopus", "content javascript");
+
+  const node = await waitFor(() => findMessage(hud, "octopus"));
+  ok(node, "text is displayed in web console");
+});
--- a/devtools/server/actors/tab.js
+++ b/devtools/server/actors/tab.js
@@ -7,17 +7,17 @@
 "use strict";
 
 /* global XPCNativeWrapper */
 
 // For performance matters, this file should only be loaded in the targeted
 // document process. For example, it shouldn't be evaluated in the parent
 // process until we try to debug a document living in the parent process.
 
-var { Ci, Cu, Cr } = require("chrome");
+var { Ci, Cu, Cr, Cc } = require("chrome");
 var Services = require("Services");
 var { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 var promise = require("promise");
 var {
   ActorPool, createExtraActors, appendExtraActors
 } = require("devtools/server/actors/common");
 var { DebuggerServer } = require("devtools/server/main");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
@@ -221,17 +221,19 @@ function TabActor(connection) {
 
   this.traits = {
     reconfigure: true,
     // Supports frame listing via `listFrames` request and `frameUpdate` events
     // as well as frame switching via `switchToFrame` request
     frames: true,
     // Do not require to send reconfigure request to reset the document state
     // to what it was before using the TabActor
-    noTabReconfigureOnClose: true
+    noTabReconfigureOnClose: true,
+    // Supports the logErrorInPage request.
+    logErrorInPage: true,
   };
 
   this._workerActorList = null;
   this._workerActorPool = null;
   this._onWorkerActorListChanged = this._onWorkerActorListChanged.bind(this);
 }
 
 // XXX (bug 710213): TabActor attach/detach/exit/destroy is a
@@ -656,16 +658,27 @@ TabActor.prototype = {
 
       return {
         "from": this.actorID,
         "workers": actors.map((actor) => actor.form())
       };
     });
   },
 
+  onLogErrorInPage(request) {
+    let {text, category} = request;
+    let scriptErrorClass = Cc["@mozilla.org/scripterror;1"];
+    let scriptError = scriptErrorClass.createInstance(Ci.nsIScriptError);
+    scriptError.initWithWindowID(text, null, null, 0, 0, 1,
+                                 category, getInnerId(this.window));
+    let console = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+    console.logMessage(scriptError);
+    return {};
+  },
+
   _onWorkerActorListChanged() {
     this._workerActorList.onListChanged = null;
     this.conn.sendActorEvent(this.actorID, "workerListChanged");
   },
 
   observe(subject, topic, data) {
     // Ignore any event that comes before/after the tab actor is attached
     // That typically happens during firefox shutdown.
@@ -1421,16 +1434,17 @@ TabActor.prototype.requestTypes = {
   "detach": TabActor.prototype.onDetach,
   "focus": TabActor.prototype.onFocus,
   "reload": TabActor.prototype.onReload,
   "navigateTo": TabActor.prototype.onNavigateTo,
   "reconfigure": TabActor.prototype.onReconfigure,
   "switchToFrame": TabActor.prototype.onSwitchToFrame,
   "listFrames": TabActor.prototype.onListFrames,
   "listWorkers": TabActor.prototype.onListWorkers,
+  "logErrorInPage": TabActor.prototype.onLogErrorInPage,
 };
 
 exports.TabActor = TabActor;
 
 /**
  * The DebuggerProgressListener object is an nsIWebProgressListener which
  * handles onStateChange events for the inspected browser. If the user tries to
  * navigate away from a paused page, the listener makes sure that the debuggee