deadhead-space-freight-tycoon/packages/engine/test/ported/state.test.ts

99 lines
3.0 KiB
TypeScript

// Ported from apps/server/test (CR-014 Step 14.5): now runs on the engine.
import { content } from "@deadhead/content";
import { playerStateSchema } from "@deadhead/schema";
import { pilotLevel } from "@deadhead/sim";
import { describe, expect, it } from "vitest";
import {
useTestApp,
signUp,
call,
setCredits,
insertDispatch,
makeOwner,
addShip,
addPilot,
} from "../support";
const randomUUID = () => globalThis.crypto.randomUUID();
const testApp = useTestApp();
describe("full player state", () => {
it("reflects one ship in flight and one idle, and validates against its schema", async () => {
const { app, clock } = testApp();
const guest = await signUp(app);
const { shipId: flyingShipId } = await makeOwner(app, guest.avatarId);
await setCredits(app, 9000);
// A second ship at the Moon crewed by a hired pilot with some XP and a skill.
const idleShipId = randomUUID();
const hiredId = randomUUID();
await addShip(app, {
id: idleShipId,
modelId: "freighter",
name: "Slow Ox",
locationId: "moon",
});
await addPilot(app, {
id: hiredId,
name: "Rae Okafor",
xp: 260,
skills: { "heavy-cargo": 1 },
skillPointsSpent: 1,
assignedShipId: idleShipId,
});
const record = await insertDispatch(app, {
shipId: flyingShipId,
pilotId: guest.avatarId,
departAt: clock.now,
});
const response = await call(app, guest, "GET", "/api/state");
expect(response.statusCode).toBe(200);
const state = playerStateSchema.parse(response.json());
expect(state.company.credits).toBe(9000);
expect(state.tutorial).toBeNull();
expect(state.bays.map((b) => b.locationId)).toEqual(["earth"]);
const flying = state.ships.find((s) => s.id === flyingShipId)!;
const idle = state.ships.find((s) => s.id === idleShipId)!;
expect(flying).toMatchObject({
status: "in-flight",
locationId: null,
dispatchId: record.id,
pilotId: guest.avatarId,
});
expect(idle).toMatchObject({
status: "idle",
locationId: "moon",
dispatchId: null,
pilotId: hiredId,
modelId: "freighter",
});
const avatar = state.pilots.find((p) => p.id === guest.avatarId)!;
const hired = state.pilots.find((p) => p.id === hiredId)!;
expect(avatar).toMatchObject({
status: "in-flight",
locationId: null,
assignedShipId: flyingShipId,
});
expect(hired).toMatchObject({
status: "idle",
locationId: "moon",
assignedShipId: idleShipId,
xp: 260,
level: pilotLevel(260, content.config),
skills: { "heavy-cargo": 1 },
});
expect(hired.level).toBe(2);
expect(hired.skillPointsAvailable).toBe(2 * content.config.skillPointsPerLevel - 1);
expect(state.activeDispatches).toEqual([
expect.objectContaining({ id: record.id, status: "in-flight", arrivalAt: record.arrivalAt }),
]);
expect(state.summaries).toEqual([]);
expect(state.locations).toHaveLength(content.locations.length);
});
});