Jest 模拟每个单独测试的第三方默认导出
Jest mock third-party default export per individual test
我正在尝试使用 jest
和 supertest
测试 express
控制器。我有一个使用 multer
处理文件的中间件。我可以在全球范围内模拟 multer
但我无法在每个 it/test
个案例中模拟它。
// 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
});
});
第一个测试通过了,但我无法更改模拟以使第二个测试通过。
如何更改我的第二个 it
案例中的模拟?
我会用jest.doMock(moduleName, factory, options)来模拟multer
。注意multer.single()
方法会在模块导入的时候执行,所以我们在模块导入之前mock它。
为了在导入模块时清除缓存(可以缓存模块作用域变量,函数的函数等),需要在运行之前使用jest.resetModules()
each测试用例。
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);
});
});
测试结果:
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
我正在尝试使用 jest
和 supertest
测试 express
控制器。我有一个使用 multer
处理文件的中间件。我可以在全球范围内模拟 multer
但我无法在每个 it/test
个案例中模拟它。
// 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
});
});
第一个测试通过了,但我无法更改模拟以使第二个测试通过。
如何更改我的第二个 it
案例中的模拟?
我会用jest.doMock(moduleName, factory, options)来模拟multer
。注意multer.single()
方法会在模块导入的时候执行,所以我们在模块导入之前mock它。
为了在导入模块时清除缓存(可以缓存模块作用域变量,函数的函数等),需要在运行之前使用jest.resetModules()
each测试用例。
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);
});
});
测试结果:
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