Deletes the vanilla shell and mounts App.tsx on #root. main.ts and the 23 views it drove are gone; App.tsx composes the ported components — sidebar, multi-view, command bar, spawn modal, help and restart overlays, daemon link, drawer — around the catalog and layout stores. The pure parts of four deleted modules moved next to the components that still use them: the spawn-form model and spawnSimilar into components/spawn, the transcript's markdown/format helpers and the diff into components/structured, the help overlay's grouping into components/dialogs. Document-level event names now live in uiEvents.ts. Deduplicated two pairs the migration left side by side: the sidebar uses dialogs/KillDialog and common/ContextMenu. It also listens for the command bar's kill/rename events, which nothing had picked up since catalog.ts went away. styles.css stays as the token and base layer, with `#app` renamed to `#root` and the pane-body rules re-keyed off the classes the React panes actually carry. Closes #253
83 lines
2.9 KiB
TypeScript
83 lines
2.9 KiB
TypeScript
// @vitest-environment happy-dom
|
|
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
|
|
import { keyCaps } from "../../commands.js";
|
|
import { groupedCommands } from "./model.js";
|
|
import { HelpOverlay } from "./HelpOverlay.js";
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
function press(key: string, init: KeyboardEventInit = {}): void {
|
|
fireEvent.keyDown(window, { key, ...init });
|
|
}
|
|
|
|
describe("HelpOverlay", () => {
|
|
it("opens on ? and closes on a second ?", () => {
|
|
render(<HelpOverlay />);
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
press("?", { shiftKey: true });
|
|
expect(screen.queryByRole("dialog")).not.toBeNull();
|
|
press("?", { shiftKey: true });
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
});
|
|
|
|
it("ignores ? while typing and when a non-shift modifier is held", () => {
|
|
render(<HelpOverlay />);
|
|
const input = document.createElement("input");
|
|
document.body.appendChild(input);
|
|
fireEvent.keyDown(input, { key: "?", shiftKey: true });
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
|
|
press("?", { ctrlKey: true });
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
input.remove();
|
|
});
|
|
|
|
it("closes on Escape, on the close button, and on a click outside the panel", () => {
|
|
render(<HelpOverlay />);
|
|
|
|
press("?", { shiftKey: true });
|
|
press("Escape");
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
|
|
press("?", { shiftKey: true });
|
|
fireEvent.click(screen.getByRole("button", { name: "Close" }));
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
|
|
press("?", { shiftKey: true });
|
|
fireEvent.click(screen.getByRole("dialog"));
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
});
|
|
|
|
it("stays open for a click inside the panel", () => {
|
|
render(<HelpOverlay />);
|
|
press("?", { shiftKey: true });
|
|
fireEvent.click(document.querySelector(".help-panel") as HTMLElement);
|
|
expect(screen.queryByRole("dialog")).not.toBeNull();
|
|
});
|
|
|
|
it("renders exactly the commands the registry has bound, grouped", () => {
|
|
render(<HelpOverlay />);
|
|
press("?", { shiftKey: true });
|
|
|
|
const groups = groupedCommands();
|
|
expect([...document.querySelectorAll(".help-group-title")].map((h) => h.textContent)).toEqual(
|
|
groups.map((g) => g.title),
|
|
);
|
|
expect(
|
|
[...document.querySelectorAll<HTMLElement>(".help-row")].map((r) => r.dataset.commandId),
|
|
).toEqual(groups.flatMap((g) => g.items.map((c) => c.id)));
|
|
expect([...document.querySelectorAll(".help-desc")].map((d) => d.textContent)).toEqual(
|
|
groups.flatMap((g) => g.items.map((c) => c.label)),
|
|
);
|
|
expect(
|
|
[...document.querySelectorAll(".help-row")].map((r) =>
|
|
[...r.querySelectorAll("kbd")].map((k) => k.textContent).join(" "),
|
|
),
|
|
).toEqual(groups.flatMap((g) => g.items.map((c) => keyCaps(c.keys[0]).join(" "))));
|
|
});
|
|
});
|