70 lines
3.0 KiB
TypeScript
70 lines
3.0 KiB
TypeScript
import { createElement } from "react";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { useGameStore } from "../game/store";
|
|
import { getInputPreferences, publishInputPreferences, setCapturingInput } from "../input/keybindRuntime";
|
|
import { closeMapForKey, MapPanel } from "./MapPanel";
|
|
|
|
// Render the live client state rather than Zustand's immutable initial SSR snapshot.
|
|
vi.mock("../game/store", async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import("../game/store")>();
|
|
return { ...actual, useGameStore: Object.assign(
|
|
(select: (state: ReturnType<typeof actual.useGameStore.getState>) => unknown) => select(actual.useGameStore.getState()), actual.useGameStore,
|
|
) };
|
|
});
|
|
|
|
const initialPreferences = getInputPreferences();
|
|
const initialState = useGameStore.getState();
|
|
|
|
function key(code: string, extra = {}) {
|
|
return { code, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, repeat: false, defaultPrevented: false,
|
|
preventDefault: vi.fn(), stopPropagation: vi.fn(), ...extra };
|
|
}
|
|
|
|
afterEach(() => {
|
|
publishInputPreferences(initialPreferences);
|
|
setCapturingInput(false);
|
|
useGameStore.setState(initialState);
|
|
});
|
|
|
|
describe("map dialog controls", () => {
|
|
it("closes with M even when a map form control owns focus", () => {
|
|
publishInputPreferences({ ...initialPreferences, pc: { ...initialPreferences.pc, map: "KeyM" } });
|
|
const event = key("KeyM");
|
|
const close = vi.fn();
|
|
closeMapForKey(event, close);
|
|
expect(close).toHaveBeenCalledOnce();
|
|
expect(event.preventDefault).toHaveBeenCalledOnce();
|
|
expect(event.stopPropagation).toHaveBeenCalledOnce();
|
|
});
|
|
it("honors the rebound map shortcut", () => {
|
|
publishInputPreferences({ ...initialPreferences, pc: { ...initialPreferences.pc, map: "Ctrl+KeyG" } });
|
|
const close = vi.fn();
|
|
closeMapForKey(key("KeyM"), close);
|
|
closeMapForKey(key("KeyG", { ctrlKey: true }), close);
|
|
expect(close).toHaveBeenCalledOnce();
|
|
});
|
|
it("ignores repeats, consumed events, other keys and keybind capture", () => {
|
|
const close = vi.fn();
|
|
closeMapForKey(key("KeyM", { repeat: true }), close);
|
|
closeMapForKey(key("KeyM", { defaultPrevented: true }), close);
|
|
closeMapForKey(key("Space"), close);
|
|
setCapturingInput(true);
|
|
closeMapForKey(key("KeyM"), close);
|
|
expect(close).not.toHaveBeenCalled();
|
|
});
|
|
it("renders available floors and the optional patrol control", () => {
|
|
useGameStore.setState({ activeDungeonId: "deadmines", overlay: "map" });
|
|
const html = renderToStaticMarkup(createElement(MapPanel));
|
|
expect(html).toContain("Map floor");
|
|
expect(html).toContain("Auto — best match");
|
|
expect(html).toContain('value="2"');
|
|
expect(html).toContain("Patrol routes");
|
|
expect(html).toContain("Choose a floor when rooms overlap");
|
|
});
|
|
it("unmounts when the map is closed", () => {
|
|
useGameStore.setState({ overlay: null });
|
|
expect(renderToStaticMarkup(createElement(MapPanel))).toBe("");
|
|
});
|
|
});
|