v1.1.0: session guard on all game routes + register + sign-in screen (ISS-107)
CI / build + unit + e2e (pull_request) Failing after 26m20s

This commit is contained in:
2026-09-26 14:40:56 +00:00
parent 21dd37f88c
commit b0f1bd8b67
54 changed files with 1002 additions and 91 deletions
+13 -4
View File
@@ -5,9 +5,12 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { loadAirportsGeoJson } from '@/lib/airports';
import { haversineKm } from '@/lib/geo';
import { FUEL_PRICE_PER_L, PLANE_TYPES, SELL_FRACTION } from '@/lib/game/catalog';
import { createSession } from '@/lib/auth';
import { getGameDb } from '@/lib/db/client';
import { GET } from './route';
let dir: string;
let sessionId: string;
beforeAll(async () => {
// Point the app's DB singleton at a throwaway file so this test never
@@ -15,8 +18,14 @@ beforeAll(async () => {
// vitest gives each test file its own module registry (fresh singleton).
dir = await fs.mkdtemp(path.join(os.tmpdir(), 'flight-state-'));
process.env.FLIGHT_DB_PATH = path.join(dir, 'state.db');
// v1.1.0 (ISS-107): /api/state is session-guarded — mint a session for the seeded admin user
// (no password needed: createSession only inserts into sessions; the guard joins players on
// username → the 'local' row).
sessionId = await createSession(await getGameDb(), 'admin-kamilkrzywda');
});
const req = () => new Request('http://localhost/api/state', { headers: { 'X-Flight-Session': sessionId } });
afterAll(async () => {
delete process.env.FLIGHT_DB_PATH;
await fs.rm(dir, { recursive: true, force: true });
@@ -24,7 +33,7 @@ afterAll(async () => {
describe('GET /api/state', () => {
it('returns 200 with the full snapshot shape', async () => {
const res = await GET();
const res = await GET(req());
expect(res.status).toBe(200);
expect(res.headers.get('content-type')).toContain('application/json');
@@ -75,13 +84,13 @@ describe('GET /api/state', () => {
});
it('is stable across repeated calls (same seeded DB)', async () => {
const a = ((await GET()).json()) as Promise<{ account: { cash: number } }>;
const b = ((await GET()).json()) as Promise<{ account: { cash: number } }>;
const a = ((await GET(req())).json()) as Promise<{ account: { cash: number } }>;
const b = ((await GET(req())).json()) as Promise<{ account: { cash: number } }>;
expect((await b).account.cash).toBe((await a).account.cash);
});
it('exposes the catalog + economy constants matching lib/game/catalog.ts (v0.10.0)', async () => {
const body = ((await GET()).json()) as Promise<{
const body = ((await GET(req())).json()) as Promise<{
catalog: Array<Record<string, unknown>>;
fuelPricePerL: number;
sellFraction: number;