I want to test my express server POST endpoint using supertest. Everything works fine in postman, but when I try to pass in body parameters into the test, as can be seen in the code snippets below, it appears that the body parameters don’t get passed in correctly. I get request body undefined.
Code from my 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;
}
Code from my test file 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);
});
});
});
I’ve searched solutions to this problem and most of the time it comes up that you have to use app.use(bodyParser.json()); before the routes (which I’m using). But the problem still persist.
My main 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;