OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

supertest request body is undefined

  • Thread starter Thread starter KarolisG
  • Start date Start date
K

KarolisG

Guest
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​


Code:
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​


Code:
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​


Code:
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;

<p>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. <em>I get request body undefined.</em></p>
<h2>Code from my controller.ts</h2>
<pre><code>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></pre>
<h2>Code from my test file controller.spec.ts</h2>
<pre><code>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);
});
});
});
</code></pre>
<p>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.</p>
<h2>My main app.ts</h2>
<pre><code>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;
</code></pre>
 
Top