使用Supertest测试Express POST接口时请求体undefined问题
使用Supertest测试Express POST接口时请求体参数无法传入的问题
我用Supertest测试Express服务器的POST接口,Postman调用一切正常,但测试里传递请求体参数时,参数无法正确传入,出现「request body undefined」的问题。
controller.ts 代码
import { Router } from 'express'; import { z } from 'zod'; import { Kysely } from 'kysely'; import * as sprints from './services'; import * as schema from './schema'; import { DB } from '../../database'; export function createSprintsRouter(db: Kysely<DB>) { const router = Router(); router.post('/', async (req, res) => { try { const parsedInput = schema.parseNewSprintInput.parse(req.body); const newSprint = await sprints.createSprint(db, parsedInput); res.status(201).json(newSprint); } catch (err) { if (err instanceof z.ZodError) { res.status(400).json({ err: err.errors }); } else { res.status(500).json({ err: (err as Error).message }); } } }); return router; }
测试文件 controller.spec.ts 代码
import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import supertest from 'supertest'; import express from 'express'; import { Kysely } from 'kysely'; import { createSprintsRouter } from '../controller'; import { getTestDbInstance } from '../../../database/db-test'; import type { DB } from '@/database/types'; describe('Sprints Controller', () => { let testDb: Kysely<DB>; let app: express.Application; beforeAll(async () => { testDb = getTestDbInstance(); const sprintsRouter = createSprintsRouter(testDb); app = express().use('/sprints', sprintsRouter); await testDb .insertInto('sprints') .values([ { code: 'TST1', title: 'Test Sprint 1' }, { code: 'TST2', title: 'Test Sprint 2' }, ]) .execute(); }); afterAll(async () => { await testDb.destroy(); }); describe("POST '/' endpoint", () => { it('should create a new sprint', async () => { const newSprint = { code: 'TST3', title: 'Test Sprint 3' }; const res = await supertest(app) .post('/sprints') .set('Content-Type', 'application/json') .send(newSprint); expect(res.status).toBe(201); expect(res.body).toEqual( expect.objectContaining({ code: 'TST3', title: 'Test Sprint 3', }) ); const allSprints = await supertest(app).get('/sprints'); expect(allSprints.body).toHaveLength(3); }); }); });
主文件 app.ts 代码
import express from 'express'; import './bot/discordBot'; import messages from './modules/messages/controller'; import messageTemplates from './modules/message-templates/controller'; import db from './database/index'; import { createSprintsRouter } from './modules/sprints/controller'; const app = express(); app.use(express.json()); const sprintsRouter = createSprintsRouter(db); app.use('/messages', messages); app.use('/templates', messageTemplates); app.use('/sprints', sprintsRouter); export default app;
问题原因及解决方法
问题出在测试文件里创建的Express实例没有配置JSON解析中间件。主文件app.ts里确实用了app.use(express.json()),但测试代码里单独新建的Express实例没有添加这个中间件,导致无法解析请求体,所以req.body为undefined。
解决方法1:给测试用的Express实例添加JSON解析中间件
修改测试文件的beforeAll部分,先挂载express.json()再添加路由:
beforeAll(async () => { testDb = getTestDbInstance(); const sprintsRouter = createSprintsRouter(testDb); app = express() .use(express.json()) .use('/sprints', sprintsRouter); await testDb .insertInto('sprints') .values([ { code: 'TST1', title: 'Test Sprint 1' }, { code: 'TST2', title: 'Test Sprint 2' }, ]) .execute(); });
解决方法2:直接导入主文件的app实例
直接使用生产环境相同的app配置,避免重复创建实例导致的中间件缺失:
// 导入主文件的app import app from '../../../app'; // 测试中直接使用supertest(app),无需重新创建app实例
内容的提问来源于stack exchange,提问作者KarolisG
相关产品推荐
相关产品推荐

