65 lines
2.6 KiB
TypeScript
65 lines
2.6 KiB
TypeScript
import { content } from "@deadhead/content";
|
|
import { checkRoute, gameToReal, realToGame } from "@deadhead/sim";
|
|
import { screen, within } from "@testing-library/react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { useClock } from "../src/clock/clock";
|
|
import { fakeApi, renderApp, samplePlayerState } from "./render";
|
|
|
|
const MONTH = 30.44 * 24 * 3_600_000;
|
|
const gameStart = realToGame(Date.parse(content.config.epoch.realStart), content.config);
|
|
const clipper = content.shipModel("clipper")!;
|
|
const [earth, mars] = [content.location("earth")!, content.location("mars")!];
|
|
|
|
/** The first monthly date on which Earth→Mars is (or isn't) in a Clipper's range. */
|
|
function dateWhenMars(inRange: boolean): number {
|
|
for (let i = 0; i <= 16 * 12; i++) {
|
|
const t = gameStart + i * MONTH;
|
|
if (checkRoute(clipper, earth, mars, t).ok === inRange) return gameToReal(t, content.config);
|
|
}
|
|
throw new Error("no such date");
|
|
}
|
|
|
|
async function reachOf(modelName: string, now: number) {
|
|
vi.useFakeTimers({ toFake: ["Date"] });
|
|
vi.setSystemTime(now);
|
|
useClock.setState({ offsetMs: 0, synced: true, now });
|
|
renderApp(
|
|
fakeApi({
|
|
getPlayerState: () => samplePlayerState({ bays: [{ id: "b-earth", locationId: "earth" }] }),
|
|
}),
|
|
"/market",
|
|
);
|
|
const card = (await screen.findByRole("button", { name: `Buy ${modelName}` })).closest("li")!;
|
|
return within(card).getByLabelText("Reach").textContent ?? "";
|
|
}
|
|
|
|
describe("market roles and reach (Step 10L.7)", () => {
|
|
afterEach(() => vi.useRealTimers());
|
|
|
|
it("shows each model's role", async () => {
|
|
renderApp(fakeApi({ getPlayerState: () => samplePlayerState() }), "/market");
|
|
for (const model of content.purchasableShipModels) {
|
|
expect(await screen.findByText(model.role)).toBeInTheDocument();
|
|
}
|
|
});
|
|
|
|
it("lists Mars from Earth for a Clipper only when Mars is in range, and Ceres by hopping", async () => {
|
|
const near = await reachOf("Clipper", dateWhenMars(true));
|
|
expect(near).toContain("From Earth now: Moon, Mars");
|
|
expect(near).toContain("By hopping: Ceres Station");
|
|
});
|
|
|
|
it("puts Mars under other dates for a Clipper when it is out of range", async () => {
|
|
const far = await reachOf("Clipper", dateWhenMars(false));
|
|
expect(far).toContain("From Earth now: Moon");
|
|
expect(far).not.toContain("From Earth now: Moon, Mars");
|
|
expect(far).toContain("Other dates: Mars");
|
|
expect(far).toContain("By hopping: Ceres Station");
|
|
});
|
|
|
|
it("lists only the Moon for a Lighter", async () => {
|
|
const reach = await reachOf("Lighter", dateWhenMars(true));
|
|
expect(reach).toBe("Reach From Earth now: Moon");
|
|
});
|
|
});
|