Files
pn-new-crm/tests/unit/website-inquiries-503.test.ts
Matt 221ae5784e chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged:

- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
  never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
  after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
  redirects (ocr to ai, reports to dashboard, invitations to users),
  docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
  flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
  let-reassign), set-state-in-effect disables in CountryFlag and
  UploadForSigning preview-bytes effect, unused 'confirm' destructures in
  interest contract + reservation tabs, unescaped apostrophe in test-template
  card copy
2026-05-23 00:52:59 +02:00

70 lines
2.2 KiB
TypeScript

/**
* 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<string, string> = {}) {
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()) as any;
expect(body.error).toMatch(/not configured/i);
});
});