Node.js cookbook · Beginner

Test an Express API with node:test and supertest

Write fast API tests without a separate test framework, including auth and validation cases.

Approach

Export the Express app separately from server.listen() so tests can call it in-process with supertest. Use the built-in node:test runner and node:assert, reset the test database between tests, and cover success, validation, auth and not-found cases.

Solution

// app.test.ts  (run: node --test, or tsx --test for TypeScript)
import { after, before, beforeEach, describe, it } from "node:test";
import assert from "node:assert/strict";
import request from "supertest";
import { app } from "../src/app.js";
import { db, resetDb } from "./helpers/db.js";

describe("POST /api/orders", () => {
  before(async () => { await db.migrate.latest(); });
  beforeEach(async () => { await resetDb(); });
  after(async () => { await db.destroy(); });

  it("creates an order for an authenticated user", async () => {
    const res = await request(app)
      .post("/api/orders")
      .set("Authorization", `Bearer ${await testToken({ sub: "user-1" })}`)
      .send({ items: [{ sku: "A1", qty: 2 }] })
      .expect(201);
    assert.equal(res.body.items.length, 1);
  });

  it("rejects invalid bodies with 422", async () => {
    const res = await request(app)
      .post("/api/orders")
      .set("Authorization", `Bearer ${await testToken({ sub: "user-1" })}`)
      .send({ items: [] })
      .expect(422);
    assert.equal(res.body.errors[0].field, "body.items");
  });

  it("requires authentication", async () => {
    await request(app).post("/api/orders").send({ items: [] }).expect(401);
  });
});

Pitfalls

  • Starting a real server on a fixed port in tests (port conflicts).
  • Tests sharing database state.
  • Mocking the database driver instead of using a test database.

Variations

  • Vitest/Jest if you prefer their mocking and watch modes.
  • Fastify's app.inject() for in-process requests.

Further reading: Node.js: Test runner

Reference: https://nodejs.org/api/test.html

More Node.js recipes