153 lines
5.0 KiB
TypeScript
153 lines
5.0 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, 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 () => {
|
|
const withSummary = () => ({
|
|
...offered(),
|
|
summaries: [
|
|
{
|
|
dispatchId: "d4",
|
|
shipId: "loaner",
|
|
pilotId: "avatar",
|
|
originId: "moon",
|
|
destinationId: "earth",
|
|
tutorial: true,
|
|
credits: 96,
|
|
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: 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();
|
|
});
|
|
});
|