import { describe, it, expect } from 'vitest'; import express from 'express'; import request from 'supertest'; import { z } from 'zod'; import { validate } from '../../lib/api/validate.js'; import { errorMiddleware } from '../../lib/api/errors.js'; import { parsePagination } from '../../lib/api/pagination.js'; function buildApp() { const app = express(); app.use(express.json()); app.post('/body', validate({ body: z.object({ name: z.string().min(1) }) }), (req, res) => res.json(req.body) ); app.get('/params/:id', validate({ params: z.object({ id: z.string().uuid() }) }), (req, res) => res.json(req.params) ); app.get('/page', (req, res) => { try { const p = parsePagination(req); res.json(p); } catch (e) { errorMiddleware(e, req, res, () => {}); } }); app.use(errorMiddleware); return app; } describe('api/validate', () => { it('body schema parses and replaces req.body', async () => { const res = await request(buildApp()).post('/body').send({ name: 'home' }); expect(res.status).toBe(200); expect(res.body).toEqual({ name: 'home' }); }); it('body schema failure → 400 with zod issues in details', async () => { const res = await request(buildApp()).post('/body').send({ name: '' }); expect(res.status).toBe(400); expect(res.body.error.code).toBe('validation_failed'); expect(Array.isArray(res.body.error.details)).toBe(true); expect(res.body.error.details.length).toBeGreaterThan(0); }); it('params schema failure → 400', async () => { const res = await request(buildApp()).get('/params/not-a-uuid'); expect(res.status).toBe(400); }); }); describe('api/pagination', () => { it('defaults to limit=50 offset=0', async () => { const res = await request(buildApp()).get('/page'); expect(res.body).toEqual({ limit: 50, offset: 0 }); }); it('honors ?limit&offset', async () => { const res = await request(buildApp()).get('/page?limit=10&offset=5'); expect(res.body).toEqual({ limit: 10, offset: 5 }); }); it('rejects negative offset', async () => { const res = await request(buildApp()).get('/page?offset=-1'); expect(res.status).toBe(400); }); it('rejects limit above max', async () => { const res = await request(buildApp()).get('/page?limit=999'); expect(res.status).toBe(400); }); });