79 lines
3.0 KiB
TypeScript
79 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 { errorResponseSchema, shipResponseSchema } from "@deadhead/schema";
|
||
import { checkRoute, effectiveStats, gameToReal, realToGame, wouldStrand } from "@deadhead/sim";
|
||
import { describe, expect, it } from "vitest";
|
||
import { TEST_NOW, useTestApp, call, getState, edit, setCredits, signUpOwner } from "../support";
|
||
|
||
const testApp = useTestApp();
|
||
|
||
describe("Lighter and Clipper (Step 10L.6)", () => {
|
||
for (const modelId of ["lighter", "clipper"]) {
|
||
it(`buys a ${modelId} at the chosen HQ`, async () => {
|
||
const { app } = testApp();
|
||
const owner = await signUpOwner(app);
|
||
const price = content.shipModel(modelId)!.price;
|
||
await setCredits(testApp().app, price);
|
||
|
||
const response = await call(app, owner, "POST", "/api/ships", {
|
||
modelId,
|
||
bayId: owner.earthBayId,
|
||
});
|
||
expect(response.statusCode).toBe(200);
|
||
const { ship } = shipResponseSchema.parse(response.json());
|
||
expect(ship).toMatchObject({ modelId, status: "idle", locationId: "earth" });
|
||
expect((await getState(app, owner)).company.credits).toBe(0);
|
||
});
|
||
}
|
||
|
||
it("refuses a deadhead that would strand the ship, changing nothing", async () => {
|
||
const { app, clock } = testApp();
|
||
const owner = await signUpOwner(app);
|
||
await setCredits(app, 100_000);
|
||
// A Clipper at the Moon, 1,420 game days in: Mars is in range from the Moon
|
||
// (198 × 1.3), but from Mars (198 × 1.15) nothing is when it gets there.
|
||
const departure = realToGame(TEST_NOW, content.config) + 1420 * 24 * 3_600_000;
|
||
clock.now = gameToReal(departure, content.config);
|
||
await edit(app, (save) => {
|
||
Object.assign(
|
||
save.ships.find((s) => s.id === owner.shipId)!,
|
||
{
|
||
modelId: "clipper",
|
||
locationId: "moon",
|
||
},
|
||
);
|
||
save.discoveredLocations.push({ locationId: "mars", discoveredAt: TEST_NOW });
|
||
});
|
||
|
||
// The scenario as the sim sees it.
|
||
const clipper = effectiveStats(content.shipModel("clipper")!, {}, content);
|
||
const [moon, mars] = [content.location("moon")!, content.location("mars")!];
|
||
expect(checkRoute(clipper, moon, mars, realToGame(clock.now, content.config)).ok).toBe(true);
|
||
expect(
|
||
wouldStrand(
|
||
clipper,
|
||
moon,
|
||
mars,
|
||
0,
|
||
realToGame(clock.now, content.config),
|
||
undefined,
|
||
content,
|
||
),
|
||
).toBe(true);
|
||
|
||
const before = await getState(app, owner);
|
||
const response = await call(app, owner, "POST", "/api/dispatches", {
|
||
kind: "reposition",
|
||
shipId: owner.shipId,
|
||
pilotId: owner.avatarId,
|
||
destinationId: "mars",
|
||
});
|
||
expect(response.statusCode).toBe(409);
|
||
expect(errorResponseSchema.parse(response.json()).error.code).toBe("would-strand");
|
||
const after = await getState(app, owner);
|
||
expect(after.company.credits).toBe(before.company.credits);
|
||
expect(after.ships).toEqual(before.ships);
|
||
expect(after.activeDispatches).toEqual([]);
|
||
});
|
||
});
|