deadhead-space-freight-tycoon/apps/web/test/hqs-screen.test.tsx

113 lines
3.4 KiB
TypeScript

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> = {}): 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",
);
});
});