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

130 lines
4.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 } 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,
...shipExtras("courier"),
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,
pilotPay: 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();
});
});