import { describe, it, expect, afterEach } from 'vitest'; import Fastify from 'fastify'; import type { FastifyInstance } from 'fastify'; import { registerHealthRoutes } from '../src/routes/health.js'; let app: FastifyInstance; afterEach(async () => { if (app) await app.close(); }); describe('GET /health', () => { it('returns healthy when DB is up', async () => { app = Fastify({ logger: false }); registerHealthRoutes(app, { checkDb: async () => true }); await app.ready(); const res = await app.inject({ method: 'GET', url: '/health' }); expect(res.statusCode).toBe(200); const body = res.json<{ status: string; version: string; checks: { database: string } }>(); expect(body.status).toBe('healthy'); expect(body.version).toBeDefined(); expect(body.checks.database).toBe('ok'); }); it('returns degraded when DB is down', async () => { app = Fastify({ logger: false }); registerHealthRoutes(app, { checkDb: async () => false }); await app.ready(); const res = await app.inject({ method: 'GET', url: '/health' }); expect(res.statusCode).toBe(503); const body = res.json<{ status: string; checks: { database: string } }>(); expect(body.status).toBe('degraded'); expect(body.checks.database).toBe('error'); }); it('returns degraded when DB check throws', async () => { app = Fastify({ logger: false }); registerHealthRoutes(app, { checkDb: async () => { throw new Error('connection refused'); }, }); await app.ready(); const res = await app.inject({ method: 'GET', url: '/health' }); expect(res.statusCode).toBe(503); }); it('includes uptime and timestamp', async () => { app = Fastify({ logger: false }); registerHealthRoutes(app, { checkDb: async () => true }); await app.ready(); const res = await app.inject({ method: 'GET', url: '/health' }); const body = res.json<{ uptime: number; timestamp: string }>(); expect(body.uptime).toBeGreaterThan(0); expect(body.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/); }); }); describe('GET /healthz', () => { it('returns ok (liveness probe)', async () => { app = Fastify({ logger: false }); registerHealthRoutes(app, { checkDb: async () => true }); await app.ready(); const res = await app.inject({ method: 'GET', url: '/healthz' }); expect(res.statusCode).toBe(200); expect(res.json<{ status: string }>().status).toBe('ok'); }); });