Files
Flight-Ops/app/api/contracts/[id]/accept/route.test.ts
T

66 lines
2.6 KiB
TypeScript

import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { eq } from 'drizzle-orm';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import * as schema from '@/lib/db/schema';
import { getGameDb } from '@/lib/db/client';
import { POST } from './route';
let dir: string;
beforeAll(async () => {
// Same pattern as app/api/state/route.test.ts: point the DB singleton at a
// throwaway file (fresh module registry per test file → fresh singleton).
dir = await fs.mkdtemp(path.join(os.tmpdir(), 'flight-accept-api-'));
process.env.FLIGHT_DB_PATH = path.join(dir, 'accept.db');
});
afterAll(async () => {
delete process.env.FLIGHT_DB_PATH;
await fs.rm(dir, { recursive: true, force: true });
});
const post = (id: string) => POST(new Request(`http://localhost/api/contracts/${id}/accept`), { params: Promise.resolve({ id }) });
describe('POST /api/contracts/:id/accept', () => {
it('returns the full state snapshot with the contract accepted', async () => {
const { db } = await getGameDb();
const open = (await db.select().from(schema.contracts)).find((c) => c.status === 'open')!;
const res = await post(open.id);
expect(res.status).toBe(200);
expect(res.headers.get('content-type')).toContain('application/json');
// Response convention: the FULL snapshot, same shape as GET /api/state.
const body = (await res.json()) as {
account: { cash: number };
simState: { clockMs: number; timeScale: number; paused: boolean };
planes: Array<Record<string, unknown>>;
contracts: Array<{ id: string; status: string }>;
};
expect(Object.keys(body).sort()).toEqual(['account', 'contracts', 'planes', 'simState']);
expect(body.contracts.find((c) => c.id === open.id)?.status).toBe('accepted');
// Persisted, not just in the response.
const row = (await db.select().from(schema.contracts).where(eq(schema.contracts.id, open.id)))[0];
expect(row.status).toBe('accepted');
});
it('rejects a non-open contract with 409', async () => {
const { db } = await getGameDb();
// Deterministic regardless of which contract the first test accepted.
await db.update(schema.contracts).set({ status: 'completed' }).where(eq(schema.contracts.id, 'contract-2'));
const res = await post('contract-2');
expect(res.status).toBe(409);
expect(((await res.json()) as { error: string }).error).toMatch(/completed/);
});
it('rejects an unknown id with 404', async () => {
const res = await post('nope');
expect(res.status).toBe(404);
expect(((await res.json()) as { error: string }).error).toMatch(/not found/);
});
});