console.log unit test failing under mocha with unknown error - node.js

My unit test failing for following code.when I run test i see below result with unknown error.I am not getting how to test second parameter paylod in console.log method.
Test console log()
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 66.67 | 100 | 0 | 66.67 | |
logger.js | 66.67 | 100 | 0 | 66.67 | 6 |
-----------|----------|----------|----------|----------|-------------------|
npm ERR! Test failed. See above for more details.
//logger.js
'use strict';
const log = (message, payload) => {
console.log(message, JSON.stringify(payload, null, 2));
};
module.exports = { log };
// log.test.js
'use strict';
const chai = require('chai');
const sinon = require('sinon');
chai.use(require('sinon-chai'));
const { expect } = chai;
const log = require('../../src/logger');
describe('Test console log()', () => {
it('should log value in console', () => {
this.stub = sinon.stub(console, 'log');
log('test invoked', { option: 1 });
});
});

Looks like you just need to destructure your require for logger.js:
'use strict';
const sinon = require('sinon');
const { log } = require('../../src/logger'); // <= destructuring assignment
describe('Test console log()', () => {
it('should log value in console', () => {
const stub = sinon.stub(console, 'log');
log('test invoked', { option: 1 });
stub.restore();
sinon.assert.calledWith(stub, 'test invoked', JSON.stringify({ option: 1 }, null, 2)); // Success!
});
});

Related

Spy module.exports functions with sinon in NodeJS always returning 0

I am trying to track the number of calls to another function using a test case written with Sinon. I have the following code, and on running the test, the calledFuncSpy callCount always gets me 0, which is not expected. Meanwhile, running another spy on console.log gives me the correct output, and I have left it commented in the code. Does anyone know what could be the problem?
Here’s the code. Let me know if more information is required to solve this problem.
specs/mymodule.js
const mymodule = require("../src/mymodule.js");
var sinon = require("sinon");
const assert = require("assert");
describe("Test suite", function() {
let calledFuncSpy;
let consoleSpy;
beforeEach(function () {
calledFuncSpy = sinon.spy(mymodule, "calledFunc");
consoleSpy = sinon.spy(console, "log");
})
afterEach(function () {
calledFuncSpy.restore();
consoleSpy.restore();
})
it("Test the add method", function () {
mymodule.ownHelloWorld();
assert.deepStrictEqual(calledFuncSpy.callCount, 1);
// assert.deepStrictEqual(consoleSpy.callCount, 1);
});
})
src/mymodule.js
function ownHelloWorld() {
calledFunc();
}
function calledFunc() {
console.log("Hello world");
}
module.exports = {
ownHelloWorld,
calledFunc
}
calledFunc called inside ownHelloWorld function can NOT be stubbed. It will always use the original calledFunc function. sinon.spy(mymodule, "calledFunc") can NOT modify the reference of it when calling the ownHelloWorld function. Also, see this comment
You can refactor it like this:
mymodule.js:
function ownHelloWorld() {
module.exports.calledFunc();
}
function calledFunc() {
console.log('Hello world');
}
module.exports = {
ownHelloWorld,
calledFunc,
};
mymodule.test.js:
const mymodule = require('./mymodule');
var sinon = require('sinon');
describe('Test suite', function () {
let calledFuncSpy;
let consoleSpy;
beforeEach(function () {
calledFuncSpy = sinon.spy(mymodule, 'calledFunc');
consoleSpy = sinon.spy(console, 'log');
});
afterEach(function () {
calledFuncSpy.restore();
consoleSpy.restore();
});
it('Test the add method', function () {
mymodule.ownHelloWorld();
sinon.assert.calledOnce(calledFuncSpy);
});
});
test result:
Test suite
Hello world
✓ Test the add method
1 passing (5ms)
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
mymodule.js | 100 | 100 | 100 | 100 |
-------------|---------|----------|---------|---------|-------------------

Jest - mocking crypto.Hmac not working with jest.mock()

