98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
import {
|
|
contractBoardResponseSchema,
|
|
dispatchResponseSchema,
|
|
type Contract,
|
|
} from "@deadhead/schema";
|
|
import { describe, expect, it } from "vitest";
|
|
import { setCredits, useTestDatabase } from "./db";
|
|
import {
|
|
call,
|
|
getState,
|
|
insertDispatch,
|
|
signUpOwner,
|
|
testContract,
|
|
useTestApp,
|
|
type Guest,
|
|
} from "./game";
|
|
|
|
const database = useTestDatabase();
|
|
const testApp = useTestApp(database);
|
|
|
|
/** An owner whose Courier has just delivered Earth→Moon; there is no Moon bay. */
|
|
async function landedAtMoon(): Promise<Guest & { shipId: string }> {
|
|
const { app, clock } = testApp();
|
|
const owner = await signUpOwner(app, database().db);
|
|
await setCredits(database().db, owner.playerId, 5000);
|
|
const record = await insertDispatch(database().db, {
|
|
playerId: owner.playerId,
|
|
shipId: owner.shipId,
|
|
pilotId: owner.avatarId,
|
|
departAt: clock.now,
|
|
contract: testContract({ payout: 1000 }),
|
|
});
|
|
clock.now = record.arrivalAt;
|
|
const state = await getState(app, owner);
|
|
expect(state.ships[0]).toMatchObject({ status: "idle", locationId: "moon" });
|
|
expect(state.bays.map((b) => b.locationId)).toEqual(["earth"]);
|
|
return owner;
|
|
}
|
|
|
|
/** A Moon→Earth job the Courier can fly with no skills. */
|
|
function courierJobHome(contracts: Contract[]): Contract {
|
|
const job = contracts.find(
|
|
(c) =>
|
|
c.destinationId === "earth" &&
|
|
c.massTonnes <= 20 &&
|
|
c.requiredSkill === null &&
|
|
c.requiredLongHaulLevel === 0,
|
|
);
|
|
if (!job) throw new Error("no Courier job home on the Moon board");
|
|
return job;
|
|
}
|
|
|
|
describe("no more stranded ships (the original bug)", () => {
|
|
it("lets a ship that delivered to the Moon, with no Moon bay, take a Moon→Earth job home", async () => {
|
|
const { app, clock } = testApp();
|
|
const owner = await landedAtMoon();
|
|
|
|
const board = contractBoardResponseSchema.parse(
|
|
(await call(app, owner, "GET", "/api/locations/moon/board")).json(),
|
|
);
|
|
const job = courierJobHome(board.contracts);
|
|
const response = await call(app, owner, "POST", "/api/dispatches", {
|
|
kind: "contract",
|
|
contractId: job.id,
|
|
shipId: owner.shipId,
|
|
pilotId: owner.avatarId,
|
|
});
|
|
expect(response.statusCode).toBe(200);
|
|
const { dispatch } = dispatchResponseSchema.parse(response.json());
|
|
|
|
clock.now = dispatch.arrivalAt;
|
|
const state = await getState(app, owner);
|
|
expect(state.ships[0]).toMatchObject({ status: "idle", locationId: "earth" });
|
|
expect(state.summaries.find((s) => s.dispatchId === dispatch.id)).toMatchObject({
|
|
originId: "moon",
|
|
destinationId: "earth",
|
|
});
|
|
});
|
|
|
|
it("lets the same ship deadhead Moon→Earth instead", async () => {
|
|
const { app, clock } = testApp();
|
|
const owner = await landedAtMoon();
|
|
const response = await call(app, owner, "POST", "/api/dispatches", {
|
|
kind: "reposition",
|
|
shipId: owner.shipId,
|
|
pilotId: owner.avatarId,
|
|
destinationId: "earth",
|
|
});
|
|
expect(response.statusCode).toBe(200);
|
|
const { dispatch } = dispatchResponseSchema.parse(response.json());
|
|
clock.now = dispatch.arrivalAt;
|
|
expect((await getState(app, owner)).ships[0]).toMatchObject({
|
|
status: "idle",
|
|
locationId: "earth",
|
|
});
|
|
});
|
|
});
|