Bug 1289258 - Part 6: Convert store tests. r=bgrins draft
authorLin Clark <lclark@mozilla.com>
Wed, 27 Jul 2016 16:24:15 -0400
changeset 397829 b8d5ad8c2134bcf6330bcc593794953221bfc3fb
parent 397828 9457081dac987bbd2dc76540cfc89feb154769dd
child 527556 e1c6496fc65d2d846f075e926ffbcd4eb196abbf
push id25412
push userbmo:lclark@mozilla.com
push dateMon, 08 Aug 2016 12:52:33 +0000
reviewersbgrins
bugs1289258
milestone51.0a1
Bug 1289258 - Part 6: Convert store tests. r=bgrins MozReview-Commit-ID: 8fK4pYs1cla
devtools/client/webconsole/new-console-output/actions/messages.js
devtools/client/webconsole/new-console-output/moz.build
devtools/client/webconsole/new-console-output/test/actions/messages.test.js
devtools/client/webconsole/new-console-output/test/fixtures/stubs.js
devtools/client/webconsole/new-console-output/test/helpers.js
devtools/client/webconsole/new-console-output/test/moz.build
devtools/client/webconsole/new-console-output/test/store/filters.test.js
devtools/client/webconsole/new-console-output/test/store/head.js
devtools/client/webconsole/new-console-output/test/store/messages.test.js
devtools/client/webconsole/new-console-output/test/store/test_messages.js
devtools/client/webconsole/new-console-output/test/store/xpcshell.ini
devtools/client/webconsole/new-console-output/utils/id-generator.js
devtools/client/webconsole/new-console-output/utils/messages.js
devtools/client/webconsole/new-console-output/utils/moz.build
--- 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',
 )