import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { test, expect } from '@playwright/test'; // Read at test time so the assertions track package.json automatically. const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8')) as { version: string }; test('GET /api/version returns the app version from package.json', async ({ page }) => { const res = await page.request.get('/api/version'); expect(res.status()).toBe(200); expect(res.headers()['content-type']).toContain('application/json'); const body = (await res.json()) as { version: string }; expect(body.version).toBe(pkg.version); }); test('GET /api/openapi serves the spec with all seventeen endpoints and the package.json version', async ({ page }) => { const res = await page.request.get('/api/openapi'); expect(res.status()).toBe(200); expect(res.headers()['content-type']).toContain('application/json'); const spec = (await res.json()) as { info: { title: string; version: string }; paths: Record }; expect(spec.info.title).toBe('Flight Ops API'); expect(spec.info.version).toBe(pkg.version); // v0.12.0 swaps the contract accept/dispatch pair for package load/abandon + plane fly; // v0.71.0 adds the admin panel (login/logout/me + guarded DB CRUD). expect(Object.keys(spec.paths).sort()).toEqual([ '/api/admin/tables', // v0.71.0 — admin panel '/api/admin/tables/{name}/rows', // v0.71.0 — GET+PUT+POST+DELETE on one path '/api/airports', '/api/events', // v0.57.0 (ISS-129) — SSE state stream '/api/login', // v0.71.0 — admin panel auth '/api/logout', // v0.71.0 '/api/market/buy-plane', '/api/market/sell-plane', '/api/me', // v0.71.0 '/api/packages/{id}/abandon', '/api/packages/{id}/load', '/api/planes/{planeId}/fly', '/api/planes/{planeId}/queue', '/api/planes/{planeId}/queue/cancel', '/api/planes/{planeId}/repair', // v0.39.0 (ISS-069) '/api/state', '/api/version', ]); });