67 lines
2.1 KiB
TypeScript
67 lines
2.1 KiB
TypeScript
import Fastify, { FastifyInstance } from 'fastify';
|
|
import { AppError } from '../../src/utils/errors.js';
|
|
import { authRoutes } from '../../src/routes/auth.js';
|
|
import type { MockDb } from '../test-utils.js';
|
|
import { createMockDb } from '../test-utils.js';
|
|
|
|
/** Mock Redis for login lockout in auth tests. Implements ttl, setex, del, eval. */
|
|
const mockRedis = {
|
|
async ttl(_key: string): Promise<number> {
|
|
return -2; // key does not exist -> not blocked
|
|
},
|
|
async setex(_key: string, _ttl: number, _value: string): Promise<'OK'> {
|
|
return 'OK';
|
|
},
|
|
async del(..._keys: string[]): Promise<number> {
|
|
return 0;
|
|
},
|
|
async eval(
|
|
_script: string,
|
|
_keysCount: number,
|
|
..._keysAndArgs: string[]
|
|
): Promise<number[]> {
|
|
return [0, 0, 0]; // counters below threshold
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Build a minimal Fastify app for auth route integration tests.
|
|
* Uses mock db, mock Redis for login lockout, and rate limit options (no actual rate limiting).
|
|
*/
|
|
export async function buildAuthTestApp(mockDb?: MockDb): Promise<FastifyInstance> {
|
|
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('redis', mockRedis);
|
|
app.decorate('rateLimitOptions', {
|
|
register: { max: 100, timeWindow: '1 hour' },
|
|
forgotPassword: { max: 100, timeWindow: '1 hour' },
|
|
verifyEmail: { max: 100, timeWindow: '15 minutes' },
|
|
apiAuthed: { max: 100, timeWindow: '1 minute' },
|
|
apiGuest: { max: 100, timeWindow: '1 minute' },
|
|
});
|
|
|
|
await app.register(authRoutes, { prefix: '/auth' });
|
|
|
|
return app;
|
|
}
|