I am trying to test an express
controller using jest
and supertest
. I have a middleware that handles file processing with multer
. I can mock multer
globally but I have been unable to mock it per it/test
cases.
// saveImage.controller.ts
jest.mock('multer', () => {
const m = () => ({
single: () => (req: Request, res: Response, next: NextFunction) => {
req.body = { type: 'screenshots' };
req.file = mockFile;
return next();
},
});
m.memoryStorage = () => jest.fn();
return m;
});
describe('POST /api/v1/garment/image/upload', () => {
it('should return 201', async () => {
await request(app)
.post('/api/v1/garment/image/upload')
.send({ file: 'myImage' }) // this is overwritten by the mock
.expect(201); // passes
});
it('should return 400', async () => {
await request(app)
.post('/api/v1/garment/image/upload')
.send() // this is overwritten by the mock
.expect(400); // fails
});
});
The first test is passing but I am unable to alter the mock to make the second test pass.
How can change the mock in my second it
case?
CodePudding user response:
I will use jest.doMock(moduleName, factory, options) to mock multer
. Note that the multer.single()
method will be executed when the module is imported, so we mock it before the module is imported.
In order to clear the cache when the module is imported (can cache the module scope variable, the function of the function, etc.), you need to use jest.resetModules()
before running each test case.
app.ts
:
import express from 'express';
import multer from 'multer';
import path from 'path';
const upload = multer({ dest: path.join(__dirname, 'uploads/') });
const app = express();
app.post('/api/v1/garment/image/upload', upload.single('file'), (req, res) => {
console.log(req.file, req.body);
if (req.file) {
res.sendStatus(201);
} else {
res.sendStatus(400);
}
});
export { app };
app.test.ts
:
import request from 'supertest';
import multer from 'multer';
import { NextFunction, Request, Response } from 'express';
describe('69997349', () => {
let app: typeof import('./app').app;
beforeEach(async () => {
jest.resetModules();
});
it('should return 201', async () => {
const mockFile = { fieldname: 'myImage' } as Express.Multer.File;
jest.doMock('multer', () => {
const m = () => ({
single: () => (req: Request, res: Response, next: NextFunction) => {
req.body = { type: 'screenshots' };
req.file = mockFile;
return next();
},
});
return m;
});
app = (await import('./app')).app;
await request(app).post('/api/v1/garment/image/upload').send({ file: 'myImage' }).expect(201);
});
it('should return 400', async () => {
jest.doMock('multer', () => {
const m = () => ({
single: () => (req: Request, res: Response, next: NextFunction) => {
return next();
},
});
return m;
});
app = (await import('./app')).app;
await request(app).post('/api/v1/garment/image/upload').expect(400);
});
});
test result:
PASS examples/69997349/app.test.ts (8.245 s)
69997349
✓ should return 201 (297 ms)
✓ should return 400 (23 ms)
console.log
{ fieldname: 'myImage' } { type: 'screenshots' }
at examples/69997349/app.ts:10:11
console.log
undefined undefined
at examples/69997349/app.ts:10:11
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 9.428 s, estimated 10 s