Stub standalone function from JSON module in Sinon - node.js

code.js
const fun = () => {
console.log('Some message');
}
module.exports = {fun}
file.js
const {fun} = require('./code');
const abc = () => {
return fun();
}
module.exports = {abc}
file.test.js
const code = require('./code');
const abc = require('./abc');
const sinon = require('sinon');
it('Should return Some Message', () => {
sinon.stub(code,'fun').returns(true);
abc.abc();
});
Here, I want to stub the function fun but as I'm importing it in a different way than an object, the stubbing is not working.
I don't want to change my importing style to an object instead of importing selective keys.
Is there any way to do the stubbing in Sinon?

You should call sinon.stub() before require('./abc'):
const sinon = require('sinon');
const code = require('./code');
sinon.stub(code,'fun').returns(true);
const abc = require('./abc');
it('Should return Some Message', () => {
abc.abc();
});

Related

How to test class called or not using mocha & chai with sinon TDD?

I want to test class called or not in nodejs, mocha & chai with sinon. I tried with stub but not worked as what I expected.
someMiddleware.js
module.export.someMiddleware = async(req,res,next)=>{
const responseData = await someReturnFunction(req);
if (!responseData || responseData == null) {
throw new SomeExtendedErrrorClass("stringArg");
}
res.send(responseData);
}
testFile.js
sinon
.stub(someMiddleWare , "someReturnFunction")
.returns(null);
const stubClass = sinon.stub(SomeExtendedErrrorClass, "constructor");
someMiddleware(req, res, next);
expect(stubClass).to.have.be.called;
Even the SomeExtendedErrrorClass called, sinon not detected.
Sinon does not support stub standalone function or class imported from other modules. You need to use Link Seams, we will be using proxyquire to construct our seams.
E.g.
someMiddleware.js:
const someReturnFunction = require('./someReturnFunction');
const SomeExtendedErrrorClass = require('./SomeExtendedErrrorClass');
module.exports.someMiddleware = async (req, res, next) => {
const responseData = await someReturnFunction(req);
if (!responseData || responseData == null) {
throw new SomeExtendedErrrorClass('stringArg');
}
res.send(responseData);
};
SomeExtendedErrrorClass.js:
class SomeExtendedErrrorClass extends Error {}
someReturnFunction.js:
async function someReturnFunction() {
return 'real implementation';
}
someMiddleware.test.js:
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const SomeExtendedErrrorClass = require('./SomeExtendedErrrorClass');
chai.use(chaiAsPromised);
const { expect } = chai;
describe('68640048', () => {
it('should get and send response data', async () => {
const someReturnFunctionStub = sinon.stub().resolves('teresa teng');
const { someMiddleware } = proxyquire('./someMiddleware', {
'./someReturnFunction': someReturnFunctionStub,
});
const mReq = {};
const mRes = { send: sinon.stub() };
await someMiddleware(mReq, mRes);
sinon.assert.calledWithExactly(mRes.send, 'teresa teng');
});
it('should throw error', async () => {
const someReturnFunctionStub = sinon.stub().resolves(null);
const { someMiddleware } = proxyquire('./someMiddleware', {
'./someReturnFunction': someReturnFunctionStub,
});
const mReq = {};
const mRes = { send: sinon.stub() };
await expect(someMiddleware(mReq, mRes)).to.eventually.rejectedWith(SomeExtendedErrrorClass);
});
});
test result:
68640048
✓ should get and send response data
✓ should throw error
2 passing (10ms)

Mocha: Can't stub function in file that was already required in another test file

I'm using Mocha to run a test suite on fileToTest.js with requires greeting.js
// --fileToTest.js--
const { greeting } = require('./greeting');
module.exports = () => greeting();
// --greeting.js--
module.exports.greeting = () => 'hi!';
By itself, this test file successfully stubs greeting.
// --test2.js--
let parent;
const sinon = require('sinon');
const chai = require('chai');
const greeting = require('../../greeting.js');
const { expect } = chai;
describe('stubbed /hi', () => {
before(async () => {
sinon.stub(greeting, 'greeting').callsFake((req, res, next) => 'bye!');
parent = require('../../parent.js');
});
after(async () => {
greeting.greeting.restore();
});
it('should say bye', async function () {
expect(parent()).to.be.equal('bye!');
});
});
However if I run a test suite and have another test file that requires fileToTest.js, like test1.js below, the first test above (test2.js) won't stub greeting.
// --test1.js--
const chai = require('chai');
const fileToTest = require('../../fileToTest.js');
const { expect } = chai;
describe('not stubbed /hi', () => {
it('should say hi', () => {
expect(fileToTest()).to.be.equal('hi!');
});
});
It seems once test1.js requires fileToTest, mocha doesn't reload the fileToTest on the test2.js's require. So fileToTest is stuck with the old greeting function.
Whats the proper way to stub a function in this situation?
Repo
This answer worked. I had to delete the cache.
before(async () => {
delete require.cache[require.resolve('../../fileToTest.js')]; // <------
sinon.stub(greeting, 'greeting').callsFake((req, res, next) => 'bye!');
fileToTest = require('../../fileToTest.js');
});

