Files
support_backend/tests/unit/app.test.ts
T
saqib mirandClaude Sonnet 5 5444fb7ef3 fix: setErrorHandler must be registered before route modules
Fastify resolves each encapsulated child context's error handler at
the time that context is registered. app.ts called
app.setErrorHandler()/setNotFoundHandler() AFTER bootstrapRoutes()
had already registered every domain module's routes (each
app.register(someRoutes) call creates its own child context, since
none of the route modules use fastify-plugin). A handler set on the
parent afterwards does not retroactively apply to already-registered
children, so every module's routes were silently falling back to
Fastify's default {statusCode, error, message} error shape instead
of this app's {success:false, error:{code,message,details},
requestId} envelope, for any thrown error -- not specific to any one
feature. Discovered while building and manually verifying the
002-saas-integration feature's inbound endpoint.

Also fixed the generic error-handler branch to preserve a framework
error's own client-facing statusCode (e.g. 400 for malformed JSON)
instead of always reporting 500.

Added a regression test in tests/unit/app.test.ts that fails without
this fix and passes with it (verified both ways).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 18:40:20 +05:30

39 lines
1.9 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { buildApp } from '@/app';
describe('App Factory Unit Test', () => {
it('should build Fastify application instance successfully', async () => {
const app = await buildApp();
expect(app).toBeDefined();
await app.close();
});
it('applies the custom error envelope to errors raised inside a registered route module, not just root-level routes', async () => {
// Regression test: app.setErrorHandler() must be called BEFORE any route module is
// registered (bootstrapRoutes), because Fastify resolves each encapsulated child
// context's error handler at registration time — a handler set afterwards does not
// retroactively apply to already-registered child modules. This was discovered while
// building specs/002-saas-integration: every domain module's routes (registered via
// `app.register(someModuleRoutes)`, which creates a child encapsulation context) were
// silently falling back to Fastify's default `{statusCode, error, message}` shape
// instead of this app's `{success:false, error:{code,message,details}, requestId}`
// envelope. Uses malformed JSON against a real registered route (not a synthetic
// top-level route) so the error is raised by Fastify's own body parser inside that
// module's encapsulation context, with no database/Redis dependency — a regression
// here (e.g. someone moving setErrorHandler back after bootstrapRoutes) fails this test.
const app = await buildApp();
const response = await app.inject({
method: 'POST',
url: '/v1/support/requests',
headers: { 'content-type': 'application/json' },
payload: 'not-valid-json{{{',
});
expect(response.statusCode).toBe(400);
const body = response.json();
expect(body).toMatchObject({ success: false, error: { code: expect.any(String) } });
expect(body.requestId).toBeDefined();
await app.close();
});
});