I'm trying to mock the crypto module of nodejs with the jestjs framework.
Here is the piece of code that I want to mock:
app.js:
const hash = crypto
.createHmac('sha256', API_TOKEN)
.update(JSON.stringify(body))
.digest('hex');
if(hash === signature) {
//verified successfully. Implement next logic
}
Here, I want the .digest function to give the value contained in the signature variable.
Following is the mock code:
jest.mock('crypto', () => {
return {
createHmac: jest.fn(() => ({
update: jest.fn(),
digest: jest.fn(() => '123') //here '123' is placeholder for 'signature value
}))
};
});
However, when running the test, the main files throws an error like this:
TypeError: Cannot read property 'update' of undefined
What am I missing here for jest mock?
You should use mockFn.mockReturnThis() to obtain method chain call.
E.g.
app.js:
const crypto = require('crypto');
function main() {
const API_TOKEN = 'API_TOKEN';
const signature = '123';
const body = {};
const hash = crypto
.createHmac('sha256', API_TOKEN)
.update(JSON.stringify(body))
.digest('hex');
if (hash === signature) {
console.log('verified successfully. Implement next logic');
}
}
module.exports = main;
app.spec.js:
const main = require('./app');
const crypto = require('crypto');
jest.mock('crypto', () => {
return {
createHmac: jest.fn().mockReturnThis(),
update: jest.fn().mockReturnThis(),
digest: jest.fn(() => '123'),
};
});
describe('64386858', () => {
it('should pass', () => {
const logSpy = jest.spyOn(console, 'log');
main();
expect(crypto.createHmac).toBeCalledWith('sha256', 'API_TOKEN');
expect(crypto.update).toBeCalledWith(JSON.stringify({}));
expect(crypto.digest).toBeCalledWith('hex');
expect(logSpy).toBeCalledWith('verified successfully. Implement next logic');
logSpy.mockRestore();
});
});
unit test result:
PASS src/stackoverflow/64386858/app.spec.js
64386858
✓ should pass (17ms)
console.log node_modules/jest-environment-jsdom/node_modules/jest-mock/build/index.js:866
verified successfully. Implement next logic
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 50 | 100 | 100 | |
app.js | 100 | 50 | 100 | 100 | 13 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.087s, estimated 11s

How to stub node-cache's cache.get()?

