96 lines
4.3 KiB
TypeScript
96 lines
4.3 KiB
TypeScript
import fs from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
|
|
import { getGameDb } from '@/lib/db/client';
|
|
import { POST } from './route';
|
|
|
|
// v1.1.0 (ISS-107) — the e2e session-mint hook. CI runs unit tests with FLIGHT_TEST_HOOKS=1 set
|
|
// (docker-compose.ci.yml), so the gate test stubs the env explicitly instead of relying on absence.
|
|
|
|
let dir: string;
|
|
|
|
beforeAll(async () => {
|
|
dir = await fs.mkdtemp(path.join(os.tmpdir(), 'flight-mint-'));
|
|
process.env.FLIGHT_DB_PATH = path.join(dir, 'mint.db');
|
|
});
|
|
|
|
afterAll(async () => {
|
|
vi.unstubAllEnvs();
|
|
delete process.env.FLIGHT_DB_PATH;
|
|
await fs.rm(dir, { recursive: true, force: true });
|
|
});
|
|
|
|
const post = (body?: unknown) =>
|
|
POST(
|
|
new Request('http://localhost/api/test/mint-player-session', {
|
|
method: 'POST',
|
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
}),
|
|
);
|
|
|
|
describe('POST /api/test/mint-player-session', () => {
|
|
it('404s when FLIGHT_TEST_HOOKS is not "1" (like its /api/test/* siblings)', async () => {
|
|
vi.stubEnv('FLIGHT_TEST_HOOKS', '');
|
|
const res = await post();
|
|
expect(res.status).toBe(404);
|
|
});
|
|
|
|
it('mints a session for the seeded local player by default (v1.2.0: e2e plays with backfilled planes)', async () => {
|
|
vi.stubEnv('FLIGHT_TEST_HOOKS', '1');
|
|
const res = await post(); // no body → DEFAULT_USERNAME 'kamilkrzywda'
|
|
expect(res.status).toBe(200);
|
|
const body = (await res.json()) as { sessionId: string };
|
|
expect(body.sessionId).toMatch(/^[0-9a-f-]{36}$/);
|
|
|
|
const inst = await getGameDb();
|
|
// The session resolves to the EXISTING admin user — no new users/players rows are created.
|
|
const sess = inst.raw.exec('SELECT user_id FROM sessions WHERE id = ?', [body.sessionId])[0].values[0];
|
|
expect(String(sess[0])).toBe('admin-kamilkrzywda');
|
|
expect(Number(inst.raw.exec('SELECT COUNT(*) FROM users')[0].values[0][0])).toBe(1);
|
|
expect(Number(inst.raw.exec('SELECT COUNT(*) FROM players')[0].values[0][0])).toBe(1);
|
|
});
|
|
|
|
it('creates a fresh test account WITH onboarding (starter plane at EDDF) for a custom username', async () => {
|
|
vi.stubEnv('FLIGHT_TEST_HOOKS', '1');
|
|
const res = await post({ username: 'e2e-tester' });
|
|
expect(res.status).toBe(200);
|
|
const body = (await res.json()) as { sessionId: string };
|
|
|
|
const inst = await getGameDb();
|
|
const userRow = inst.raw.exec("SELECT id FROM users WHERE username = 'e2e-tester'")[0].values[0];
|
|
expect(userRow.length).toBe(1);
|
|
const playerRow = inst.raw.exec("SELECT id, cash FROM players WHERE username = 'e2e-tester'")[0].values[0];
|
|
expect(String(playerRow[0])).toBe(String(userRow[0])); // one UUID for both rows
|
|
|
|
// v1.2.0 (ISS-108): the new test player gets a starter plane at EDDF owned by them.
|
|
const planes = inst.raw.exec('SELECT id, owner_id, location_icao FROM planes WHERE owner_id = ?', [String(userRow[0])])[0].values;
|
|
expect(planes).toHaveLength(1);
|
|
expect(String(planes[0][2])).toBe('EDDF');
|
|
|
|
// The minted session resolves to the new user.
|
|
const sess = inst.raw.exec('SELECT user_id FROM sessions WHERE id = ?', [body.sessionId])[0].values[0];
|
|
expect(String(sess[0])).toBe(String(userRow[0]));
|
|
});
|
|
|
|
it('is idempotent — re-minting an existing username mints another session, no duplicate rows or planes', async () => {
|
|
vi.stubEnv('FLIGHT_TEST_HOOKS', '1');
|
|
const count = async (sql: string) => Number((await getGameDb()).raw.exec(sql)[0].values[0][0]);
|
|
expect(await count("SELECT COUNT(*) FROM users WHERE username = 'e2e-tester'")).toBe(1);
|
|
|
|
const res = await post({ username: 'e2e-tester' });
|
|
expect(res.status).toBe(200);
|
|
expect(await count("SELECT COUNT(*) FROM users WHERE username = 'e2e-tester'")).toBe(1); // still one account…
|
|
expect(await count("SELECT COUNT(*) FROM planes p JOIN players pl ON p.owner_id = pl.id WHERE pl.username = 'e2e-tester'")).toBe(1); // …and exactly one onboarding plane
|
|
});
|
|
|
|
it('rejects bad usernames and unknown fields with 400', async () => {
|
|
vi.stubEnv('FLIGHT_TEST_HOOKS', '1');
|
|
for (const body of [{ username: 'x' }, { username: 'BAD USER!' }, { bogus: 1 }]) {
|
|
const res = await post(body);
|
|
expect(res.status).toBe(400);
|
|
expect(((await res.json()) as { error: string }).error).toBeTruthy();
|
|
}
|
|
});
|
|
});
|