Bug 1438463 - Fix click on location in browser console with new frontend; r=nchevobbe.
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Fri, 16 Feb 2018 09:14:02 +0100
changeset 404408 43390eee81420fcd1c462b3e775e8926ae407ca8
parent 404407 75e8d75c3de9c10effd6e98388868509674d4593
child 404409 5b8dd2380f3eda126be82974414577a53ca64a27
push id100000
push userncsoregi@mozilla.com
push dateMon, 19 Feb 2018 16:46:49 +0000
treeherdermozilla-inbound@176fb0d46b64 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnchevobbe
bugs1438463
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1438463 - Fix click on location in browser console with new frontend; r=nchevobbe. To fix this, we fallback to viewSource when we don't have access to the toolbox, which is what was done in the old frontend. MozReview-Commit-ID: JCcprTlViMi
devtools/client/webconsole/new-console-output/components/Message.js
devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
devtools/client/webconsole/new-console-output/test/components/message-location.test.js
--- a/devtools/client/webconsole/new-console-output/components/Message.js
+++ b/devtools/client/webconsole/new-console-output/components/Message.js
@@ -160,18 +160,20 @@ class Message extends Component {
       attachment = this.props.attachment;
     } else if (stacktrace && open) {
       attachment = dom.div(
         {
           className: "stacktrace devtools-monospace"
         },
         StackTrace({
           stacktrace: stacktrace,
-          onViewSourceInDebugger: serviceContainer.onViewSourceInDebugger,
-          onViewSourceInScratchpad: serviceContainer.onViewSourceInScratchpad,
+          onViewSourceInDebugger: serviceContainer.onViewSourceInDebugger
+            || serviceContainer.onViewSource,
+          onViewSourceInScratchpad: serviceContainer.onViewSourceInScratchpad
+            || serviceContainer.onViewSource,
           sourceMapService: serviceContainer.sourceMapService,
         })
       );
     }
 
     // If there is an expandable part, make it collapsible.
     let collapse = null;
     if (collapsible) {
@@ -188,17 +190,17 @@ class Message extends Component {
         { className: "message-flex-body error-note" },
         dom.span({ className: "message-body devtools-monospace" },
           "note: " + note.messageBody
         ),
         dom.span({ className: "message-location devtools-monospace" },
           note.frame ? FrameView({
             frame: note.frame,
             onClick: serviceContainer
-              ? serviceContainer.onViewSourceInDebugger
+              ? serviceContainer.onViewSourceInDebugger || serviceContainer.onViewSource
               : undefined,
             showEmptyPathAsHost: true,
             sourceMapService: serviceContainer
               ? serviceContainer.sourceMapService
               : undefined
           }) : null
         )));
     } else {
@@ -208,21 +210,23 @@ class Message extends Component {
     const repeat = this.props.repeat && this.props.repeat > 1 ?
       MessageRepeat({repeat: this.props.repeat}) : null;
 
     let onFrameClick;
     if (serviceContainer && frame) {
       if (source === MESSAGE_SOURCE.CSS) {
         onFrameClick = serviceContainer.onViewSourceInStyleEditor;
       } else if (/^Scratchpad\/\d+$/.test(frame.source)) {
-        onFrameClick = serviceContainer.onViewSourceInScratchpad;
+        onFrameClick = serviceContainer.onViewSourceInScratchpad
+          || serviceContainer.onViewSource;
       } else {
         // Point everything else to debugger, if source not available,
         // it will fall back to view-source.
-        onFrameClick = serviceContainer.onViewSourceInDebugger;
+        onFrameClick = serviceContainer.onViewSourceInDebugger
+          || serviceContainer.onViewSource;
       }
     }
 
     // Configure the location.
     const location = dom.span({ className: "message-location devtools-monospace" },
       frame ? FrameView({
         frame,
         onClick: onFrameClick,
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -95,16 +95,21 @@ NewConsoleOutputWrapper.prototype = {
           return this.document.createElement(nodename);
         },
         getLongString: (grip) => {
           return hud.proxy.webConsoleClient.getString(grip);
         },
         requestData(id, type) {
           return hud.proxy.networkDataProvider.requestData(id, type);
         },
+        onViewSource(frame) {
+          if (hud && hud.owner && hud.owner.viewSource) {
+            hud.owner.viewSource(frame.url, frame.line);
+          }
+        }
       };
 
       // Set `openContextMenu` this way so, `serviceContainer` variable
       // is available in the current scope and we can pass it into
       // `createContextMenu` method.
       serviceContainer.openContextMenu = (e, message) => {
         let { screenX, screenY, target } = e;
 
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/components/message-location.test.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test utils.
+const expect = require("expect");
+const { mount } = require("enzyme");
+const sinon = require("sinon");
+const { createFactory } = require("devtools/client/shared/vendor/react");
+const serviceContainer = require("devtools/client/webconsole/new-console-output/test/fixtures/serviceContainer");
+
+let { MessageContainer } = require("devtools/client/webconsole/new-console-output/components/MessageContainer");
+MessageContainer = createFactory(MessageContainer);
+
+// Test fakes.
+const { stubPreparedMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
+
+describe("Message - location element", () => {
+  it("Calls onViewSourceInDebugger when clicked", () => {
+    const onViewSourceInDebugger = sinon.spy();
+    const onViewSource = sinon.spy();
+
+    const message = stubPreparedMessages.get("console.log('foobar', 'test')");
+    const wrapper = mount(MessageContainer({
+      getMessage: () => message,
+      serviceContainer: Object.assign({}, serviceContainer, {
+        onViewSourceInDebugger,
+        onViewSource,
+      })
+    }));
+
+    // There should be the location
+    const locationLink = wrapper.find(`.message-location a`);
+    expect(locationLink.length).toBe(1);
+    expect(locationLink.text()).toBe("test-console-api.html:1:27");
+
+    locationLink.simulate("click");
+
+    expect(onViewSourceInDebugger.calledOnce).toBe(true);
+    expect(onViewSource.notCalled).toBe(true);
+  });
+
+  it.only("Calls onViewSource when clicked and onViewSourceInDebugger undefined", () => {
+    const onViewSource = sinon.spy();
+
+    const message = stubPreparedMessages.get("console.log('foobar', 'test')");
+
+    const wrapper = mount(MessageContainer({
+      getMessage: () => message,
+      serviceContainer: Object.assign({}, serviceContainer, {
+        onViewSource,
+        onViewSourceInDebugger: undefined,
+      })
+    }));
+
+    // There should be the location
+    const locationLink = wrapper.find(`.message-location a`);
+
+    locationLink.simulate("click");
+    expect(onViewSource.calledOnce).toBe(true);
+  });
+});