import Fastify, { FastifyInstance } from 'fastify'; import { AppError } from '../../src/utils/errors.js'; import { adminQuestionsRoutes } from '../../src/routes/admin/questions.js'; import type { MockDb } from '../test-utils.js'; import { createMockDb } from '../test-utils.js'; const mockAdminUser = { id: 'admin-1', email: 'admin@test.com' }; /** * Build a minimal Fastify app for admin route integration tests. * Bypasses real auth - preHandlers set req.user to mock admin. */ export async function buildAdminTestApp(mockDb?: MockDb): Promise { const db = mockDb ?? createMockDb(); const app = Fastify({ logger: false, requestIdHeader: 'x-request-id', requestIdLogLabel: 'requestId', }); app.setErrorHandler((err: unknown, _request, reply) => { const error = err as Error & { statusCode?: number; validation?: unknown }; if (err instanceof AppError) { return reply.status(err.statusCode).send(err.toJSON()); } if (error.validation) { return reply.status(422).send({ error: { code: 'VALIDATION_ERROR', message: 'Validation failed', details: error.validation }, }); } return reply.status(500).send({ error: { code: 'INTERNAL_ERROR', message: error.message } }); }); app.decorate('db', db); app.decorate('rateLimitOptions', { apiAuthed: { max: 100, timeWindow: '1 minute' }, }); app.decorateRequest('user', undefined); app.decorate('authenticate', async (req: { user?: { id: string; email: string } }) => { req.user = mockAdminUser; }); app.decorate('authenticateAdmin', async (req: { user?: { id: string; email: string } }) => { if (!req.user) req.user = mockAdminUser; (req.user as { role?: string }).role = 'admin'; }); await app.register(adminQuestionsRoutes, { prefix: '/admin' }); return app; }