How to mock external function call in jest test - javascript

Here is my Node.js module to test (userdata.js file):
const myService = require('./my-service')
class UserData {
getData(query) {
return new Promise((resolve, reject) => {
myService.getUserData(query)
.then((userdata) => {
myService.getManagerData(userdata)
.then((managerdata) => {
resolve(managerdata)
})
})
})
}
}
module.exports = UserData
and test file:
const UserData = require('/.userdata')
test('UserData.getData', () => {
expect(UserData.getData('John Smith')).toBe('John\' manager');
});
I want to mock myService.getUserData and/or myService.getManagerData functions call that I'm not directly declare in test file.. How do I mock them properly to return some dummy result?

You can use jest.spyOn(object, methodName) to make stub for myService.getUserData and myService. getManagerData methods.
E.g.
userData.js:
const myService = require('./myService');
class UserData {
getData(query) {
return new Promise((resolve, reject) => {
myService.getUserData(query).then((userdata) => {
myService.getManagerData(userdata).then((managerdata) => {
resolve(managerdata);
});
});
});
}
}
module.exports = UserData;
myService.js:
const myService = {
getUserData(query) {
return 'real user data';
},
getManagerData(userdata) {
return 'real manager data';
},
};
module.exports = myService;
userData.test.js:
const UserData = require('./userData');
const myService = require('./myService');
describe('61784452', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('should pass', async () => {
jest.spyOn(myService, 'getUserData').mockResolvedValueOnce('fake user data');
jest.spyOn(myService, 'getManagerData').mockResolvedValueOnce('fake manager data');
const userData = new UserData();
const actual = await userData.getData('query');
expect(actual).toEqual('fake manager data');
expect(myService.getUserData).toBeCalledWith('query');
expect(myService.getManagerData).toBeCalledWith('fake user data');
});
});
unit test results with coverage report:
PASS stackoverflow/61784452/userData.test.js (12.908s)
61784452
✓ should pass (5ms)
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 84.62 | 100 | 71.43 | 84.62 |
myService.js | 50 | 100 | 0 | 50 | 3-6
userData.js | 100 | 100 | 100 | 100 |
--------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 13.99s

Related

how to jest mock for a custom library

