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
Related
let image = await object
.firstCall(params)
.promise()
.then(data => {
return data
})
.catch(err => {
console.(err)
});
What's the way to stub the chained promises with sinon ? I've tried the following, but with no luck
promiseStub = sinon.stub().callsArg(0).resolves("something");
firtCallStub = sinon.stub(object, "firstCall").returns(this.promiseStub);
Unit test solution:
index.ts:
import { object } from './obj';
export async function main() {
const params = {};
return object
.firstCall(params)
.promise()
.then((data) => {
return data;
})
.catch((err) => {
console.log(err);
});
}
obj.ts:
export const object = {
firstCall(params) {
return this;
},
async promise() {
return 'real data';
},
};
index.test.ts:
import { main } from './';
import { object } from './obj';
import sinon from 'sinon';
import { expect } from 'chai';
describe('64795845', () => {
afterEach(() => {
sinon.restore();
});
it('should return data', async () => {
const promiseStub = sinon.stub(object, 'promise').resolves('fake data');
const firtCallStub = sinon.stub(object, 'firstCall').returnsThis();
const actual = await main();
expect(actual).to.be.equal('fake data');
sinon.assert.calledWithExactly(firtCallStub, {});
sinon.assert.calledOnce(promiseStub);
});
});
unit test result:
64795845
✓ should return data
1 passing (32ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 66.67 | 100 | 40 | 66.67 |
index.ts | 83.33 | 100 | 66.67 | 83.33 | 12
obj.ts | 33.33 | 100 | 0 | 33.33 | 3-6
----------|---------|----------|---------|---------|-------------------
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",
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
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