Sinon stub not working if tested using express app

I have a a controller function like below.
SendOTPController.js
const otpService = require('../services/otpService')
module.exports = async function(req, res) {
const {error, data} = await sendOTP(req.query.phone)
if(error)
return res.send(error)
return res.send(data)
}
otpService.js
module.exports = async function(phone) {
await result = fetch(`http://api.send-otp?phone=${phone}`)
if (result !== sucess)
return {
error: "Failed to send OTP!"
data: null
}
return {
error: null
data: result
}
}
Below is my test.
const expect = require('chai').expect
const request = require('supertest')
const sinon = require('sinon')
const rewire = require('rewire')
const SendOTPController= rewire('../../src/controllers/SendOTPController')
const app = require('../../src/app')
describe('GET /api/v1/auth/otp/generate', function () {
it('should generate OTP', async () => {
let stub = sinon.stub().returns({
error: null,
data: "OTP sent"
})
SendOTPController.__set__('sendOTPOnPhone', stub)
const result = await request(app)
.get('/api/v1/auth/otp/generate?phone=8576863491')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
console.log(result.body)
expect(stub.called).to.be.true
})
})
In above code the stub is not being called.
But if use only controller without using express app it works fine.
const expect = require('chai').expect
const request = require('supertest')
const sinon = require('sinon')
const rewire = require('rewire')
const SendOTPController= rewire('../../src/controllers/SendOTPController')
const app = require('../../src/app')
describe('GET /api/v1/auth/otp/generate', function () {
it('should generate OTP', async () => {
let stub = sinon.stub().returns({
error: null,
data: "OTP sent"
})
SendOTPController.__set__('sendOTPOnPhone', stub)
const result = await SendOTPController() // not using express app, hence not passing req, res
console.log(result)
expect(stub.called).to.be.true
})
})
I went through many modules and docs.
They give a solution how I can stub a module.exports = async function(){}.
They also work, but only If they are directly imported and tested.
They don't work if I use it with express app.
Any help would be appreciated, thanks.
Instead of returns try to use resolves:
let stub = sinon.stub().resolves({
error: null,
data: "OTP sent"
})
returns is for sync code, resolves for async.

How to implement functional unit testing sinon with mocks in NodeJs?

How to implement sinon.mock on follwing function.
function getDashboard(req,res){
res.send("success");
}
describe("GetDashboard test"){
it("Response Should be test", function(){
const getDashboard = sinon.stub().returns('success');
let req = {}
let res = {
send: function(){};
const mock = sinon.mock(res);
mock.expect(getDashboard.calledOnce).to.be.true;
mock.verify();
}
})
}
Also how to stubbing data in function.Is it correct way of mocking.
Here is a working example:
const sinon = require('sinon');
function getDashboard(req, res) { res.send('success'); }
describe("getDashboard", function () {
it("should respond with 'success'", function () {
const req = {};
const res = { send: sinon.stub() };
getDashboard(req, res);
sinon.assert.calledWithExactly(res.send, 'success'); // Success!
})
});
Details
getDashboard calls the send function of the res object that it is given, so you just need to create a mock object with a sinon stub for the send property and verify that it was called as expected.

Unit test with promise handling - node.js

i want to do a unit test with async function on the code. and here is my code on user.test.js
'use strict'
const UserDomain = require("../../../../../../bin/modules/users/repositories/commands/domain")
const UserHandler = require("../../../../../../bin/modules/users/repositories/commands/command_handler")
const expect = require('chai').expect;
const assert = require('chai').assert;
const sinon = require('sinon');
describe('User domain', () => {
describe('".login(data)"', () => {
let user;
beforeEach( () => {
user = {
clientId : "adithyavisnu",
clientSecret : "secretOfmine#19"
}
});
it("should return error when username/password is empty", (done)=> {
done();
// let
})
it("should return object", async () => {
const domainStub = sinon.stub(UserDomain.prototype, 'login');
const result = await UserHandler.login(user);
sinon.assert.calledOnce(domainStub);
domainStub.restore();
})
});
});
If the normal code (not the unit test code above) the const result = await UserHandler.login(user); will have an object response, but when i do in user.test.js it do not get the response. the result is undefined.
here are the user_handler code
'use strict';
const User = require('./domain');
const login = async (data) => {
const postData = async () => {
const user = new User();
const result = await user.login(data);
return result;
}
const response = await postData();
return response;
}
Is there something i did wrong on the code or some code is missing?
I am sorry if you do think there is unclear information
Thank you for the responses
In the normal flow, the UserHandler calls the Domain.login method and returns the result object. When you run the unit test you are stubbing the Domain.login method. so, it wont return the result as normal flow. You can either make the stub return some result object and test that or just spy the Domain.login instead of stubbing it , if you just want to just check that the Domain.login was called without altering its behavior. Read more on stubs/spies here if you would like - http://sinonjs.org/releases/v1.17.7/stubs/

Resources