I am using Jest as my unit test framework. I am trying to mock third part npm “request” and executed my test cases, but i am receiving and the test fails
expect(jest.fn()).toHaveBeenCalledWith(...expected) Expected: 200 Number of calls: 0
The following is my code:
spec.js
jest.mock('request', () => ({ post: jest.fn() })); const request = require('request'); const mockRequest = (reqData) => { return { params: reqData.params? reqData.params:{} , body: reqData.body?reqData.body:{}, headers: reqData.headers?reqData.headers:{} }; }; const mockResponse = () => { const res = {}; res.status = jest.fn().mockReturnValue(res); res.json = jest.fn().mockReturnValue(res); res.send = jest.fn().mockReturnValue(res); return res; }; describe("Test suite for controller", () => { test("should return true for successful validation",async () => { request.post.mockResolvedValue({ "key1":"value1", "key2":"value2" }); const req = mockRequest(); const res = mockResponse(); const Ctrl = require('../../controllers/ctrl') await Ctrl.validate(req, res); //const result = await res1.json(); expect(res.status).toHaveBeenCalledWith(200); }); });
Ctrl.js
const request = require('request'); module.exports = { async validate(req, res) { var postBody = { url: url, form: body, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }; await request.post(postBody, function (error, response, body) { if (error) { return res.status(200).json({ result: "false" }); } else { return res.status(200).json({ result: "true" }); } }); }); }
Please share your ideas. Thanks in adavnce.
Advertisement
Answer
- You don’t need to use
await
with the callback ofrequest.post
, just choose one of them. Don’t use them together. Choose Promise or error-first Callback for handling the asynchronous code. - You should mock the implementation of
request.post
so that you can get the callback function in your test case. Then, you can pass the successful response or error to this callback and test the code logic of callback. - You can use mockFn.mockReturnThis() for mocking the chain methods of
res
object.
Here is the unit test solution:
ctrl.js
:
const request = require('request'); module.exports = { async validate(req, res) { var postBody = { url: 'url', form: req.body, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, }; request.post(postBody, function(error, response, body) { if (error) { return res.status(200).json({ result: 'false' }); } else { return res.status(200).json({ result: 'true' }); } }); }, };
ctrl.spec.js
:
const request = require('request'); const Ctrl = require('./ctrl'); jest.mock('request', () => ({ post: jest.fn(), })); describe('Test suite for controller', () => { afterAll(() => { jest.resetAllMocks(); }); test('should return true for successful validation', async () => { request.post.mockImplementationOnce((body, callback) => { callback(null); }); const req = { body: {} }; const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; await Ctrl.validate(req, res); expect(request.post).toBeCalledWith( { url: 'url', form: {}, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, }, expect.any(Function), ); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toBeCalledWith({ result: 'true' }); }); test('should handle error for failed validation', async () => { const mErr = new Error('network'); request.post.mockImplementationOnce((body, callback) => { callback(mErr); }); const req = { body: {} }; const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; await Ctrl.validate(req, res); expect(request.post).toBeCalledWith( { url: 'url', form: {}, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, }, expect.any(Function), ); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toBeCalledWith({ result: 'false' }); }); });
unit test result with coverage report:
PASS src/stackoverflow/64311760/ctrl.spec.js (16.499s) Test suite for controller ✓ should return true for successful validation (16ms) ✓ should handle error for failed validation (2ms) ----------|----------|----------|----------|----------|-------------------| File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s | ----------|----------|----------|----------|----------|-------------------| All files | 100 | 100 | 100 | 100 | | ctrl.js | 100 | 100 | 100 | 100 | | ----------|----------|----------|----------|----------|-------------------| Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 19.59s