import { content } from "@deadhead/content"; import { screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, expect, it } from "vitest"; import { fakeApi, renderApp, samplePlayerState, sampleTutorialBoard } from "./render"; const offered = () => samplePlayerState({ tutorial: { loanerLocationId: "earth", runInFlight: false, runsCompleted: 4, dealAvailable: true, }, }); /** State the server returns after the deal: tutorial over, a Courier, a bay, the loan. */ const afterDeal = () => samplePlayerState({ tutorial: null, company: { id: "co1", name: "Deadhead Freight", credits: 800, loanBalance: content.config.dealLoanAmount, }, ships: [ { id: "s1", modelId: "courier", name: "Dusty Mule", status: "idle", locationId: "earth", dispatchId: null, lastArrivalAt: 0, pilotId: "avatar", }, ], bays: [{ id: "b1", locationId: "earth" }], }); describe("the deal", () => { it("does not appear when the deal is not available", async () => { renderApp( fakeApi({ getPlayerState: () => samplePlayerState(), getTutorialBoard: () => sampleTutorialBoard(), }), "/contracts", ); await screen.findByRole("heading", { level: 1, name: "Contracts" }); expect( screen.queryByRole("dialog", { name: "An offer from Halvorsen" }), ).not.toBeInTheDocument(); }); it("appears when available, showing the configured loan and repayment share", async () => { renderApp( fakeApi({ getPlayerState: offered, getTutorialBoard: () => sampleTutorialBoard() }), "/contracts", ); const dialog = await screen.findByRole("dialog", { name: "An offer from Halvorsen" }); expect(dialog).toHaveTextContent("Courier and a bay at Earth"); expect(screen.getByLabelText("Loan amount")).toHaveTextContent( `${content.config.dealLoanAmount.toLocaleString("en-US")} cr`, ); expect(screen.getByLabelText("Repayment share")).toHaveTextContent( `${Math.round(content.config.loanRepaymentShare * 100)}% of every payout`, ); expect(screen.getAllByRole("button").filter((b) => dialog.contains(b))).toHaveLength(1); }); it("waits until the delivery summary is dismissed", async () => { const withSummary = () => ({ ...offered(), summaries: [ { dispatchId: "d4", shipId: "loaner", pilotId: "avatar", originId: "moon", destinationId: "earth", tutorial: true, credits: 96, deadhead: false, fuelCost: 0, goodId: "consumer-goods", massTonnes: 12, shipper: "Pacific Orbital Logistics", loanRepayment: 0, pilotXp: 10, discoveredLocationId: null, scriptedId: null, restEndsAt: null, resolvedAt: 1, }, ], }); renderApp( fakeApi({ getPlayerState: withSummary, getTutorialBoard: () => sampleTutorialBoard() }), "/contracts", ); await screen.findByRole("dialog", { name: "While you were away" }); expect( screen.queryByRole("dialog", { name: "An offer from Halvorsen" }), ).not.toBeInTheDocument(); }); it("Shake on it accepts the deal and goes to HQ", async () => { let accepted = false; const api = fakeApi({ getPlayerState: () => (accepted ? afterDeal() : offered()), getTutorialBoard: () => sampleTutorialBoard(), acceptDeal: () => { accepted = true; return afterDeal(); }, }); renderApp(api, "/contracts"); await userEvent.click(await screen.findByRole("button", { name: "Shake on it" })); await waitFor(() => expect(api.call).toHaveBeenCalledWith("acceptDeal", {})); expect(await screen.findByRole("heading", { level: 1, name: "HQ" })).toBeInTheDocument(); expect( screen.queryByRole("dialog", { name: "An offer from Halvorsen" }), ).not.toBeInTheDocument(); }); });