summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/node/components/evaluation-result.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/webconsole/test/node/components/evaluation-result.test.js')
-rw-r--r--devtools/client/webconsole/test/node/components/evaluation-result.test.js505
1 files changed, 505 insertions, 0 deletions
diff --git a/devtools/client/webconsole/test/node/components/evaluation-result.test.js b/devtools/client/webconsole/test/node/components/evaluation-result.test.js
new file mode 100644
index 0000000000..9cbca548ed
--- /dev/null
+++ b/devtools/client/webconsole/test/node/components/evaluation-result.test.js
@@ -0,0 +1,505 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test utils.
+const expect = require("expect");
+const { render, mount } = require("enzyme");
+const sinon = require("sinon");
+
+// React
+const {
+ createFactory,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const Provider = createFactory(
+ require("resource://devtools/client/shared/vendor/react-redux.js").Provider
+);
+const {
+ formatErrorTextWithCausedBy,
+ setupStore,
+} = require("resource://devtools/client/webconsole/test/node/helpers.js");
+
+// Components under test.
+const EvaluationResult = createFactory(
+ require("resource://devtools/client/webconsole/components/Output/message-types/EvaluationResult.js")
+);
+const {
+ INDENT_WIDTH,
+} = require("resource://devtools/client/webconsole/components/Output/MessageIndent.js");
+
+// Test fakes.
+const {
+ stubPreparedMessages,
+} = require("resource://devtools/client/webconsole/test/node/fixtures/stubs/index.js");
+const serviceContainer = require("resource://devtools/client/webconsole/test/node/fixtures/serviceContainer.js");
+
+describe("EvaluationResult component:", () => {
+ it.skip("renders a grip result", () => {
+ const message = stubPreparedMessages.get("new Date(0)");
+ // We need to wrap the ConsoleApiElement in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+
+ expect(wrapper.find(".message-body").text()).toBe(
+ "Date 1970-01-01T00:00:00.000Z"
+ );
+
+ expect(wrapper.hasClass("message")).toBe(true);
+ expect(wrapper.hasClass("log")).toBe(true);
+ });
+
+ it("renders an error", () => {
+ const message = stubPreparedMessages.get("asdf()");
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+
+ expect(wrapper.find(".message-body").text()).toBe(
+ "Uncaught ReferenceError: asdf is not defined[Learn More]"
+ );
+
+ expect(wrapper.hasClass("message")).toBe(true);
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("renders an error with a longString exception message", () => {
+ const message = stubPreparedMessages.get("longString message Error");
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+
+ const text = wrapper.find(".message-body").text();
+ expect(text.startsWith("Uncaught Error: Long error Long error")).toBe(true);
+ expect(wrapper.hasClass("message")).toBe(true);
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("renders thrown empty string", () => {
+ const message = stubPreparedMessages.get(`eval throw ""`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught <empty string>");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("renders thrown string", () => {
+ const message = stubPreparedMessages.get(`eval throw "tomato"`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught tomato");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Boolean", () => {
+ const message = stubPreparedMessages.get(`eval throw false`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught false");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Number", () => {
+ const message = stubPreparedMessages.get(`eval throw 0`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught 0");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown null", () => {
+ const message = stubPreparedMessages.get(`eval throw null`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught null");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown undefined", () => {
+ const message = stubPreparedMessages.get(`eval throw undefined`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught undefined");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Symbol", () => {
+ const message = stubPreparedMessages.get(`eval throw Symbol`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe('Uncaught Symbol("potato")');
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Object", () => {
+ const message = stubPreparedMessages.get(`eval throw Object`);
+ // We need to wrap the EvaluationResult in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe(`Uncaught Object { vegetable: "cucumber" }`);
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error Object", () => {
+ const message = stubPreparedMessages.get(`eval throw Error Object`);
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught Error: pumpkin");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with custom name", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with custom name`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe("Uncaught JuicyError: pineapple");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with an error cause", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with error cause`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe(
+ "Uncaught Error: something went wrong\nCaused by: SyntaxError: original error"
+ );
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with an error cause chain", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with cause chain`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe(
+ [
+ "Uncaught Error: err-d",
+ "Caused by: Error: err-c",
+ "Caused by: Error: err-b",
+ "Caused by: Error: err-a",
+ ].join("\n")
+ );
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with a cyclical error cause chain", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with cyclical cause chain`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe(
+ [
+ "Uncaught Error: err-y",
+ "Caused by: Error: err-x",
+ // TODO: it shouldn't be displayed like this. This will
+ // be fixed in Bug 1719605
+ "Caused by: undefined",
+ ].join("\n")
+ );
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with a falsy cause", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with falsy cause`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe("Uncaught Error: false cause\nCaused by: false");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with a null cause", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with null cause`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe("Uncaught Error: null cause\nCaused by: null");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with an undefined cause", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with undefined cause`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe("Uncaught Error: undefined cause\nCaused by: undefined");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with a number cause", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with number cause`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe("Uncaught Error: number cause\nCaused by: 0");
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with a string cause", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with string cause`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe(
+ `Uncaught Error: string cause\nCaused by: "cause message"`
+ );
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render thrown Error object with object cause", () => {
+ const message = stubPreparedMessages.get(
+ `eval throw Error Object with object cause`
+ );
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+ const text = formatErrorTextWithCausedBy(
+ wrapper.find(".message-body").text()
+ );
+ expect(text).toBe(`Uncaught Error: object cause\nCaused by: Object { … }`);
+ expect(wrapper.hasClass("error")).toBe(true);
+ });
+
+ it("render pending Promise", () => {
+ const message = stubPreparedMessages.get(`eval pending promise`);
+ // We need to wrap the EvaluationResult in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe(`Promise { <state>: "pending" }`);
+ });
+
+ it("render Promise.resolve result", () => {
+ const message = stubPreparedMessages.get(`eval Promise.resolve`);
+ // We need to wrap the EvaluationResult in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe(`Promise { <state>: "fulfilled", <value>: 123 }`);
+ });
+
+ it("render Promise.reject result", () => {
+ const message = stubPreparedMessages.get(`eval Promise.reject`);
+ // We need to wrap the EvaluationResult in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe(`Promise { <state>: "rejected", <reason>: "ouch" }`);
+ });
+
+ it("render promise fulfilled in microtask", () => {
+ // See Bug 1439963
+ const message = stubPreparedMessages.get(`eval resolved promise`);
+ // We need to wrap the EvaluationResult in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe(`Promise { <state>: "fulfilled", <value>: 246 }`);
+ });
+
+ it("render promise rejected in microtask", () => {
+ // See Bug 1439963
+ const message = stubPreparedMessages.get(`eval rejected promise`);
+ // We need to wrap the EvaluationResult in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe(
+ `Promise { <state>: "rejected", <reason>: ReferenceError }`
+ );
+ });
+
+ it("render rejected promise with Error with cause", () => {
+ const message = stubPreparedMessages.get(`eval rejected promise`);
+ // We need to wrap the EvaluationResult in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ const text = wrapper.find(".message-body").text();
+ expect(text).toBe(
+ `Promise { <state>: "rejected", <reason>: ReferenceError }`
+ );
+ });
+
+ it("renders an inspect command result", () => {
+ const message = stubPreparedMessages.get("inspect({a: 1})");
+ // We need to wrap the ConsoleApiElement in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+
+ 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,
+ dispatch: () => {},
+ })
+ )
+ );
+
+ const url =
+ "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined";
+ const learnMore = wrapper.find(".learn-more-link");
+ expect(learnMore.length).toBe(1);
+ expect(learnMore.prop("title")).toBe(url);
+
+ learnMore.simulate("click");
+ const call = serviceContainer.openLink.getCall(0);
+ expect(call.args[0]).toEqual(message.exceptionDocURL);
+ });
+
+ it("has the expected indent", () => {
+ const message = stubPreparedMessages.get("new Date(0)");
+
+ const indent = 10;
+ // We need to wrap the ConsoleApiElement in a Provider in order for the
+ // ObjectInspector to work.
+ let wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({
+ message: Object.assign({}, message, { indent }),
+ serviceContainer,
+ })
+ )
+ );
+ expect(wrapper.prop("data-indent")).toBe(`${indent}`);
+ const indentEl = wrapper.find(".indent");
+ expect(indentEl.prop("style").width).toBe(`${indent * INDENT_WIDTH}px`);
+
+ wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({ message, serviceContainer })
+ )
+ );
+ expect(wrapper.prop("data-indent")).toBe(`0`);
+ // there's no indent element where the indent is 0
+ expect(wrapper.find(".indent").length).toBe(0);
+ });
+
+ it("has location information", () => {
+ const message = stubPreparedMessages.get("1 + @");
+ const wrapper = render(EvaluationResult({ message, serviceContainer }));
+
+ const locationLink = wrapper.find(`.message-location`);
+ expect(locationLink.length).toBe(1);
+ expect(locationLink.text()).toBe("debugger eval code:1:4");
+ });
+
+ it("has a timestamp when passed a truthy timestampsVisible prop", () => {
+ const message = stubPreparedMessages.get("new Date(0)");
+ // We need to wrap the ConsoleApiElement in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({
+ message,
+ serviceContainer,
+ timestampsVisible: true,
+ })
+ )
+ );
+ const {
+ timestampString,
+ } = require("resource://devtools/client/webconsole/utils/l10n.js");
+
+ expect(wrapper.find(".timestamp").text()).toBe(
+ timestampString(message.timeStamp)
+ );
+ });
+
+ it("does not have a timestamp when timestampsVisible prop is falsy", () => {
+ const message = stubPreparedMessages.get("new Date(0)");
+ // We need to wrap the ConsoleApiElement in a Provider in order for the
+ // ObjectInspector to work.
+ const wrapper = render(
+ Provider(
+ { store: setupStore() },
+ EvaluationResult({
+ message,
+ serviceContainer,
+ timestampsVisible: false,
+ })
+ )
+ );
+
+ expect(wrapper.find(".timestamp").length).toBe(0);
+ });
+});