deadhead-space-freight-tycoon/apps/web/test/display-options.test.tsx

113 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { content } from "@deadhead/content";
import type { Contract } from "@deadhead/schema";
import { MS_PER_HOUR, realToGame } from "@deadhead/sim";
import { act, screen } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useClock } from "../src/clock/clock";
import {
formatGameHoursSpan,
formatGameSpan,
formatGameTime,
formatSpan,
formatTimeOfDay,
} from "../src/clock/timeFormat";
import { formatClock } from "../src/format";
import { mapMotionStyle } from "../src/map/layout";
import { mapStyle } from "../src/map/style";
import { DEFAULT_PREFERENCES, usePreferences } from "../src/state/preferences";
import { fakeApi, renderApp, samplePlayerState } from "./render";
const NOW = Date.parse("2100-01-01T00:00:00Z");
/** 4m 16s of real time is 4.27 game hours at 60× compression. */
const SPAN = 4 * 60_000 + 16_000;
describe("time and span helpers (Step 10K.3)", () => {
it("formats game time in 24-hour and 12-hour clocks", () => {
const t = Date.parse("2100-03-14T13:05:00Z");
expect(formatGameTime(t, "24h")).toBe("2100-03-14 13:05");
expect(formatGameTime(t, "12h")).toMatch(/^2100-03-14 1:05\sPM$/);
});
it("formats a real time of day in each clock mode", () => {
const t = new Date(2100, 0, 1, 15, 7).getTime();
expect(formatTimeOfDay(t, "24h")).toBe("15:07");
expect(formatTimeOfDay(t, "12h")).toMatch(/^0?3:07\sPM$/);
expect(formatTimeOfDay(t, "locale")).toBe(
new Date(t).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
);
});
it("formats spans as real time, game time or both", () => {
expect(formatSpan(SPAN, "real")).toBe("4m 16s");
expect(formatSpan(SPAN, "game")).toBe("4.3 game h");
expect(formatSpan(SPAN, "both")).toBe("4m 16s · 4.3 game h");
expect(formatSpan(SPAN, "both", formatClock)).toBe("04:16 · 4.3 game h");
expect(formatGameSpan(62.4)).toBe("62 game h");
expect(formatGameHoursSpan(5, "game")).toBe("5.0 game h");
expect(formatGameHoursSpan(5, "real")).toBe(
formatSpan((5 * MS_PER_HOUR) / content.config.timeCompression, "real"),
);
});
it("stills the map background with reduced motion", () => {
expect(mapMotionStyle(true).parallax).toBe(0);
expect(mapMotionStyle(true).backgroundZoomFollow).toBe(0);
expect(mapMotionStyle(false).parallax).toBe(mapStyle.parallax);
});
});
describe("display options in the app (Step 10K.3)", () => {
beforeEach(() => {
vi.useFakeTimers({ toFake: ["Date", "setInterval", "clearInterval"] });
vi.setSystemTime(NOW);
useClock.setState({ offsetMs: 0, synced: true, now: NOW });
});
afterEach(() => {
vi.useRealTimers();
act(() => usePreferences.getState().set(DEFAULT_PREFERENCES));
});
it("switches the HQ clock to 24-hour", async () => {
act(() => usePreferences.getState().set({ clock: "12h" }));
renderApp(fakeApi({ getPlayerState: () => samplePlayerState({ tutorial: null }) }), "/");
const game = realToGame(NOW, content.config);
expect(await screen.findByLabelText("Game clock")).toHaveTextContent(
formatGameTime(game, "12h"),
);
act(() => usePreferences.getState().set({ clock: "24h" }));
expect(screen.getByLabelText("Game clock")).toHaveTextContent(formatGameTime(game, "24h"));
});
it("shows contract expiry in both real and game time when asked", async () => {
const job: Contract = {
id: "c1",
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
goodId: "consumer-goods",
shipper: "Pacific Orbital Logistics",
priority: false,
deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 1234,
requiredSkill: null,
requiredLongHaulLevel: 0,
offeredAt: NOW,
expiresAt: NOW + SPAN,
firstContact: false,
};
renderApp(
fakeApi({
getPlayerState: () => samplePlayerState({ tutorial: null }),
getContractBoard: () => ({ contracts: [job], periodEndsAt: NOW + 600_000 }),
}),
"/contracts?location=earth",
);
const card = (await screen.findByText("1,234 cr")).closest("li")!;
expect(card).toHaveTextContent("expires in 4m 16s");
act(() => usePreferences.getState().set({ countdown: "both" }));
expect(card).toHaveTextContent("expires in 4m 16s · 4.3 game h");
});
});