Reputation: 87
I am trying mock request()
function of node module request
using jest
in typescript but I was unable to do that, can someone help me where was going wrong? By the way, I am trying to create a generic proxy function that should work with all http methods such as get, post, delete, update. So I want to use request()
function only instead of request.get(),request.post()...etc using an if-else ladder based on the request method.
Proxy.ts:
import * as request from 'request';
export default class ProxyClass {
static proxy(req: any, res: any): any {
const options: any = {
headers: req.headers,
}
const proxyReq: any = request(options);
proxyReq.on('error', (err: any) => {
return res.status(500).send(err);
});
return proxyReq.pipe(res);
}
}
Proxy.spec.ts:
import 'jest';
import * as request from 'request';
import {Request} from 'jest-express/lib/request';
import {Response} from 'jest-express/lib/response';
import ProxyClass from './Proxy';
describe('proxy request', () => {
const req: any = new Request();
const res: any = new Response();
it('should call pipe', () => {
const mockRequest = {
pipe: jest.fn(),
on: jest.fn(),
}
jest.mock('request', () => {
return function() {
return mockRequest;
}
});
ProxyClass.proxy(req, res);
expect(mockRequest.pipe).toHaveBeenCalledTimes(1);
jest.clearAllMocks();
});
});
And when I run above test, I am getting the error:
TypeError: request is not a function
Upvotes: 2
Views: 12770
Reputation: 45810
If you are getting TypeError: request is not a function
then you probably have esModuleInterop
set to true
in your TypeScript config.
If that is the case then you'll need to import request
like this:
import request from 'request';
TypeScript and ES6 modules are different than the older module style and the esModuleInterop
flag tells TypeScript to do some extra work to compile import
statements of older modules to work as if they were the newer style...in this case treating the single function export as if it were the default
export of a TypeScript/ES6 module.
jest.mock
doesn't work inside a test so you'll need to move it outside the test.
If you are passing a factory function as the second parameter then it needs to be completely self-contained since the call to jest.mock
gets hoisted and will run before anything else in the test file.
In this case you can make your mock return the same object every time so you can get the mock during your test and check that it was called as expected:
import request from 'request';
import {Request} from 'jest-express/lib/request';
import {Response} from 'jest-express/lib/response';
import ProxyClass from './Proxy';
jest.mock('request', () => {
const mockRequest = {
pipe: jest.fn(),
on: jest.fn(),
}
return function() {
return mockRequest; // <= returns the same object every time...
}
});
describe('proxy request', () => {
const req: any = new Request();
const res: any = new Response();
it('should call pipe', () => {
const mockRequest = request(); // <= ...so you can get it here
ProxyClass.proxy(req, res);
expect(mockRequest.pipe).toHaveBeenCalledTimes(1); // Success!
jest.clearAllMocks();
});
});
(note that you don't need to import jest
since jest
loads and runs your test files and has already inserted itself into the global scope)
Upvotes: 3