Background
I have a small server that receives data from a machine. Every time I receive a message I call a function in a dispatcher object that simply console.logs everything it receives.
Problem
The code works well as I can see the console.logs in the console, but Sinon spy.called doesn't work. It is always false no matter how many times I call dispatcher.onMessage.
Code
server.js
const eventDispatcher = {
onMessage: console.log,
};
const server = (dispatcher = eventDispatcher) => {
//this gets called everytime the server receives a message
const onData = data => {
//Process data
//....
dispatcher.onMessage(data);
};
const getDispatcher = () => dispatcher;
return Object.freeze({
getDispatcher
});
};
test.js
describe("message sender", () => {
const myServer = serverFactory();
it("should send information to server", () => {
dummyMachine.socket.write("Hello World!\r\n");
const dataSpy = sinon.spy(myServer.getDispatcher(), "onMessage");
expect(dataSpy.called).to.be.true; //always fails!
});
});
Research
After reading similar posts I believe this happens due to some layer of indirection, as pointed in:
And should be fixed via using this:
However, looking at my code I really can't get what I am missing.
Question
- What am I doing wrong?
MCVE
Directory Structure
Project_Folder
|____package.json
|____server.js
|____test
|____ dummyMachine_spec.js
package.json
{
"name": "sinon-question",
"version": "1.0.0",
"description": "MCVE about a dummy machine connecting to a server for StackOverflow",
"main": "server.js",
"scripts": {
"test": "NODE_ENV=test mocha --reporter spec --slow 5000 --timeout 5000 test/*_spec.js || true"
},
"author": "Pedro Miguel P. S. Martins",
"license": "ISC",
"devDependencies": {
"chai": "^3.5.0",
"mocha": "^3.3.0",
"sinon": "^2.2.0"
},
"dependencies": {
"net": "^1.0.2"
}
}
server.js
"use strict";
const net = require("net");
const eventDispatcher = {
onMessage: console.log,
};
const server = (dispatcher = eventDispatcher) => {
let serverSocket;
const onData = data => {
//Process data
dispatcher.onMessage(`I am server and I got ${data}`);
};
const start = (connectOpts) => {
return new Promise(fulfil => {
serverSocket = net.createConnection(connectOpts, () => {
serverSocket.on("data", onData);
fulfil();
});
});
};
const stop = () => serverSocket.destroy();
const getDispatcher = () => dispatcher;
return Object.freeze({
start,
stop,
getDispatcher
});
};
module.exports = server;
test/dummyMachine.js
"use strict";
const chai = require("chai"),
expect = chai.expect;
const sinon = require("sinon");
const net = require("net");
const serverFactory = require("../server.js");
describe("Dummy Machine", () => {
const dummyMachine = {
IP: "localhost",
port: 4002,
server: undefined,
socket: undefined
};
const server = serverFactory();
before("Sets up dummyReader and server", done => {
dummyMachine.server = net.createServer(undefined, socket => {
dummyMachine.socket = socket;
});
dummyMachine.server.listen(
dummyMachine.port,
dummyMachine.IP,
undefined,
() => {
server.start({
host: "localhost",
port: 4002
})
.then(done);
}
);
});
after("Kills dummyReader and server", () => {
server.stop();
dummyMachine.server.close();
});
it("should connect to server", done => {
dummyMachine.server.getConnections((err, count) => {
expect(err).to.be.null;
expect(count).to.eql(1);
done();
});
});
it("should send information to server", () => {
dummyMachine.socket.write("Hello World\r\n");
const dataSpy = sinon.spy(server.getDispatcher(), "onMessage");
expect(dataSpy.called).to.be.true; //WORK DAAMN YOU!
});
});
Instructions for MCVE
- Download the files and create the directory structure indicated.
- Enter project folder and type
npm installon a terminal - Type
npm test
The first test should pass, meaning a connection is in fact being made.
The second test will fail, even though you get the console log, proving that onMessage was called.