import type { Dispatch, Pilot, Ship } from "@deadhead/schema"; import { screen, within } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { fuelPriceOf, formatFuelPrice } from "../src/components/Fuel"; import { fakeApi, renderApp, samplePlayerState, shipExtras } from "./render"; const ship = (id: string, name: string, overrides: Partial = {}): Ship => ({ id, modelId: "courier", name, status: "idle", locationId: "earth", dispatchId: null, lastArrivalAt: 0, ...shipExtras("courier"), pilotId: null, ...overrides, }); const avatar = samplePlayerState().pilots[0]!; const spare: Pilot = { ...avatar, id: "p2", name: "Rae Okafor", isAvatar: false, level: 2 }; const inbound: Dispatch = { id: "d1", shipId: "s-fly", pilotId: "avatar", contract: null, originId: "moon", destinationId: "earth", tutorial: false, departureAt: Date.now() - 60_000, arrivalAt: Date.now() + 180_000, distanceMillionKm: 0.39, fuelCost: 50, fuelBurnedFu: 0, expectedPayout: 0, seed: 1, status: "in-flight", resolvedAt: null, }; function render(bays: { id: string; locationId: string }[]) { renderApp( fakeApi({ getPlayerState: () => samplePlayerState({ tutorial: null, bays, ships: [ ship("s1", "Dusty Mule"), ship("s2", "Moon Moth", { locationId: "moon" }), ship("s-fly", "Swift Heron", { status: "in-flight", locationId: null, dispatchId: "d1", }), ], pilots: [ { ...avatar, assignedShipId: "s-fly", status: "in-flight", locationId: null }, spare, ], activeDispatches: [inbound], }), }), "/hqs", ); } describe("HQs screen (CR-020)", () => { it("shows each HQ's ships, inbound flights, spare pilots and fuel price", async () => { render([{ id: "b1", locationId: "earth" }]); const hq = await screen.findByRole("listitem", { name: "HQ at Earth" }); expect(hq).toHaveTextContent(`Fuel: ${formatFuelPrice(fuelPriceOf("earth"))}`); const ships = within(hq).getByRole("region", { name: "Ships at Earth" }); expect(ships).toHaveTextContent("Dusty Mule"); expect(ships).not.toHaveTextContent("Moon Moth"); expect(within(hq).getByRole("region", { name: "Inbound to Earth" })).toHaveTextContent( "Swift Heron from Moon", ); expect(within(hq).getByRole("region", { name: "Pilots at Earth" })).toHaveTextContent( "Rae OkaforLevel 2", ); expect(within(hq).getByRole("link", { name: "View contracts" })).toHaveAttribute( "href", "/contracts?location=earth", ); expect(within(hq).getByRole("link", { name: "Hire pilots" })).toHaveAttribute( "href", "/pilots", ); }); it("lists one card per HQ", async () => { render([ { id: "b1", locationId: "earth" }, { id: "b2", locationId: "moon" }, ]); expect(await screen.findByRole("listitem", { name: "HQ at Moon" })).toHaveTextContent( "Moon Moth", ); expect(screen.getAllByRole("listitem", { name: /^HQ at / })).toHaveLength(2); }); it("points to Places when the player has no HQ", async () => { render([]); expect(await screen.findByText("You don't have an HQ yet.")).toBeInTheDocument(); expect(screen.getByRole("link", { name: "Lease one in Places" })).toHaveAttribute( "href", "/locations", ); }); });