deadhead-space-freight-tycoon/apps/web/test/deal-modal.test.tsx

163 lines
5.1 KiB
TypeScript

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,
shipExtras,
comeBack,
} from "./render";
const offered = () =>
samplePlayerState({
tutorial: {
loanerLocationId: "earth",
runInFlight: false,
runsCompleted: 4,
dealAvailable: true,
},
});
/** State the server returns after the deal: tutorial over, the Courier and Clipper, a bay, the loan. */
const afterDeal = () =>
samplePlayerState({
tutorial: null,
company: {
id: "co1",
name: "Deadhead Freight",
credits: 800,
loanBalance: content.dealLoanAmount,
},
ships: [
{
id: "s1",
modelId: "courier",
name: "Dusty Mule",
status: "idle",
locationId: "earth",
dispatchId: null,
lastArrivalAt: 0,
...shipExtras("courier"),
pilotId: "avatar",
},
{
id: "s2",
modelId: "clipper",
name: "Swift Heron",
status: "idle",
locationId: "earth",
dispatchId: null,
lastArrivalAt: 0,
...shipExtras("clipper"),
pilotId: "veteran",
},
],
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" });
// Both ships and the veteran (CR-013), names from content.
const veteran = content.veteranPilot;
expect(screen.getByLabelText("Ships and bay")).toHaveTextContent(
`A Courier for you, a Clipper for ${veteran.name}, and a bay at Earth`,
);
expect(dialog).toHaveTextContent("his Courier, his Clipper, and his Earth bay");
expect(screen.getByLabelText("Veteran pilot")).toHaveTextContent(veteran.name);
expect(screen.getByLabelText("Veteran pilot")).toHaveTextContent(veteran.bio);
expect(screen.getByLabelText("Loan amount")).toHaveTextContent(
`${content.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 () => {
comeBack();
const withSummary = () => ({
...offered(),
summaries: [
{
dispatchId: "d4",
shipId: "loaner",
pilotId: "avatar",
originId: "moon",
destinationId: "earth",
tutorial: true,
credits: 96,
deadhead: false,
independent: false,
fuelCost: 0,
topUp: null,
goodId: "consumer-goods",
massTonnes: 12,
shipper: "Pacific Orbital Logistics",
loanRepayment: 0,
pilotPay: 0,
pilotXp: 10,
discoveredLocationId: null,
scriptedId: null,
event: 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");
// The loan offered is the loan the server books (CR-013: Courier + Clipper + bay).
expect(await screen.findByLabelText("Loan amount")).toHaveTextContent(
`${afterDeal().company.loanBalance.toLocaleString("en-US")} cr`,
);
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: "Dashboard" })).toBeInTheDocument();
expect(
screen.queryByRole("dialog", { name: "An offer from Halvorsen" }),
).not.toBeInTheDocument();
});
});