deadhead-space-freight-tycoon/apps/web/test/map-reach-origins.test.tsx

67 lines
2.4 KiB
TypeScript

import { content } from "@deadhead/content";
import type { Ship } from "@deadhead/schema";
import { checkRoute, gameToReal, realToGame } from "@deadhead/sim";
import { screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, describe, expect, it, vi } from "vitest";
import { useClock } from "../src/clock/clock";
import { fakeApi, renderApp, samplePlayerState, shipExtras } 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 [mars, ceres] = [content.location("mars")!, content.location("ceres-station")!];
/** The first monthly date on which a Clipper at Mars can reach Ceres. */
const NOW = (() => {
for (let i = 0; i <= 16 * 12; i++) {
const t = gameStart + i * MONTH;
if (checkRoute(clipper, mars, ceres, t).ok) return gameToReal(t, content.config);
}
throw new Error("no such date");
})();
const atMars: Ship = {
id: "s1",
modelId: "clipper",
name: "Swift Heron",
status: "idle",
locationId: "mars",
dispatchId: null,
pilotId: null,
lastArrivalAt: 0,
...shipExtras("clipper"),
};
describe("map reachability per origin (Step 10L.8)", () => {
afterEach(() => vi.useRealTimers());
it("lists the Clipper from Mars, where it is, and not from Earth", async () => {
vi.useFakeTimers({ toFake: ["Date", "setInterval", "clearInterval"] });
vi.setSystemTime(NOW);
useClock.setState({ offsetMs: 0, synced: true, now: NOW });
const state = samplePlayerState({
bays: [{ id: "b-earth", locationId: "earth" }],
ships: [atMars],
});
state.locations = state.locations.map((l) =>
l.id === "mars" ? { ...l, discovered: true } : l,
);
renderApp(fakeApi({ getPlayerState: () => state }), "/map");
const canvas = await screen.findByTestId("map-canvas");
await userEvent.click(
within(canvas).getByRole("button", { name: "Tap Ceres Station (locked)" }),
);
const text = screen.getByLabelText("Reachable with").textContent ?? "";
const parts = Object.fromEntries(
text.split(" · ").map((part) => {
const [origin, list] = part.split(": ");
return [origin!, list!.split(", ")];
}),
);
expect(parts["From Mars"]).toContain("Clipper");
expect(parts["From Earth"] ?? []).not.toContain("Clipper");
});
});