120 lines
4.1 KiB
TypeScript
120 lines
4.1 KiB
TypeScript
import { pilotExtras } from "./fixtures";
|
|
import { content } from "@deadhead/content";
|
|
import type { Contract, Pilot, Ship } from "@deadhead/schema";
|
|
import { contractTripGameHours, priorityWindow } from "@deadhead/sim";
|
|
import { screen, within } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { formatGameHoursSpan } from "../src/clock/timeFormat";
|
|
import { useClock } from "../src/clock/clock";
|
|
import { fakeApi, renderApp, samplePlayerState, shipExtras } from "./render";
|
|
|
|
const NOW = Date.parse("2100-01-01T00:00:00Z");
|
|
const earth = content.location("earth")!;
|
|
const moon = content.location("moon")!;
|
|
|
|
const ship = (id: string, name: string, modelId: string, pilotId: string): Ship => ({
|
|
id,
|
|
name,
|
|
modelId,
|
|
status: "idle",
|
|
locationId: "earth",
|
|
dispatchId: null,
|
|
lastArrivalAt: 0,
|
|
...shipExtras(modelId),
|
|
pilotId,
|
|
});
|
|
|
|
const pilot = (id: string, name: string, shipId: string): Pilot => ({
|
|
id,
|
|
name,
|
|
isAvatar: false,
|
|
isVeteran: false,
|
|
xp: 0,
|
|
level: 0,
|
|
skills: {},
|
|
skillPointsAvailable: 0,
|
|
assignedShipId: shipId,
|
|
status: "idle",
|
|
locationId: "earth",
|
|
dutyHours: 0,
|
|
dutyLimit: 12,
|
|
resting: false,
|
|
restEndsAt: null,
|
|
...pilotExtras,
|
|
});
|
|
|
|
/** Priority mail to the Moon, with the Freighter-reference window the sim would set. */
|
|
const rush: Contract = {
|
|
id: "c-rush",
|
|
originId: "earth",
|
|
destinationId: "moon",
|
|
cargoTypeId: "standard",
|
|
goodId: "mail",
|
|
shipper: "Pacific Orbital Logistics",
|
|
priority: true,
|
|
deliveryWindowGameHours: priorityWindow(earth, moon, 6, content),
|
|
tier: 0,
|
|
massTonnes: 6,
|
|
payout: 1_500,
|
|
requiredSkill: null,
|
|
requiredLongHaulLevel: 0,
|
|
offeredAt: NOW,
|
|
expiresAt: NOW + 3_600_000,
|
|
firstContact: false,
|
|
};
|
|
|
|
const trip = (modelId: string) => contractTripGameHours(content.shipModel(modelId)!, rush, content);
|
|
|
|
async function openSheet() {
|
|
renderApp(
|
|
fakeApi({
|
|
getPlayerState: () =>
|
|
samplePlayerState({
|
|
tutorial: null,
|
|
company: { id: "c", name: "D", credits: 10_000, loanBalance: 0 },
|
|
bays: [{ id: "b", locationId: "earth" }],
|
|
ships: [
|
|
ship("s-fast", "Quick Finch", "courier", "p-fast"),
|
|
ship("s-slow", "Old Barge", "bulk-hauler", "p-slow"),
|
|
],
|
|
pilots: [pilot("p-fast", "Ana Ruiz", "s-fast"), pilot("p-slow", "Bo Lind", "s-slow")],
|
|
}),
|
|
getContractBoard: () => ({ contracts: [rush], periodEndsAt: NOW + 3_600_000 }),
|
|
}),
|
|
"/contracts?location=earth",
|
|
);
|
|
await userEvent.click(await screen.findByRole("button", { name: "Dispatch" }));
|
|
return screen.getByRole("dialog");
|
|
}
|
|
const option = (dialog: HTMLElement, shipName: string) =>
|
|
within(dialog).getByText(shipName).closest("li")!;
|
|
|
|
describe("Priority in the dispatch sheet (CR-007)", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers({ toFake: ["Date", "setInterval", "clearInterval"] });
|
|
vi.setSystemTime(NOW);
|
|
useClock.setState({ offsetMs: 0, synced: true, now: NOW });
|
|
});
|
|
afterEach(() => vi.useRealTimers());
|
|
|
|
it("enables a ship fast enough for the window and shows its margin", async () => {
|
|
const window = rush.deliveryWindowGameHours!;
|
|
const fast = option(await openSheet(), "Quick Finch");
|
|
expect(within(fast).getByRole("radio")).toBeEnabled();
|
|
expect(within(fast).getByLabelText("Priority margin")).toHaveTextContent(
|
|
`Priority: ${formatGameHoursSpan(trip("courier"), "real")} trip, ${formatGameHoursSpan(window - trip("courier"), "real")} to spare in the ${formatGameHoursSpan(window, "real")} window`,
|
|
);
|
|
});
|
|
|
|
it("disables a too-slow ship with its trip and the window from the sim", async () => {
|
|
const window = rush.deliveryWindowGameHours!;
|
|
expect(trip("bulk-hauler")).toBeGreaterThan(window);
|
|
const slow = option(await openSheet(), "Old Barge");
|
|
expect(within(slow).getByRole("radio")).toBeDisabled();
|
|
expect(within(slow).getByRole("list", { name: "Problems" })).toHaveTextContent(
|
|
`Too slow — ${formatGameHoursSpan(trip("bulk-hauler"), "real")} vs ${formatGameHoursSpan(window, "real")} window`,
|
|
);
|
|
});
|
|
});
|