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",
Related
here is my file under test:
file.js:
function handleRequest(grpcRequestObj, callback){
if(grpcRequestObj.type === REAL_CLIENT_REQUEST){
log.trace("Запрос от реального клиента", refId);
module.exports.realClientRequestWay(grpcRequestObj, callback);
return;
}
}
function realClientRequestWay(grpcRequestObj, callback){
//some logic
}
module.exports = {
handleRequest,
realClientRequestWay
}
test file:
test("should call real clients way", ()=>{
jest.mock("../lib/grpc/state");
const state = require("../lib/grpc/state");
state.ready = true;
const constants = require("../lib/grpc/constants");
const handleRequestModule = require("../lib/grpc/handleRequest");
const { handleRequest } = jest.requireActual("../lib/grpc/handleRequest");
handleRequestModule.realClientRequestWay = jest.fn();
const grpcRequest = {
type: constants.REAL_CLIENT_REQUEST,
refId: "123"
};
const mockCb = jest.fn();
handleRequest(grpcRequest, mockCb);
expect(handleRequestModule.realClientRequestWay).toHaveBeenCalledTimes(1);
});
I am mocking realClientRequestWay fucntion to be a jest mock function just to check if it runs,
but it is not calling, what am I doing wrong?
You can use jest.spyOn(object, methodName) and mockImplementation to overwrite the original function with a mocked one.
E.g.
file.js:
const log = { trace: console.log };
const REAL_CLIENT_REQUEST = 'REAL_CLIENT_REQUEST';
function handleRequest(grpcRequestObj, callback) {
const refId = '1';
if (grpcRequestObj.type === REAL_CLIENT_REQUEST) {
log.trace('Запрос от реального клиента', refId);
module.exports.realClientRequestWay(grpcRequestObj, callback);
return;
}
}
function realClientRequestWay(grpcRequestObj, callback) {
//some logic
}
module.exports = {
handleRequest,
realClientRequestWay,
};
file.test.js:
const file = require('./file');
describe('62079376', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('should request', () => {
jest.spyOn(file, 'realClientRequestWay').mockImplementationOnce();
const mCallback = jest.fn();
file.handleRequest({ type: 'REAL_CLIENT_REQUEST' }, mCallback);
expect(file.realClientRequestWay).toBeCalledWith({ type: 'REAL_CLIENT_REQUEST' }, mCallback);
});
it('should do nothing if type not match', () => {
jest.spyOn(file, 'realClientRequestWay').mockImplementationOnce();
const mCallback = jest.fn();
file.handleRequest({ type: '' }, mCallback);
expect(file.realClientRequestWay).not.toBeCalled();
});
});
unit test results with 100% coverage:
PASS stackoverflow/62079376/file.test.js (10.044s)
62079376
✓ should request (16ms)
✓ should do nothing if type not match (1ms)
console.log
Запрос от реального клиента 1
at Object.handleRequest (stackoverflow/62079376/file.js:7:9)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
file.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 11.393s, estimated 12s
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
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
export const get = () => {
return fetch().then((response) => funcA(response));
};
const funcA = (response) => {
if (!response.ok) {
return response.json().then((data) => {
throw Error(...);
});
}
};
How can i mock response.json().then() ? I got the error response.json(...).then is not a function.
I put the json() in the response i mocked
response = { ok: false, json: () => err };
response.json method should return a promise. E.g.
index.ts:
export const funcA = (response) => {
if (!response.ok) {
return response.json().then((data) => {
throw Error(data);
});
}
};
index.test.ts:
import { funcA } from './';
describe('48916842', () => {
it('should pass', () => {
const mResponse = { ok: false, json: jest.fn().mockRejectedValueOnce('custom error') };
expect(funcA(mResponse)).rejects.toThrowError('custom error');
});
});
unit test result with coverage report:
PASS stackoverflow/48916842/index.test.ts (10.276s)
48916842
✓ should pass (5ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 75 | 50 | 50 | 75 |
index.ts | 75 | 50 | 50 | 75 | 4
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 11.929s, estimated 12s
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