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(); }); });