Docs and Tests

Documentation and the Test Suite

The OpenAPI document is generated from schemas.js, following OpenAPI: registry.registerPath is given the same Zod 44,027 objects the validators use, so the published contract cannot drift from the code enforcing it, and GET /openapi.json serves it to any viewer of Interactive Docs.

src/openapi.js — the same schema, registered as a pathJavaScript
registry.registerPath({
  method: 'get', path: '/books', tags: ['Books'], operationId: 'listBooks',
  summary: 'List books', security: [], request: { query: listQuery },
  responses: { 200: { description: 'A page of books', content: { 'application/json': {
    schema: z.object({ data: z.array(Book), page: Page }) } } } }
});

new OpenApiGeneratorV31(registry.definitions).generateDocument({ openapi: '3.1.0', info, servers }) then serializes the lot, Book and Page arriving as $refs in components/schemas.

The suite is 29 Supertest 14,405 cases in one file, and what makes it fast and independent is in beforeEach: a brand-new store per test, and a brand-new app around it. No database, no port, no teardown.

test/api.test.js — a fresh stack per test (excerpt)CSS
beforeEach(async () => {
  app = createApp({ store: createStore(), logger: silent });   // silent: 5xx logs stay quiet
  reader = await tokenFor('ada@example.com');                  // roles ["reader"]
  editor = await tokenFor('root@example.com');                 // roles ["reader","editor"]
});
test('POST /api/v1/books creates and sets Location for an editor', async () => {
  const res = await request(app).post('/api/v1/books')
    .set('Authorization', `Bearer ${editor}`)
    .send({ title: 'Dawn', authorId: 'au_3', year: 1987, genre: 'sci-fi' }).expect(201);
  assert.equal(res.headers.location, '/api/v1/books/bk_6');
  await request(app).get(res.headers.location).expect(200);    // follow what you returned
});

Following the Location header inside the create test proves the URL you advertised is one your router serves — the commonest inconsistency in a hand-written API.

Output of 97
$ node --test test/api.test.js
  ✔ POST /api/v1/books refuses a reader with 403 (148.7043ms)
  ✔ POST /api/v1/books creates and sets Location for an editor (151.1955ms)
  ✔ POST a review, then refuse the second from the same reader (175.9094ms)
  ✔ the OpenAPI document describes every registered path (170.4942ms)        [4 of 29 shown]
ℹ tests 29   ℹ pass 29   ℹ fail 0   ℹ duration_ms 5159.2323

node --test --experimental-test-coverage shows the gaps. The project reaches 99.35% of lines against 90.16% of branches, and error-handler.js sits at 100% of lines with 60% of branches, because no test drives its headersSent or 5xx paths. Branch coverage is the column to read: full lines with half the branches means the happy path ran. Assert one fact per line, too: assert.equal(res.body.error.code, 'conflict') says what broke, where a single deepEqual over a whole body says only that something did.