abc.js
import { form } from '#myCustomLib/validator'
const _validator = new form.particulars.Validator()
function sampleFunctionIWantToTest(formInfo) {
var error = _validator.fullValidation(formInfo)
if(error) {return true}
return false
}
I want to write a test for the function. I would like to mock the result for
_validator.fullValidation(formInfo)
How do I mock?
You can use jest.mock(moduleName, factory, options) to mock #myCustomLib/validator package.
E.g.
abc.js:
import { form } from '#myCustomLib/validator';
const _validator = new form.particulars.Validator();
function sampleFunctionIWantToTest(formInfo) {
var error = _validator.fullValidation(formInfo);
if (error) {
return true;
}
return false;
}
export { sampleFunctionIWantToTest };
abc.test.js:
import { form } from '#myCustomLib/validator';
const validatorMock = {
fullValidation: jest.fn(),
};
jest.mock(
'#myCustomLib/validator',
() => {
const formMock = {
particulars: {
Validator: jest.fn(() => validatorMock),
},
};
return { form: formMock };
},
{ virtual: true },
);
describe('62949328', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should return true', () => {
const mError = new Error('error message');
validatorMock.fullValidation.mockReturnValueOnce(mError);
const { sampleFunctionIWantToTest } = require('./abc');
const actual = sampleFunctionIWantToTest();
expect(actual).toBeTruthy();
expect(form.particulars.Validator).toBeCalledTimes(1);
});
it('should return false', () => {
validatorMock.fullValidation.mockReturnValueOnce(null);
const { sampleFunctionIWantToTest } = require('./abc');
const actual = sampleFunctionIWantToTest();
expect(actual).toBeFalsy();
expect(form.particulars.Validator).toBeCalledTimes(1);
});
});
unit test result with 100% coverage:
PASS stackoverflow/62949328/abc.test.js (13.298s)
62949328
✓ should return true (6ms)
✓ should return false (1ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
abc.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 15.161s
jestjs version: "jest": "^25.5.4",

Jest: Mock class method in a function

So just trying to understand how I mock a class function within a function itself. How do I mock the data returned from the exchange.someFunction() method so I can test the actual getPositions() function itself?
const library = require('library');
const exchange = new library.exchange_name();
async function getPositions() {
let positions = [];
const results = await exchange.someFunction();
// Do some stuff
return results;
}
I was trying to do the following but have no idea if I'm doing anything correct at all
const exchange = require('../../exchange');
jest.mock('library')
it('get balances', async () => {
library.someFunction.mockResolvedValue({
data: [{some data here}]
)}
}
Error thrown:
TypeError: Cannot read property 'mockResolvedValue' of undefined
Here is the unit test solution:
index.js:
const library = require('./library');
const exchange = new library.exchange_name();
async function getPositions() {
let positions = [];
const results = await exchange.someFunction();
return results;
}
module.exports = getPositions;
library.js:
function exchange_name() {
async function someFunction() {
return 'real data';
}
return {
someFunction,
};
}
module.exports = { exchange_name };
index.test.js:
const getPositions = require('./');
const mockLibrary = require('./library');
jest.mock('./library', () => {
const mockExchange = { someFunction: jest.fn() };
return { exchange_name: jest.fn(() => mockExchange) };
});
describe('61649788', () => {
it('get balances', async () => {
const mockExchange = new mockLibrary.exchange_name();
mockExchange.someFunction.mockResolvedValueOnce({ data: ['mocked data'] });
const actual = await getPositions();
expect(actual).toEqual({ data: ['mocked data'] });
expect(mockExchange.someFunction).toBeCalled();
});
});
unit test results with 100% coverage:
PASS stackoverflow/61649788/index.test.js (8.775s)
61649788
✓ get balances (7ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.099s

How to mock object creation and its method

new UrlBuilder(urlString).buildURL(params).getShortenedURL().then(data => {
.....
});
How can I stub the object creation and check whether getShortenedURL() has been called?
I tried
this.urlBuilder = sinon.stub(UrlBuilder.prototype, getShortenedURL).resolves({url: '/someUrl'});
But every time I run a test that has:
assert(this.urlBuilder.getShortenedURL.called);
it'll say
ReferenceError: getShortenedURL is not defined
Here is the unit test solution:
index.js:
const UrlBuilder = require('./urlBuilder');
function main() {
const urlString = 'https://stackoverflow.com/';
const params = {};
return new UrlBuilder(urlString)
.buildURL(params)
.getShortenedURL()
.then((data) => data);
}
module.exports = main;
urlBuilder.js:
class UrlBuilder {
constructor(url) {
this.url = url;
}
buildURL(params) {
return this;
}
getShortenedURL() {
return Promise.resolve('real data');
}
}
module.exports = UrlBuilder;
index.test.js:
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const { expect } = require('chai');
describe('60214679', () => {
it('should pass', async () => {
const urlBuilderInstanceStub = {
buildURL: sinon.stub().returnsThis(),
getShortenedURL: sinon.stub().resolves('fake data'),
};
const urlBuilderStub = sinon.stub().callsFake(() => urlBuilderInstanceStub);
const main = proxyquire('./', {
'./urlBuilder': urlBuilderStub,
});
const actual = await main();
expect(actual).to.be.eq('fake data');
sinon.assert.calledWithExactly(urlBuilderStub, 'https://stackoverflow.com/');
sinon.assert.calledWithExactly(urlBuilderInstanceStub.buildURL, {});
sinon.assert.calledOnce(urlBuilderInstanceStub.getShortenedURL);
});
});
Unit test results with coverage report:
60214679
✓ should pass (2010ms)
1 passing (2s)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 70 | 100 | 40 | 70 |
index.js | 100 | 100 | 100 | 100 |
urlBuilder.js | 25 | 100 | 0 | 25 | 3,6,9
---------------|---------|----------|---------|---------|-------------------
Source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/60214679

Asserting that method has been called in a promise with Mocha and Sinon

I have the following simplified method and test, where I want to test that handleResponse() has been called.
The test fails with handleResponse() not beeing called at all. If I modify the code to run handleResponse outside the promise, the test completes successfully.
Is this because the promise is async, and the assertion is being run before the promise? If so, how can I wait for the promise to the completed before running the assertion?
Code:
export function fetchList(id) {
// handleResponse(response); // Works here
return (dispatch) => {
service.getList(id).then((response) => {
handleResponse(response); // Doesnt work here
}, (error) => {
addNotification(error);
});
};
}
Test:
describe('fetchList', () => {
let getListStub;
let handleResponseStub;
beforeEach(() => {
getListStub = sinon.stub(service, 'getList');
handleResponseStub = sinon.stub(appActions, 'handleResponse');
});
afterEach(() => {
getListStub.restore();
handleResponseStub.restore();
});
it('should dispatch handleResponse on success', () => {
const dispatchStub = sinon.stub();
const id = 1;
const returnValue = 'return value';
getListStub.withArgs(id).resolves(returnValue);
listActions.fetchList(id)(dispatchStub);
sinon.assert.calledOnce(getListStub);
sinon.assert.calledOnce(handleResponseStub); // Fails
});
});
You forget add async/await to your unit test and change to return service.getList(...). Otherwise, the assertion will execute before resolving the promise of service.getList(...).
listActions.ts:
import * as service from "./service";
import { handleResponse, addNotification } from "./appActions";
export function fetchList(id) {
return dispatch => {
return service.getList(id).then(
response => {
handleResponse(response);
},
error => {
addNotification(error);
}
);
};
}
appActions.ts:
export function handleResponse(res) {
console.log("handleResponse");
}
export function addNotification(error) {
console.log("addNotification");
}
service.ts:
export function getList(id) {
return new Promise(resolve => {
setTimeout(() => {
resolve([]);
}, 5000);
});
}
listActions.spec.ts:
import * as service from "./service";
import * as appActions from "./appActions";
import * as listActions from "./listActions";
import sinon from "sinon";
describe("fetchList", () => {
let getListStub;
let handleResponseStub;
beforeEach(() => {
getListStub = sinon.stub(service, "getList");
handleResponseStub = sinon.stub(appActions, "handleResponse");
});
afterEach(() => {
getListStub.restore();
handleResponseStub.restore();
});
it("should dispatch handleResponse on success", async () => {
const dispatchStub = sinon.stub();
const id = 1;
const returnValue = "return value";
getListStub.withArgs(id).resolves(returnValue);
await listActions.fetchList(id)(dispatchStub);
sinon.assert.calledOnce(getListStub);
sinon.assert.notCalled(dispatchStub);
sinon.assert.calledOnce(handleResponseStub); // Fails
});
});
Unit test result with coverage report:
fetchList
✓ should dispatch handleResponse on success
1 passing (95ms)
---------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------------|----------|----------|----------|----------|-------------------|
All files | 83.33 | 100 | 53.85 | 82.86 | |
appActions.ts | 50 | 100 | 0 | 50 | 2,6 |
listActions.spec.ts | 100 | 100 | 100 | 100 | |
listActions.ts | 85.71 | 100 | 75 | 85.71 | 11 |
service.ts | 25 | 100 | 0 | 25 | 2,3,4 |
---------------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/43186634

How to test `catch` and `then` with sinon js?

I have been trying to stub and mock my function to be able to test my function
SetExample.createCandyBox = function(config) {
this.getCandies(config.candyUrl)
.catch(() => {
return {};
})
.then((candies) => {
Advertisements.pushCandyBox(config, candies);
});
};
I want to test a scenario when the config.candyUrl is incorrect(404, etc) with something like:
it('should return to an empty array when url is incorrect', sinon.test(function() {
// Fixture is an element I created for testing.
var configStub = SetExample.getCandyConfig(fixture);
var createCandyBoxMock = sinon.mock(config);
createCandyBoxMock.expects('catch');
SetExample. createCandyBox(configStub);
}));
When I do this, term is error => Can't find variable: config.
What did I do wrong? can someone help and explain? I am new to Sinon :( Thx in advance!
You can use sinon.stub() to stub this.getCandies and its resolved/rejected value. And stub Advertisements.pushCandyBox, then make an assertion to check if it has been called or not.
E.g.
SetExample.js:
const Advertisements = require('./Advertisements');
function SetExample() {}
SetExample.getCandies = async function (url) {
return 'your real getCandies implementation';
};
SetExample.createCandyBox = function (config) {
return this.getCandies(config.candyUrl)
.catch(() => {
return {};
})
.then((candies) => {
Advertisements.pushCandyBox(config, candies);
});
};
module.exports = SetExample;
Advertisements.js:
function Advertisements() {}
Advertisements.pushCandyBox = function (config, candies) {
return 'your real pushCandyBox implementation';
};
module.exports = Advertisements;
SetExample.test.js
const SetExample = require('./SetExample');
const Advertisements = require('./Advertisements');
const sinon = require('sinon');
describe('38846337', () => {
describe('#createCandyBox', () => {
afterEach(() => {
sinon.restore();
});
it('should handle error', async () => {
const err = new Error('timeout');
sinon.stub(SetExample, 'getCandies').withArgs('wrong url').rejects(err);
sinon.stub(Advertisements, 'pushCandyBox');
await SetExample.createCandyBox({ candyUrl: 'wrong url' });
sinon.assert.calledWithExactly(SetExample.getCandies, 'wrong url');
sinon.assert.calledWithExactly(Advertisements.pushCandyBox, { candyUrl: 'wrong url' }, {});
});
});
});
unit test result:
38846337
#createCandyBox
✓ should handle error
1 passing (7ms)
-------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------------|---------|----------|---------|---------|-------------------
All files | 81.82 | 100 | 42.86 | 81.82 |
Advertisements.js | 66.67 | 100 | 0 | 66.67 | 4
SetExample.js | 87.5 | 100 | 60 | 87.5 | 6
-------------------|---------|----------|---------|---------|-------------------

Categories

Resources