deadhead-space-freight-tycoon/apps/web/test/away-summary.test.tsx

162 lines
4.9 KiB
TypeScript

import type { ResolutionSummary, Ship } from "@deadhead/schema";
import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it } from "vitest";
import { fakeApi, renderApp, samplePlayerState, shipExtras } from "./render";
const ship: Ship = {
id: "s1",
modelId: "courier",
name: "Dusty Mule",
status: "idle",
locationId: "mars",
dispatchId: null,
lastArrivalAt: 0,
...shipExtras("courier"),
pilotId: "avatar",
};
const summaries: ResolutionSummary[] = [
{
dispatchId: "d1",
shipId: "s1",
pilotId: "avatar",
originId: "earth",
destinationId: "mars",
tutorial: false,
credits: 51_200,
deadhead: false,
fuelCost: 0,
topUp: null,
goodId: "consumer-goods",
massTonnes: 12,
shipper: "Pacific Orbital Logistics",
loanRepayment: 0,
pilotPay: 0,
pilotXp: 32,
discoveredLocationId: "mars",
scriptedId: null,
restEndsAt: null,
resolvedAt: 1,
},
{
dispatchId: "d2",
shipId: "loaner",
pilotId: "avatar",
originId: "moon",
destinationId: "earth",
tutorial: true,
credits: 240,
deadhead: false,
fuelCost: 0,
topUp: null,
goodId: "consumer-goods",
massTonnes: 12,
shipper: "Pacific Orbital Logistics",
loanRepayment: 0,
pilotPay: 0,
pilotXp: 10,
discoveredLocationId: null,
scriptedId: null,
restEndsAt: null,
resolvedAt: 2,
},
];
describe("while you were away", () => {
it("names what was delivered, how much, for whom and where (CR-007)", async () => {
const delivery: ResolutionSummary = {
...summaries[0]!,
destinationId: "moon",
goodId: "medical-supplies",
massTonnes: 6,
shipper: "Meridian Health",
discoveredLocationId: null,
};
renderApp(
fakeApi({
getPlayerState: () =>
samplePlayerState({ tutorial: null, ships: [ship], summaries: [delivery] }),
}),
);
const dialog = await screen.findByRole("dialog", { name: "While you were away" });
expect(within(dialog).getAllByRole("listitem")[0]).toHaveTextContent(
"Delivered 6 t Medical Supplies for Meridian Health to the Moon",
);
});
it("shows a deadhead as an empty flight with its fuel, not as a +0 payout", async () => {
const deadhead: ResolutionSummary = {
...summaries[0]!,
dispatchId: "d3",
destinationId: "moon",
deadhead: true,
fuelCost: 230,
topUp: null,
goodId: null,
massTonnes: null,
shipper: null,
credits: 0,
pilotXp: 0,
discoveredLocationId: null,
};
renderApp(
fakeApi({
getPlayerState: () =>
samplePlayerState({ tutorial: null, ships: [ship], summaries: [deadhead] }),
}),
);
const dialog = await screen.findByRole("dialog", { name: "While you were away" });
const entry = within(dialog).getAllByRole("listitem")[0]!;
expect(entry).toHaveTextContent("Dusty Mule");
expect(entry).toHaveTextContent("Earth → Moon");
expect(entry).toHaveTextContent("Deadhead · 230 cr fuel");
expect(entry).not.toHaveTextContent("+0 cr");
expect(entry).not.toHaveTextContent("XP");
expect(entry).not.toHaveTextContent("Delivered");
});
it("lists each completed delivery, and dismissing acknowledges them and hides the dialog", async () => {
let acknowledged = false;
const api = fakeApi({
getPlayerState: () =>
samplePlayerState({
tutorial: null,
ships: [ship],
summaries: acknowledged ? [] : summaries,
}),
acknowledgeSummaries: ({ dispatchIds }) => {
acknowledged = true;
return { acknowledged: dispatchIds.length };
},
});
renderApp(api);
const dialog = await screen.findByRole("dialog", { name: "While you were away" });
const items = within(dialog).getAllByRole("listitem");
expect(items).toHaveLength(2);
expect(items[0]).toHaveTextContent("Dusty Mule");
expect(items[0]).toHaveTextContent("Earth → Mars");
expect(items[0]).toHaveTextContent("+51,200 cr");
expect(items[0]).toHaveTextContent("+32 XP");
expect(items[0]).toHaveTextContent("Discovered Mars!");
expect(items[1]).toHaveTextContent("Company loaner");
expect(items[1]).toHaveTextContent("Moon → Earth");
expect(items[1]).not.toHaveTextContent("Discovered");
await userEvent.click(within(dialog).getByRole("button", { name: "Got it" }));
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
await waitFor(() =>
expect(api.call).toHaveBeenCalledWith("acknowledgeSummaries", { dispatchIds: ["d1", "d2"] }),
);
});
it("does not show the dialog when there is nothing to report", async () => {
renderApp(fakeApi({ getPlayerState: () => samplePlayerState() }));
await screen.findByRole("heading", { level: 1, name: "HQ" });
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
});
});