I'm writing a unit test for a function that uses node-cache.
At the following function,
I want to have a string return at the first cache.get
an array in the second cache.get
Please note that I removed some parts of code from testFunction since it is not relavant to my question.
const NodeCache = require('node-cache');
const cache = new NodeCache();
...
const testFunction = () => {
let myStringCache = cache.get('cacheName1');
let myArrayCache = cache.get('cacheName2');
... Do something with caches ...
return 'return something';
}
...
module.exports = {
...,
testFunction,
...
}
I created the following test
describe('sample test with testFunction() ', ()=>{
let stubCache;
let stub;
before((done)=>{
sandbox = sinon.createSandbox();
stubCache = sandbox.stub(cache, 'get');
stubCache.withArgs('cacheName1').returns('sample string');
stubCache.withArgs('cacheName2').returns([1,2,3,4,5,6]);
stub = proxyquire('./filelocation.js',{
'node-cache': stubCache
});
done();
});
it('should not throw error',(done)=>{
chai.expect(stub.testFunction()).not.to.throw;
});
})
I was Googling around, and there is some partial solution to use proxyquire to stub the value. but looks like it does stub but it's not where I wanted.
It stubs at NodeCache but cache
So I have questions:
Does anybody know how to stub cache.get() with mocha, chai or sinon? If so, please share how you do it ?
Is it possible to stub different returns by the argument of cache.get()?
Here is the unit test solution:
index.js:
const NodeCache = require("node-cache");
const cache = new NodeCache();
const testFunction = () => {
let myStringCache = cache.get("cacheName1");
let myArrayCache = cache.get("cacheName2");
console.log("myStringCache:", myStringCache);
console.log("myArrayCache:", myArrayCache);
return "return something";
};
module.exports = {
testFunction
};
index.spec.js:
const sinon = require("sinon");
const proxyquire = require("proxyquire");
const chai = require("chai");
describe("sample test with testFunction() ", () => {
let stubCache;
let stub;
let getCacheStub;
before(() => {
sandbox = sinon.createSandbox();
getCacheStub = sandbox.stub();
stubCache = sandbox.stub().callsFake(() => {
return {
get: getCacheStub
};
});
getCacheStub.withArgs("cacheName1").returns("sample string");
getCacheStub.withArgs("cacheName2").returns([1, 2, 3, 4, 5, 6]);
stub = proxyquire("./", {
"node-cache": stubCache
});
});
it("should not throw error", () => {
const logSpy = sinon.spy(console, "log");
chai.expect(stub.testFunction()).not.to.throw;
sinon.assert.calledWith(
logSpy.firstCall,
"myStringCache:",
"sample string"
);
sinon.assert.calledWith(logSpy.secondCall, "myArrayCache:", [
1,
2,
3,
4,
5,
6
]);
});
});
Unit test result with 100% coverage:
sample test with testFunction()
myStringCache: sample string
myArrayCache: [ 1, 2, 3, 4, 5, 6 ]
✓ should not throw error
1 passing (87ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
index.spec.js | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/58278211

mocking/stubbing a function that returns another function

I have two functions funcA and funcB
funcA is being an npm module, and funcB is custom function that calls funcA
funcB.js:
const a = require('a')
const funcB = ()=> a.funcA({arg})
I want to test that a.funcA has been called when invoking funcB
funcB.test.js:
describe("", () => {
it("should call a.funcA", () => {
sandbox.stub(a, "funcA");
funcB();
expect(a.funcA).to.have.been.called;
});
});
funcA:
function funcA() {
//....
return function c() {
//other logic here.
};
}
When i run test, i get this message:
I got a.funcA is not a spy or a call to a spy! error
How do i stub funcA? any ideas? ive tried mockquire but wouldnt work.
Here is the unit test solution:
funcB.js:
const a = require("./a");
const funcB = () => a.funcA({ arg: 123 });
exports.funcB = funcB;
a.js:
exports.funcA = function funcA(args) {
return function c() {};
};
funcB.test.js:
const { expect } = require("chai");
const sinon = require("sinon");
const a = require("./a");
const { funcB } = require("./funcB");
describe("57796168", () => {
let sandbox;
before(() => {
sandbox = sinon.createSandbox();
});
it("should call a.funcA", () => {
const funcAStub = sandbox.stub(a, "funcA");
funcB();
sinon.assert.calledWith(funcAStub, { arg: 123 });
expect(funcAStub.callCount).to.be.equal(1);
expect(funcAStub.calledWith({ arg: 123 })).to.be.true;
});
});
Unit test result with coverage report:
57796168
✓ should call a.funcA
1 passing (10ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 94.74 | 100 | 66.67 | 94.44 | |
a.js | 50 | 100 | 0 | 50 | 2 |
funcB.js | 100 | 100 | 100 | 100 | |
funcB.test.js | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/57796168

Unit test bluebird Promise.all with Mocha/Chai

What would be the proper way to unit test this getall function using mocha/chai? I'm having a hard time understanding what to expect with Promise.all.
const Promise = require('bluebird');
const someApiService = require('./someapiservice');
const _ = require('underscore');
function getall(arr) {
let promises = _.map(arr, function(item) {
return someApiService(item.id);
});
return Promise.all(promises);
}
We should stub standalone function someApiService use link seams. This is the CommonJS version, so we will be using proxyquire to construct our seams. Additionally, I use sinon.js to create the stub for it.
E.g.
getall.js:
const Promise = require('bluebird');
const someApiService = require('./someapiservice');
const _ = require('underscore');
function getall(arr) {
let promises = _.map(arr, function (item) {
return someApiService(item.id);
});
return Promise.all(promises);
}
module.exports = getall;
someapiservice.js:
module.exports = function someApiService(id) {
return Promise.resolve('real data');
};
getall.test.js:
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const { expect } = require('chai');
describe('45337461', () => {
it('should pass', async () => {
const someapiserviceStub = sinon.stub().callsFake((id) => {
return Promise.resolve(`fake data with id: ${id}`);
});
const getall = proxyquire('./getall', {
'./someapiservice': someapiserviceStub,
});
const actual = await getall([{ id: 1 }, { id: 2 }, { id: 3 }]);
expect(actual).to.deep.equal(['fake data with id: 1', 'fake data with id: 2', 'fake data with id: 3']);
sinon.assert.calledThrice(someapiserviceStub);
});
});
unit test result:
45337461
✓ should pass (2745ms)
1 passing (3s)
-------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------------|---------|----------|---------|---------|-------------------
All files | 88.89 | 100 | 66.67 | 88.89 |
getall.js | 100 | 100 | 100 | 100 |
someapiservice.js | 50 | 100 | 0 | 50 | 2
-------------------|---------|----------|---------|---------|-------------------

Resources