83 lines
3.1 KiB
TypeScript
83 lines
3.1 KiB
TypeScript
import type { Pilot, PlayerState, Ship } from "@deadhead/schema";
|
|
import { act, screen, within } from "@testing-library/react";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { useClock } from "../src/clock/clock";
|
|
import { independentStatus } from "../src/components/IndependentPilots";
|
|
import { fakeApi, renderApp, samplePlayerState, shipExtras } from "./render";
|
|
|
|
const NOW = Date.parse("2100-01-01T00:00:00Z");
|
|
const SHOP_ENDS = NOW + 12 * 60_000 + 34_000;
|
|
|
|
const ship: Ship = {
|
|
id: "s1",
|
|
modelId: "courier",
|
|
name: "Wren",
|
|
status: "idle",
|
|
locationId: "earth",
|
|
dispatchId: null,
|
|
pilotId: "p1",
|
|
lastArrivalAt: NOW - 60_000,
|
|
...shipExtras("courier"),
|
|
inShopUntil: SHOP_ENDS,
|
|
};
|
|
|
|
const base = samplePlayerState();
|
|
const ada = (overrides: Partial<Pilot>): Pilot => ({
|
|
...base.pilots[0]!,
|
|
id: "p1",
|
|
name: "Ada",
|
|
isAvatar: false,
|
|
dutyHours: 11,
|
|
...overrides,
|
|
});
|
|
|
|
/** Ada waiting with the ship in the shop, or unassigned and left at the HQ. */
|
|
const inShop = ada({ assignedShipId: "s1", locationId: "earth", restingInShopUntil: SHOP_ENDS });
|
|
const unassigned = ada({ assignedShipId: null, locationId: "earth", restingInShopUntil: null });
|
|
|
|
const owner = (pilot: Pilot): PlayerState =>
|
|
samplePlayerState({
|
|
tutorial: null,
|
|
bays: [{ id: "b1", locationId: "earth" }],
|
|
ships: [{ ...ship, pilotId: pilot.assignedShipId ? "p1" : null }],
|
|
pilots: [base.pilots[0]!, pilot],
|
|
});
|
|
|
|
describe("resting while in the shop (Step 23.3, decision 0.5.135)", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers({ toFake: ["Date", "setInterval", "clearInterval"] });
|
|
vi.setSystemTime(NOW);
|
|
useClock.setState({ offsetMs: 0, synced: true, now: NOW });
|
|
});
|
|
afterEach(() => vi.useRealTimers());
|
|
|
|
it("shows the shop countdown as rest, and drops it once the pilot is unassigned", async () => {
|
|
let state = owner(inShop);
|
|
const { queryClient } = renderApp(fakeApi({ getPlayerState: () => state }), "/pilots");
|
|
const card = (await screen.findByText("Ada")).closest("li")!;
|
|
expect(within(card).getByLabelText("Ada rest")).toHaveTextContent(
|
|
"Resting while in the shop — 12:34",
|
|
);
|
|
// No duty bar while the shop counts as rest.
|
|
expect(within(card).queryByRole("progressbar", { name: "Ada duty" })).not.toBeInTheDocument();
|
|
|
|
state = owner(unassigned);
|
|
await act(() => queryClient.invalidateQueries());
|
|
const after = (await screen.findByText("Ada")).closest("li")!;
|
|
expect(after).not.toHaveTextContent(/Resting/);
|
|
expect(within(after).getByRole("progressbar", { name: "Ada duty" })).toBeInTheDocument();
|
|
});
|
|
|
|
it("counts down with the clock", async () => {
|
|
renderApp(fakeApi({ getPlayerState: () => owner(inShop) }), "/pilots");
|
|
const card = (await screen.findByText("Ada")).closest("li")!;
|
|
act(() => useClock.setState({ now: NOW + 4 * 60_000 }));
|
|
expect(within(card).getByLabelText("Ada rest")).toHaveTextContent("08:34");
|
|
});
|
|
|
|
it("says so in an Independent pilot's status line", () => {
|
|
const state = owner({ ...inShop, mode: "independent" });
|
|
expect(independentStatus(state, state.pilots[1]!)).toMatch(/^Resting while in the shop until /);
|
|
});
|
|
});
|