// @vitest-environment jsdom // // The `page` scope as App binds it through `useGlobalKeymap`: the `g` chords jump to a module this // account can reach, stay out of an overlay's way, and leave the global keys (Shift+W, h) intact. // Its own file for the same reason as keymap.sequence.test.ts: a pending `g` is module state. import { useEffect } from "react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { act, cleanup, render } from "@testing-library/react"; import { closeKeyboardHelp, useGlobalKeymap, useKeyboardHelpOpen } from "./keymap"; import { pushLayer, removeLayer } from "./layerStack"; import type { Page } from "./urlState"; let clock = Date.UTC(2031, 0, 1); beforeEach(() => { vi.useFakeTimers({ toFake: ["Date"] }); clock += 3_600_000; vi.setSystemTime(clock); }); afterEach(() => { cleanup(); closeKeyboardHelp(); vi.useRealTimers(); }); const ALL: Page[] = ["home", "feed", "channels", "playlists", "plex", "files", "settings"]; function Host({ onNavigate, pages = ALL, onHelp = () => {}, }: { onNavigate: (p: Page) => void; pages?: Page[]; onHelp?: (open: boolean) => void; }) { useGlobalKeymap(true, onNavigate, pages); const help = useKeyboardHelpOpen(); useEffect(() => { onHelp(help); }, [help, onHelp]); return null; } const key = (init: KeyboardEventInit) => act(() => { window.dispatchEvent( new KeyboardEvent("keydown", { bubbles: true, cancelable: true, ...init }), ); }); describe("the g chords", () => { it("jump to the module named by the second key", () => { const nav = vi.fn(); render(); key({ key: "f" }); expect(nav).not.toHaveBeenCalled(); key({ key: "g" }); key({ key: "f" }); key({ key: "g" }); key({ key: "," }); expect(nav.mock.calls).toEqual([["feed"], ["settings"]]); }); // The retired Downloads page's chord still answers — where its content went. it("g d, the old Downloads chord, goes to Files", () => { const nav = vi.fn(); render(); key({ key: "g" }); key({ key: "d" }); expect(nav.mock.calls).toEqual([["files"]]); }); // `h` alone opens the sheet; the `h` of `g h` must not ALSO do that. it("take the h of g h away from the help sheet", () => { const nav = vi.fn(); let help = false; render( (help = v)} />); key({ key: "g" }); key({ key: "h" }); expect(nav).toHaveBeenCalledWith("home"); expect(help).toBe(false); }); it("refuse a module this account cannot reach", () => { const nav = vi.fn(); render(); key({ key: "g" }); key({ key: "x" }); expect(nav).not.toHaveBeenCalled(); }); it("stand aside for an overlay, while Shift+W still answers there", () => { const nav = vi.fn(); render(); const id = pushLayer(); key({ key: "g" }); key({ key: "f" }); expect(nav).not.toHaveBeenCalled(); key({ key: "w", shiftKey: true }); expect(nav).toHaveBeenCalledWith("home"); removeLayer(id); }); });