--- a/devtools/client/webconsole/new-console-output/actions/messages.js
+++ b/devtools/client/webconsole/new-console-output/actions/messages.js
@@ -4,27 +4,34 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
prepareMessage
} = require("devtools/client/webconsole/new-console-output/utils/messages");
+const { IdGenerator } = require("devtools/client/webconsole/new-console-output/utils/id-generator");
const {
MESSAGE_ADD,
MESSAGES_CLEAR,
SEVERITY_FILTER,
MESSAGES_SEARCH,
FILTERS_CLEAR,
} = require("../constants");
-function messageAdd(packet) {
- let message = prepareMessage(packet);
+const defaultIdGenerator = new IdGenerator();
+
+function messageAdd(packet, idGenerator = null) {
+ if (idGenerator == null) {
+ idGenerator = defaultIdGenerator;
+ }
+ let message = prepareMessage(packet, idGenerator);
+
return {
type: MESSAGE_ADD,
message
};
}
function messagesClear() {
return {
--- a/devtools/client/webconsole/new-console-output/moz.build
+++ b/devtools/client/webconsole/new-console-output/moz.build
@@ -13,16 +13,8 @@ DIRS += [
DevToolsModules(
'constants.js',
'main.js',
'new-console-output-wrapper.js',
'store.js',
'types.js',
)
-
-MOCHITEST_CHROME_MANIFESTS += [
- 'test/chrome/chrome.ini'
-]
-XPCSHELL_TESTS_MANIFESTS += [
- 'test/store/xpcshell.ini'
-]
-
--- a/devtools/client/webconsole/new-console-output/test/actions/messages.test.js
+++ b/devtools/client/webconsole/new-console-output/test/actions/messages.test.js
@@ -1,23 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
-const {
- messageAdd,
- messagesClear
-} = require("devtools/client/webconsole/new-console-output/actions/messages");
const { getRepeatId } = require("devtools/client/webconsole/new-console-output/utils/messages");
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
+const { setupActions } = require("devtools/client/webconsole/new-console-output/test/helpers");
const constants = require("devtools/client/webconsole/new-console-output/constants");
const expect = require("expect");
+let actions;
+
describe("Message actions:", () => {
+ before(()=>{
+ actions = setupActions();
+ });
+
describe("messageAdd", () => {
it("creates expected action given a packet", () => {
const packet = {
"from": "server1.conn4.child1/consoleActor2",
"type": "consoleAPICall",
"message": {
"arguments": [
"foobar",
@@ -33,33 +36,33 @@ describe("Message actions:", () => {
"private": false,
"styles": [],
"timeStamp": 1455064271115,
"timer": null,
"workerType": "none",
"category": "webdev"
}
};
- const action = messageAdd(packet);
+ const action = actions.messageAdd(packet);
const expected = {
type: constants.MESSAGE_ADD,
message: stubConsoleMessages.get("console.log('foobar', 'test')")
};
// Some values on the message are generated by prepareMessage. Manually set
// these on the expected message to match.
expected.message = expected.message.set("repeatId", getRepeatId(expected.message));
- expected.message = expected.message.set("id", "0");
+ expected.message = expected.message.set("id", "1");
expect(action).toEqual(expected);
});
});
describe("messagesClear", () => {
it("creates expected action", () => {
- const action = messagesClear();
+ const action = actions.messagesClear();
const expected = {
type: constants.MESSAGES_CLEAR,
};
expect(action).toEqual(expected);
});
});
});
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs.js
@@ -92,16 +92,29 @@ exports.stubConsoleMessages = new Map([
],
repeat: 1,
repeatId: null,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
})
],
[
+ "console.clear()",
+ new ConsoleMessage({
+ allowRepeating: true,
+ source: MESSAGE_SOURCE.CONSOLE_API,
+ type: MESSAGE_TYPE.CLEAR,
+ level: MESSAGE_LEVEL.LOG,
+ messageText: null,
+ parameters: ["Console cleared."],
+ repeat: 1,
+ repeatId: null,
+ })
+ ],
+ [
"console.count('bar')",
new ConsoleMessage({
allowRepeating: true,
source: MESSAGE_SOURCE.CONSOLE_API,
type: MESSAGE_TYPE.LOG,
level: MESSAGE_LEVEL.DEBUG,
messageText: "bar: 1",
parameters: null,
--- a/devtools/client/webconsole/new-console-output/test/helpers.js
+++ b/devtools/client/webconsole/new-console-output/test/helpers.js
@@ -2,16 +2,53 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let ReactDOM = require("devtools/client/shared/vendor/react-dom");
let React = require("devtools/client/shared/vendor/react");
var TestUtils = React.addons.TestUtils;
+const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
+const { configureStore } = require("devtools/client/webconsole/new-console-output/store");
+const { IdGenerator } = require("devtools/client/webconsole/new-console-output/utils/id-generator");
+const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
+const Services = require("devtools/client/webconsole/new-console-output/test/fixtures/Services");
+
+/**
+ * Prepare actions for use in testing.
+ */
+function setupActions() {
+ // Some actions use dependency injection. This helps them avoid using state in
+ // a hard-to-test way. We need to inject stubbed versions of these dependencies.
+ const wrappedActions = Object.assign({}, actions);
+
+ const idGenerator = new IdGenerator();
+ wrappedActions.messageAdd = (packet) => {
+ return actions.messageAdd(packet, idGenerator);
+ };
+
+ return wrappedActions;
+}
+
+/**
+ * Prepare the store for use in testing.
+ */
+function setupStore(input) {
+ // Inject the Services stub.
+ const store = configureStore(Services);
+
+ // Add the messages from the input commands to the store.
+ input.forEach((cmd) => {
+ store.dispatch(actions.messageAdd(stubConsoleMessages.get(cmd)));
+ });
+
+ return store;
+}
+
function renderComponent(component, props) {
const el = React.createElement(component, props, {});
// By default, renderIntoDocument() won't work for stateless components, but
// it will work if the stateless component is wrapped in a stateful one.
// See https://github.com/facebook/react/issues/4839
const wrappedEl = React.DOM.span({}, [el]);
const renderedComponent = TestUtils.renderIntoDocument(wrappedEl);
return ReactDOM.findDOMNode(renderedComponent).children[0];
@@ -20,11 +57,13 @@ function renderComponent(component, prop
function shallowRenderComponent(component, props) {
const el = React.createElement(component, props);
const renderer = TestUtils.createRenderer();
renderer.render(el, {});
return renderer.getRenderOutput();
}
module.exports = {
+ setupActions,
+ setupStore,
renderComponent,
shallowRenderComponent
};
--- a/devtools/client/webconsole/new-console-output/test/moz.build
+++ b/devtools/client/webconsole/new-console-output/test/moz.build
@@ -2,8 +2,11 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'fixtures'
]
+MOCHITEST_CHROME_MANIFESTS += [
+ 'chrome/chrome.ini'
+]
--- a/devtools/client/webconsole/new-console-output/test/store/filters.test.js
+++ b/devtools/client/webconsole/new-console-output/test/store/filters.test.js
@@ -2,38 +2,23 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const expect = require("expect");
const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
const { getAllMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
-const { configureStore } = require("devtools/client/webconsole/new-console-output/store");
-const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
-const Services = require("devtools/client/webconsole/new-console-output/test/fixtures/Services");
+const { setupStore } = require("devtools/client/webconsole/new-console-output/test/helpers");
describe("Search", () => {
it("matches on value grips", () => {
const store = setupStore([
"console.log('foobar', 'test')",
"console.warn('danger, will robinson!')",
"console.log(undefined)"
]);
store.dispatch(actions.messagesSearch("danger"));
let messages = getAllMessages(store.getState());
expect(messages.size).toEqual(1);
});
});
-
-function setupStore(input) {
- const store = configureStore(Services);
- addMessages(input, store.dispatch);
- return store;
-}
-
-function addMessages(input, dispatch) {
- input.forEach((cmd) => {
- dispatch(actions.messageAdd(stubConsoleMessages.get(cmd)));
- });
-}
-
deleted file mode 100644
--- a/devtools/client/webconsole/new-console-output/test/store/head.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/* exported configureStore */
-
-"use strict";
-
-var { utils: Cu } = Components;
-var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
-const Services = require("Services");
-
-var DevToolsUtils = require("devtools/shared/DevToolsUtils");
-var flags = require("devtools/shared/flags");
-flags.testing = true;
-flags.wantLogging = true;
-flags.wantVerbose = false;
-
-const { configureStore } = require("devtools/client/webconsole/new-console-output/store");
-
-const testPackets = new Map();
-testPackets.set("console.log", {
- "from": "server1.conn4.child1/consoleActor2",
- "type": "consoleAPICall",
- "message": {
- "arguments": [
- "foobar",
- "test"
- ],
- "columnNumber": 1,
- "counter": null,
- "filename": "file:///test.html",
- "functionName": "",
- "groupName": "",
- "level": "log",
- "lineNumber": 1,
- "private": false,
- "styles": [],
- "timeStamp": 1455064271115,
- "timer": null,
- "workerType": "none",
- "category": "webdev"
- }
-});
-
-testPackets.set("console.clear", {
- "from": "server1.conn1.child1/consoleActor2",
- "type": "consoleAPICall",
- "message": {
- "arguments": [],
- "columnNumber": 1,
- "counter": null,
- "filename": "debugger eval code",
- "functionName": "",
- "groupName": "",
- "level": "clear",
- "lineNumber": 1,
- "private": false,
- "timeStamp": 1462571355142,
- "timer": null,
- "workerType": "none",
- "styles": [],
- "category": "webdev"
- }
-});
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/store/messages.test.js
@@ -0,0 +1,99 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { getAllMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
+const { getRepeatId } = require("devtools/client/webconsole/new-console-output/utils/messages");
+const {
+ setupActions,
+ setupStore
+} = require("devtools/client/webconsole/new-console-output/test/helpers");
+const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
+
+const expect = require("expect");
+
+describe("Message reducer:", () => {
+ let actions;
+
+ before(() => {
+ actions = setupActions();
+ });
+
+ it("adds a message to an empty store", () => {
+ const { dispatch, getState } = setupStore([]);
+
+ const message = stubConsoleMessages.get("console.log('foobar', 'test')");
+ dispatch(actions.messageAdd(message));
+
+ const messages = getAllMessages(getState());
+
+ // @TODO Remove repeatId once stubs are generated using prepareMessage.
+ let expected = message.set("repeatId", getRepeatId(message)).set("id", "1");
+ expect(messages.first()).toEqual(expected);
+ });
+
+ it("increments repeat on a repeating message", () => {
+ const { dispatch, getState } = setupStore([
+ "console.log('foobar', 'test')",
+ "console.log('foobar', 'test')"
+ ]);
+
+ const message = stubConsoleMessages.get("console.log('foobar', 'test')");
+ dispatch(actions.messageAdd(message));
+ dispatch(actions.messageAdd(message));
+
+ const messages = getAllMessages(getState());
+
+ expect(messages.size).toBe(1);
+ expect(messages.first().repeat).toBe(4);
+ });
+
+ it("does not clobber a unique message", () => {
+ const { dispatch, getState } = setupStore([
+ "console.log('foobar', 'test')",
+ "console.log('foobar', 'test')"
+ ]);
+
+ const message = stubConsoleMessages.get("console.log('foobar', 'test')");
+ dispatch(actions.messageAdd(message));
+
+ const message2 = stubConsoleMessages.get("console.log(undefined)");
+ dispatch(actions.messageAdd(message2));
+
+ const messages = getAllMessages(getState());
+
+ expect(messages.size).toBe(2);
+ expect(messages.first().repeat).toBe(3);
+ expect(messages.last().repeat).toBe(1);
+ });
+
+ it("clears the store in response to console.clear()", () => {
+ const { dispatch, getState } = setupStore([
+ "console.log('foobar', 'test')",
+ "console.log(undefined)"
+ ]);
+
+ dispatch(actions.messageAdd(stubConsoleMessages.get("console.clear()")));
+
+ const messages = getAllMessages(getState());
+
+ expect(messages.size).toBe(1);
+ expect(messages.first().parameters[0]).toBe("Console cleared.");
+ });
+
+ it("limits the number of messages displayed", () => {
+ const { dispatch, getState } = setupStore([]);
+
+ const logLimit = 1000;
+ const baseMessage = stubConsoleMessages.get("console.log(undefined)");
+ for (let i = 1; i <= logLimit + 1; i++) {
+ const msg = baseMessage.set("parameters", [`message num ${i}`]);
+ dispatch(actions.messageAdd(msg));
+ }
+
+ const messages = getAllMessages(getState());
+ expect(messages.count()).toBe(logLimit);
+ expect(messages.first().parameters[0]).toBe(`message num 2`);
+ expect(messages.last().parameters[0]).toBe(`message num ${logLimit + 1}`);
+ });
+});
deleted file mode 100644
--- a/devtools/client/webconsole/new-console-output/test/store/test_messages.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
-const packet = testPackets.get("console.log");
-const clearPacket = testPackets.get("console.clear");
-const {
- getRepeatId,
- prepareMessage
-} = require("devtools/client/webconsole/new-console-output/utils/messages");
-const { getAllMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
-
-function run_test() {
- run_next_test();
-}
-
-/**
- * Test adding a message to the store.
- */
-add_task(function* () {
- const { getState, dispatch } = configureStore();
-
- dispatch(actions.messageAdd(packet));
-
- const expectedMessage = prepareMessage(packet);
-
- const messages = getAllMessages(getState());
- equal(messages.size, 1, "We added exactly one message.")
-
- const message = messages.first();
- notEqual(message.id, expectedMessage.id, "ID should be unique.");
- // Remove ID for deepEqual comparison.
- deepEqual(message.remove('id'), expectedMessage.remove('id'),
- "MESSAGE_ADD action adds a message");
-});
-
-/**
- * Test repeating messages in the store.
- */
-add_task(function* () {
- const { getState, dispatch } = configureStore();
-
- dispatch(actions.messageAdd(packet));
- dispatch(actions.messageAdd(packet));
- dispatch(actions.messageAdd(packet));
-
- const messages = getAllMessages(getState());
- equal(messages.size, 1,
- "Repeated messages don't increase message list size");
- equal(messages.first().repeat, 3, "Repeated message is updated as expected");
-
- let newPacket = Object.assign({}, packet);
- newPacket.message.arguments = ["funny"];
- dispatch(actions.messageAdd(newPacket));
-
- equal(getAllMessages(getState()).size, 2,
- "Non-repeated messages aren't clobbered");
-});
-
-/**
- * Test getRepeatId().
- */
-add_task(function* () {
- const message1 = prepareMessage(packet);
- let message2 = prepareMessage(packet);
- equal(getRepeatId(message1), getRepeatId(message2),
- "getRepeatId() returns same repeat id for objects with the same values");
-
- message2 = message2.set("parameters", ["new args"]);
- notEqual(getRepeatId(message1), getRepeatId(message2),
- "getRepeatId() returns different repeat ids for different values");
-});
-
-/**
- * Test adding a console.clear message to the store.
- */
-add_task(function*() {
- const { getState, dispatch } = configureStore();
-
- dispatch(actions.messageAdd(packet));
-
- let messages = getAllMessages(getState());
- equal(messages.size, 1,
- "MESSAGE_ADD action adds a message");
-
- dispatch(actions.messageAdd(clearPacket));
-
- messages = getAllMessages(getState());
- deepEqual(messages.first().remove('id'), prepareMessage(clearPacket).remove('id'),
- "console.clear clears existing messages and add a new one");
-});
-
-/**
- * Test message limit on the store.
- */
-add_task(function* () {
- const { getState, dispatch } = configureStore();
- const logLimit = 1000;
- const messageNumber = logLimit + 1;
-
- let newPacket = Object.assign({}, packet);
- for (let i = 1; i <= messageNumber; i++) {
- newPacket.message.arguments = [i];
- dispatch(actions.messageAdd(newPacket));
- }
-
- let messages = getAllMessages(getState());
- equal(messages.count(), logLimit, "Messages are pruned up to the log limit");
- deepEqual(messages.last().parameters, [messageNumber],
- "The last message is the expected one");
-});
-
-/**
- * Test message limit on the store with user set prefs.
- */
-add_task(function* () {
- const userSetLimit = 10;
- Services.prefs.setIntPref("devtools.hud.loglimit", userSetLimit);
-
- const { getState, dispatch } = configureStore();
-
- let newPacket = Object.assign({}, packet);
- for (let i = 1; i <= userSetLimit + 1; i++) {
- newPacket.message.parameters = [i];
- dispatch(actions.messageAdd(newPacket));
- }
-
- let messages = getAllMessages(getState());
- equal(messages.count(), userSetLimit,
- "Messages are pruned up to the user set log limit");
-});
deleted file mode 100644
--- a/devtools/client/webconsole/new-console-output/test/store/xpcshell.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[DEFAULT]
-tags = devtools devtools-webconsole
-head = head.js
-tail =
-firefox-appdir = browser
-
-[test_messages.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/utils/id-generator.js
@@ -0,0 +1,22 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+exports.IdGenerator = class IdGenerator {
+ constructor() {
+ this.messageId = 1;
+ }
+
+ getNextId() {
+ // Return the next message id, as a string.
+ return "" + this.messageId++;
+ }
+
+ getCurrentId() {
+ return this.messageId;
+ }
+};
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -23,32 +23,26 @@ const {
CATEGORY_JS,
CATEGORY_OUTPUT,
CATEGORY_WEBDEV,
LEVELS,
SEVERITY_LOG,
} = require("../constants");
const { ConsoleMessage } = require("../types");
-let messageId = 0;
-function getNextMessageId() {
- // Return the next message id, as a string.
- return "" + messageId++;
-}
-
-function prepareMessage(packet) {
+function prepareMessage(packet, idGenerator) {
// This packet is already in the expected packet structure. Simply return.
if (!packet.source) {
packet = transformPacket(packet);
}
if (packet.allowRepeating) {
packet = packet.set("repeatId", getRepeatId(packet));
}
- return packet.set("id", getNextMessageId());
+ return packet.set("id", idGenerator.getNextId());
}
/**
* Transforms a packet from Firefox RDP structure to Chrome RDP structure.
*/
function transformPacket(packet) {
if (packet._type) {
packet = convertCachedPacket(packet);
--- a/devtools/client/webconsole/new-console-output/utils/moz.build
+++ b/devtools/client/webconsole/new-console-output/utils/moz.build
@@ -1,9 +1,10 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
+ 'id-generator.js',
'messages.js',
'variables-view.js',
)