/** * Dedicated test for the 503 path on /api/public/website-inquiries. * * Lives in its own file rather than sharing the main test file because * the test mocks `@/lib/env` to return an empty object - that mock would * leak into other tests in the same file via Vitest's module cache, * making the rest of the suite return 503 instead of the expected * status. Isolating to a single-test file sidesteps that entirely. * * Asserts the security-critical contract: when WEBSITE_INTAKE_SECRET is * unset, every request gets 503, regardless of headers or payload. This * is the dev/staging posture; without it, the endpoint would be * unauthenticated. */ import { describe, expect, it, vi } from 'vitest'; vi.mock('@/lib/env', () => ({ env: {}, // WEBSITE_INTAKE_SECRET intentionally unset })); vi.mock('@/lib/rate-limit', () => ({ rateLimiters: { websiteIntake: { limit: 10, window: 60_000 } }, checkRateLimit: vi.fn(async () => ({ allowed: true, resetAt: Date.now() })), })); vi.mock('@/lib/logger', () => ({ logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() }, })); vi.mock('@/lib/db', () => ({ db: { select: () => ({ from: () => ({ where: () => ({ limit: async () => [] }) }) }), insert: () => ({ values: () => ({ onConflictDoNothing: () => ({ returning: async () => [] }), }), }), }, })); function makeReq(body: unknown, headers: Record = {}) { return { headers: { get(name: string) { return headers[name.toLowerCase()] ?? null; }, }, json: async () => body, } as unknown as import('next/server').NextRequest; } describe('POST /api/public/website-inquiries — 503 when secret unset', () => { it('returns 503 even when a "valid" header + payload are supplied', async () => { const { POST } = await import('@/app/api/public/website-inquiries/route'); const res = await POST( makeReq( { submission_id: '11111111-1111-4111-8111-111111111111', kind: 'berth_inquiry', payload: {}, }, { 'x-webhook-secret': 'anything-here-doesnt-matter' }, ), ); expect(res.status).toBe(503); const body = await res.json(); expect(body.error).toMatch(/not configured/i); }); });