import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { GET } from './route'; let dir: string; beforeAll(async () => { // Same pattern as app/api/state/route.test.ts: point the DB singleton at a throwaway file so // this test never touches ./db/flight.db. getGameDb() reads the env var on first call, and // vitest gives each test file its own module registry (fresh singleton). dir = await fs.mkdtemp(path.join(os.tmpdir(), 'flight-events-')); process.env.FLIGHT_DB_PATH = path.join(dir, 'events.db'); }); afterAll(async () => { delete process.env.FLIGHT_DB_PATH; await fs.rm(dir, { recursive: true, force: true }); }); describe('GET /api/events', () => { it('streams SSE with the current snapshot as the first event', async () => { const res = await GET(); expect(res.status).toBe(200); expect(res.headers.get('content-type')).toContain('text/event-stream'); expect(res.headers.get('cache-control')).toBe('no-cache'); expect(res.headers.get('x-accel-buffering')).toBe('no'); const reader = (res.body as ReadableStream).getReader(); try { const { value } = await reader.read(); // first chunk: the initial snapshot event const text = new TextDecoder().decode(value); expect(text.startsWith('data: ')).toBe(true); const snap = JSON.parse(text.slice('data: '.length)) as Record; expect(typeof (snap.simState as { clockMs: number }).clockMs).toBe('number'); } finally { await reader.cancel(); // → stream cancel → unsubscribe from the registry } }); });