I need to write unit test using sinon to web socket client.
the code is as following:
Socket = {
connect: function ()
{
socket = new WebSocket('ws://localhost:12345');
socket.onopen = function()
{
console.log('connected to the server');
};
socket.onmessage = function(message)
{
console.log('Received:', message.data);
};
}
};
We need return the socket instance at last in the connect method. Because you assigned two new functions to onopen and onmessage events. It will override the spy or stub methods on the socket object.
Test environment: Node
Here is the unit test solution:
index.js:
const Socket = {
connect: function() {
socket = new WebSocket("ws://localhost:12345");
socket.onopen = function() {
console.log("connected to the server");
};
socket.onmessage = function(message) {
console.log("Received:", message.data);
};
return socket;
}
};
module.exports = Socket;
index.spec.js:
const sinon = require("sinon");
const { expect } = require("chai");
const Socket = require("./index");
class WebSocket {
constructor(uri) {}
onopen() {}
onmessage() {}
}
global.WebSocket = WebSocket;
describe("17806481", () => {
it("should test connect correctly", () => {
const logSpy = sinon.spy(console, "log");
const socket = Socket.connect();
const onopenSpy = sinon.spy(socket, "onopen");
const onmessageSpy = sinon.spy(socket, "onmessage");
onopenSpy();
expect(logSpy.firstCall.calledWith("connected to the server")).to.be.true;
const mMessage = { data: "fake data" };
onmessageSpy(mMessage);
expect(logSpy.secondCall.calledWith("Received:", mMessage.data)).to.be.true;
});
});
Unit test result with 100% coverage for Socket module:
17806481
connected to the server
Received: fake data
✓ should test connect correctly
1 passing (10ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 75 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
index.spec.js | 100 | 100 | 60 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/17806481
Related
I am attempting to write unit test for a service function that returns a Pino log message when ran. I have built a stub, using Sinon, from the logger module I am using in service.js, but have not been able to get a successful test. The test returns: AssertionError: expected error to have been called exactly once, but it was called 0 times
Ideally I would like to be able to assert that the logger was called, and that function returned with the exact logger call and message.
Below is some sample code for what I am trying to achieve
logger.js
const pino = require('pino');
const defaultLogger = pino({}, 'output.log');
module.exports = {
defaultLogger
}
service.js
const path = require('path');
const { defaultLogger } = require('../common/logger');
const logger = defaultLogger.child({ filename: path.basename(__filename) });
const logResponse = () => {
return logger.info('successful');
};
service.test.js
const sinon = require('sinon');
const chai = require('chai');
const sinonChai = require('sinon-chai');
const service = require('../service.js')
const { defaultLogger } = require('../common/logger');
const { expect } = chai;
chai.should();
chai.use(sinonChai);
describe('Service Test', () => {
it('should return a log message', () => {
const spy = sinon.spy(service, 'logResponse')
const stub = sinon.stub(defaultLogger, 'error');
spy.should.have.been.calledOnce;
expect(stub).to.have.been.calledOnce;
spy.should.have.returned(logger.info('successful'));
})
})
Here is the unit test solution:
./logger.js:
const pino = require('pino');
const defaultLogger = pino({}, 'output.log');
module.exports = {
defaultLogger,
};
./service.js:
const path = require('path');
const { defaultLogger } = require('./logger');
const logger = defaultLogger.child({ filename: path.basename(__filename) });
const logResponse = () => {
return logger.info('successful');
};
module.exports = {
logResponse,
};
./service.test.js:
const { defaultLogger } = require('./logger');
const sinon = require('sinon');
const chai = require('chai');
const { expect } = chai;
describe('63618186', () => {
it('should return a log message ', () => {
const loggerStub = {
info: sinon.stub().returns('anything'),
};
sinon.stub(defaultLogger, 'child').returns(loggerStub);
const service = require('./service');
const actual = service.logResponse();
expect(actual).to.be.equal('anything');
sinon.assert.calledOnce(defaultLogger.child);
sinon.assert.calledWithExactly(loggerStub.info, 'successful');
});
});
unit test result with coverage report:
63618186
✓ should return a log message
1 passing (41ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
logger.js | 100 | 100 | 100 | 100 |
service.js | 100 | 100 | 100 | 100 |
------------|---------|----------|---------|---------|-------------------
//routes.js
app.get('/:id/info',
UnoController.getGameInfo,
...
);
//UnoController.js
async function getGameInfo(req, res) {
data = await UnoModel.getGameInfo(req.params.id);
if(data==null) return res.status(404).json({message:'Room Not Found'});
res.json(data);
}
//UnoModel.js
exports.getGameInfo = async function (id) {
return await mongodb.findById('uno', id);
}
I am writing unit testing in node js using sinon.
I want stub the UnoModel.getGameInfo to return {id:'123456789012'}, When i hit /someid/info rest api.
I wrote the test case like below.
//UnoApiTest.js
it('get game info with player payload and invalid room id', function (done) {
sinon.stub(UnoModel, 'getGameInfo').resolves({ id: '123456789012' });
request({
url: 'http://localhost:8080/api/v1/game/uno/123456789012/info',
headers: { 'x-player-token': jwt.sign({ _id: '123' }) }
}, function (error, response, body) {
expect(response.statusCode).to.equal(200);
done();
});
});
But i am receiving the statusCode as 404.
I tried to console the data. Its actually fetching from db.
It doesn't returns the provided value for stub.
Can anyone help me with this?
Is there any other way to do this?
It should work. E.g.
server.js:
const express = require('express');
const UnoController = require('./UnoController');
const app = express();
app.get('/api/v1/game/uno/:id/info', UnoController.getGameInfo);
module.exports = app;
UnoController.js:
const UnoModel = require('./UnoModel');
async function getGameInfo(req, res) {
const data = await UnoModel.getGameInfo(req.params.id);
if (data == null) return res.status(404).json({ message: 'Room Not Found' });
res.json(data);
}
exports.getGameInfo = getGameInfo;
UnoModel.js:
// simulate mongodb
const mongodb = {
findById(arg1, arg2) {
return { name: 'james' };
},
};
exports.getGameInfo = async function(id) {
return await mongodb.findById('uno', id);
};
UnoApiTest.test.js:
const app = require('./server');
const UnoModel = require('./UnoModel');
const request = require('request');
const sinon = require('sinon');
const { expect } = require('chai');
describe('61172026', () => {
const port = 8080;
let server;
before((done) => {
server = app.listen(port, () => {
console.log(`http server is listening on http://localhost:${port}`);
done();
});
});
after((done) => {
server.close(done);
});
it('should pass', (done) => {
sinon.stub(UnoModel, 'getGameInfo').resolves({ id: '123456789012' });
request({ url: 'http://localhost:8080/api/v1/game/uno/123456789012/info' }, function(error, response, body) {
expect(response.statusCode).to.equal(200);
done();
});
});
});
API automation test results with coverage report:
61172026
http server is listening on http://localhost:8080
✓ should pass
1 passing (50ms)
------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------|---------|----------|---------|---------|-------------------
All files | 80 | 50 | 33.33 | 85.71 |
UnoController.js | 83.33 | 50 | 100 | 100 | 5
UnoModel.js | 50 | 100 | 0 | 50 | 4,8
server.js | 100 | 100 | 100 | 100 |
------------------|---------|----------|---------|---------|-------------------
source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/61172026
I'm writing unit test cases for my node application using mocha on very first time. I have no clear idea about how to mock a function in mocha.
I added the function of my node application. How can a unit test for below mentioned function look like?.
var authHandler = require('./authenticationHandler');
exports.postloginValues = (req, res) => {
var realEdUsername_Update = req.body.uName;
var encodedPassword = Buffer.from(req.body.password).toString('base64');
var jsonData = {
loginName : realEdUsername_Update,
userPassword : encodedPassword
};
var parseData = JSON.stringify(jsonData);
var result = authHandler.validateRealEdUser(parseData, res);
};
index.js:
var authHandler = require('./authenticationHandler');
exports.postloginValues = (req, res) => {
var realEdUsername_Update = req.body.uName;
var encodedPassword = Buffer.from(req.body.password).toString('base64');
var jsonData = {
loginName: realEdUsername_Update,
userPassword: encodedPassword,
};
var parseData = JSON.stringify(jsonData);
var result = authHandler.validateRealEdUser(parseData, res);
};
authenticationHandler.js:
module.exports = {
validateRealEdUser(parseData, res) {},
};
index.test.js:
const { postloginValues } = require('./');
var authHandler = require('./authenticationHandler');
const sinon = require('sinon');
describe('60734436', () => {
it('should pass', () => {
const validateRealEdUserStub = sinon.stub(authHandler, 'validateRealEdUser');
const mReq = { body: { password: '123', uName: 'james' } };
const mRes = {};
postloginValues(mReq, mRes);
sinon.assert.calledWithExactly(
validateRealEdUserStub,
JSON.stringify({ loginName: 'james', userPassword: Buffer.from(mReq.body.password).toString('base64') }),
mRes,
);
validateRealEdUserStub.reset();
});
});
unit test results with coverage report:
60734436
✓ should pass
1 passing (8ms)
--------------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 50 | 100 |
authenticationHandler.js | 100 | 100 | 0 | 100 |
index.js | 100 | 100 | 100 | 100 |
--------------------------|---------|----------|---------|---------|-------------------
I need to call a function using node-cron and want to write a unit test case for that. the unit test case should be able to test if the function is getting calling based on the pattern.
Below is my code
const server = (module.exports = {
cronJob: null,
scheduledJob: function(pattern) {
server.cronJob = cron.schedule(pattern, () => {
server.run();
});
},
run: function() {
console.log("run called");
},
});
describe("entry point test suite", () => {
it("should call function every second", (done) => {
const pattern = "* * * * * *";
let spy = sinon.spy(server, "run");
server.scheduledJob(pattern);
server.cronJob.Start();
// to do wait for 3 sencond
server.cronJob.Stop();
expect(spy.callCount).eq(3);
});
});
Two questions:
other than setTimeout what option I have to wait for 3 seconds so that cron job will run 3 times as pattern is for each second.
This test is failing with error server.cronjob.start is not a function.
How can I make this work?
Here is the unit testing solution:
server.js:
const cron = require("node-cron");
const server = (module.exports = {
cronJob: null,
scheduledJob: function(pattern) {
server.cronJob = cron.schedule(pattern, () => {
server.run();
});
},
run: function() {
console.log("run called");
},
});
server.test.js:
const server = require("./server");
const sinon = require("sinon");
const cron = require("node-cron");
const { expect } = require("chai");
describe("57208090", () => {
afterEach(() => {
sinon.restore();
});
describe("#scheduledJob", () => {
it("should schedule job", () => {
const pattern = "* * * * * *";
const runStub = sinon.stub(server, "run");
const scheduleStub = sinon
.stub(cron, "schedule")
.yields()
.returns({});
server.scheduledJob(pattern);
sinon.assert.calledWith(scheduleStub, pattern, sinon.match.func);
sinon.assert.calledOnce(runStub);
expect(server.cronJob).to.be.eql({});
});
});
describe("#run", () => {
it("should run server", () => {
const logSpy = sinon.spy(console, "log");
server.run();
sinon.assert.calledWith(logSpy, "run called");
});
});
});
Unit test result with 100% coverage:
57208090
#scheduledJob
✓ should schedule job
#run
run called
✓ should run server
2 passing (12ms)
----------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
server.js | 100 | 100 | 100 | 100 | |
server.test.js | 100 | 100 | 100 | 100 | |
----------------|----------|----------|----------|----------|-------------------|
You asked for unit testing. If you need an integration testing, please create a new post.
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/57208090
i have little experience with jest as i am trying to change variable in my function as we expect to have error thrown if the function's inner variable(baseUrl) changed to null, my function :
buildUrl.js:
export function buildUrl(contentId, data, options = {}) {
let baseUrl = config.has('imgBaseUrl') && config.get('imgBaseUrl');
if (!baseUrl) {
throw new Error('some error');
}
}
i need to mock the baseUrl to value of null for example and test it
buildUrl.test.js
import {buildUrl} from "./buildURL";
....
it('throw an error when "baseUrl" is not configured', () => {
let mockBaseUrl = {baseUrl: null};
jest.mock('./buildURL', ()=> mockBaseUrl);
// jest.mock('../../../config/test', ()=>mockImgBaseUrl); // or mock the config to be used by the function?
expect(()=> buildUrl('1.44444', data[0], defaultOptions)).toThrow(
'some error'
);
});
another approach using jest.fn() didnt work as expected , maybe i am missing something here...
Here is the unit test solution:
baseUrl.js:
import config from './config';
export function buildUrl(contentId, data, options = {}) {
let baseUrl = config.has('imgBaseUrl') && config.get('imgBaseUrl');
if (!baseUrl) {
throw new Error('some error');
}
console.log(baseUrl);
}
config.js:
export default {
config: {},
has(key) {
return !!config[key];
},
get(key) {
return config[key];
}
};
baseUrl.spec.js:
import { buildUrl } from './buildUrl';
import config from './config';
describe('buildUrl', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('should throw error when baseUrl is null', () => {
const defaultOptions = {};
const data = ['fake data'];
const hasSpy = jest.spyOn(config, 'has').mockReturnValueOnce(true);
const getSpy = jest.spyOn(config, 'get').mockReturnValueOnce(null);
expect(() => buildUrl('1.44444', data[0], defaultOptions)).toThrowError('some error');
expect(hasSpy).toBeCalledWith('imgBaseUrl');
expect(getSpy).toBeCalledWith('imgBaseUrl');
});
it('should log baseUrl', () => {
const defaultOptions = {};
const data = ['fake data'];
const hasSpy = jest.spyOn(config, 'has').mockReturnValueOnce(true);
const getSpy = jest.spyOn(config, 'get').mockReturnValueOnce('https://github.com/mrdulin');
const logSpy = jest.spyOn(console, 'log');
buildUrl('1.44444', data[0], defaultOptions);
expect(hasSpy).toBeCalledWith('imgBaseUrl');
expect(getSpy).toBeCalledWith('imgBaseUrl');
expect(logSpy).toBeCalledWith('https://github.com/mrdulin');
});
});
Unit test result:
PASS src/stackoverflow/48006588/buildUrl.spec.js (8.595s)
buildUrl
✓ should throw error when baseUrl is null (9ms)
✓ should log baseUrl (7ms)
console.log node_modules/jest-mock/build/index.js:860
https://github.com/mrdulin
-------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-------------|----------|----------|----------|----------|-------------------|
All files | 80 | 83.33 | 33.33 | 77.78 | |
buildUrl.js | 100 | 83.33 | 100 | 100 | 3 |
config.js | 33.33 | 100 | 0 | 33.33 | 4,7 |
-------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 9.768s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/48006588
I think you can do this:
jest.mock('./buildURL', () => {buildUrl: jest.fn()})
buildUrl.mockImplementation(() => {baseUrl: null})
See Jest docs