import { beforeEach, describe, expect, it } from "vitest"; import { MANASTORM_BUBBLE_DEFAULT_RADIUS, createManastormClientOverlayState, manastormBubbleFillPercent, manastormBubbleSeverity, withManastormNextWaveCountdown, withManastormSafetyBubble, } from "./manastormClientOverlay"; import { useManastormStore } from "./manastormStore"; describe("Manastorm client overlay contract", () => { beforeEach(() => { useManastormStore.getState().resetRun(); }); it("shows only explicit non-negative countdown values", () => { const initial = createManastormClientOverlayState(); expect(withManastormNextWaveCountdown(initial, 4.9).nextWaveCountdownSeconds).toBe(4); expect(withManastormNextWaveCountdown(initial, 0).nextWaveCountdownSeconds).toBe(0); expect(withManastormNextWaveCountdown(initial, -1).nextWaveCountdownSeconds).toBeNull(); expect(withManastormNextWaveCountdown(initial, Number.NaN).nextWaveCountdownSeconds).toBeNull(); expect(withManastormNextWaveCountdown(initial, null).nextWaveCountdownSeconds).toBeNull(); }); it("normalizes safety-bubble distance and preserves decoded warning thresholds", () => { const initial = createManastormClientOverlayState(); const safe = withManastormSafetyBubble(initial, { active: true, radius: 9, distanceRemaining: 6, }); const warning = withManastormSafetyBubble(safe, { active: true, radius: 9, distanceRemaining: 3, }); const danger = withManastormSafetyBubble(warning, { active: true, radius: 9, distanceRemaining: 1.5, }); const clamped = withManastormSafetyBubble(danger, { active: true, radius: 8, distanceRemaining: 20, }); expect(safe.safetyBubble.severity).toBe("safe"); expect(warning.safetyBubble.severity).toBe("warning"); expect(danger.safetyBubble.severity).toBe("danger"); expect(clamped.safetyBubble.distanceRemaining).toBe(8); expect(manastormBubbleFillPercent(clamped.safetyBubble)).toBe(100); expect(manastormBubbleSeverity(3.01)).toBe("safe"); }); it("uses the decoded nine-yard default and hides cleanly", () => { const initial = createManastormClientOverlayState(); const active = withManastormSafetyBubble(initial, { active: true }); const hidden = withManastormSafetyBubble(active, { active: false }); expect(active.safetyBubble).toMatchObject({ active: true, radius: MANASTORM_BUBBLE_DEFAULT_RADIUS, distanceRemaining: MANASTORM_BUBBLE_DEFAULT_RADIUS, severity: "safe", }); expect(hidden).toEqual(initial); }); it("exposes data-driven store actions and clears transient client state on reset", () => { useManastormStore.getState().setNextWaveCountdown(7); useManastormStore.getState().setSafetyBubble({ active: true, radius: 9, distanceRemaining: 2, }); expect(useManastormStore.getState().clientOverlay).toMatchObject({ nextWaveCountdownSeconds: 7, safetyBubble: { active: true, severity: "warning", distanceRemaining: 2, }, }); useManastormStore.getState().resetRun(); expect(useManastormStore.getState().clientOverlay).toEqual( createManastormClientOverlayState(), ); }); });