I have been having some trouble getting the correct Express Request type working in Jest. I have a simple user registration passing with this code:
import { userRegister } from '../../controllers/user'; import { Request, Response, NextFunction } from 'express'; describe('User Registration', () => { test('User has an invalid first name', async () => { const mockRequest: any = { body: { firstName: 'J', lastName: 'Doe', email: '[email protected]', password: 'Abcd1234', passwordConfirm: 'Abcd1234', company: 'ABC Inc.', }, }; const mockResponse: any = { json: jest.fn(), status: jest.fn(), }; const mockNext: NextFunction = jest.fn(); await userRegister(mockRequest, mockResponse, mockNext); expect(mockNext).toHaveBeenCalledTimes(1); expect(mockNext).toHaveBeenCalledWith( new Error('First name must be between 2 and 50 characters') ); }); });
However, if I change:
const mockRequest: any = { body: { firstName: 'J', lastName: 'Doe', email: '[email protected]', password: 'Abcd1234', passwordConfirm: 'Abcd1234', company: 'ABC Inc.', }, };
to:
const mockRequest: Partial<Request> = { body: { firstName: 'J', lastName: 'Doe', email: '[email protected]', password: 'Abcd1234', passwordConfirm: 'Abcd1234', company: 'ABC Inc.', }, };
From the TypeScript documentation (https://www.typescriptlang.org/docs/handbook/utility-types.html#partialt), this should make all fields on the Request object optional.
However, I get this error:
Argument of type 'Partial<Request>' is not assignable to parameter of type 'Request'. Property '[Symbol.asyncIterator]' is missing in type 'Partial<Request>' but required in type 'Request'.ts(2345) stream.d.ts(101, 13): '[Symbol.asyncIterator]' is declared here.
I was hoping that someone with a little more TypeScript experience could comment and let me know what I am doing wrong.
Jest can be used to mock ES6 classes that are imported into files you want to test. ES6 classes are constructor functions with some syntactic sugar. Therefore, any mock for an ES6 class must be a function or an actual ES6 class (which is, again, another function). So you can mock them using mock functions.
In Jest mocking is supported out of the box - this is unlike other JavaScript testing frameworks like Mocha. It has built-in mock functions that allow you to replace the actual implementation of a function, capture calls to a function, and verify parameters passed.
Your mock data type doesn't have to perfectly fit the actual data. Well, it doesn't by definition. It's just a mock, right?
What you need is a type assertion. It's a way to tell TypeScript "Okay bro, I know what I'm doing here.".
This is not a production code, it's a test. You're probably even running it in watch mode. We can reject some type safety here without problem. TypeScript doesn't know it's a mock, but we do.
const mockRequest = { body: { firstName: 'J', lastName: 'Doe', email: '[email protected]', password: 'Abcd1234', passwordConfirm: 'Abcd1234', company: 'ABC Inc.', }, } as Request;
If something crashes during the test, because mockRequest
isn't similar to Request enough, we'll know and we'll fix the mock, add some new properties etc.
If as Request
doesn't work you can tell TypeScript "I REALLY know what I'm doing here" by asserting to any
or unknown
first and then to the type you need. It would look like
const x: number = "not a number :wink:" as any as number;
It's useful when we'd like to test that our code doesn't work well with bad input.
For your particular case -- mocking express Request -- there is jest-express to help you, if you can spare the node_modules size of course.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With