/** * Guards the one thing about Payload's mounting that fails silently. * * payload.config.ts itself cannot be imported here — Payload is ESM-only and * next/jest will not transform it — so this asserts the shared constants and * that the config actually wires them in, by reading its source. The live * proof that /api still reaches FastAPI is the e2e journeys, which call * /api/schools against the running app. */ import fs from 'fs'; import path from 'path'; import { PAYLOAD_API_ROUTE, PAYLOAD_ADMIN_ROUTE } from '@/lib/payloadRoutes'; const CONFIG = fs.readFileSync( path.join(__dirname, '..', '..', 'payload.config.ts'), 'utf8', ); describe('payload mount points', () => { it('serves the CMS API from /cms-api, never /api', () => { // /api is the FastAPI proxy's catch-all. Payload's default would be // swallowed by it and forwarded to the backend, silently. expect(PAYLOAD_API_ROUTE).toBe('/cms-api'); expect(PAYLOAD_API_ROUTE).not.toBe('/api'); }); it('serves the admin panel from /admin', () => { expect(PAYLOAD_ADMIN_ROUTE).toBe('/admin'); }); it('wires both constants into the Payload config', () => { expect(CONFIG).toContain('PAYLOAD_API_ROUTE'); expect(CONFIG).toContain('PAYLOAD_ADMIN_ROUTE'); }); it('never hardcodes a routes block that could drift from the constants', () => { expect(CONFIG).not.toMatch(/routes:\s*\{[^}]*api:\s*['"]/); }); it('isolates CMS tables in their own postgres schema', () => { // Blog content must sit outside `public`, where the app tables, Airflow's // metadata and scripts/migrate_csv_to_db.py --drop all live. expect(CONFIG).toMatch(/schemaName:\s*['"]payload['"]/); }); });