Rewrites the 27 DOM-behavior test files (dialogs, sidebar, spawn form, command bar, structured pane, catalog, multiview, theme, etc.) to use screen/within/fireEvent/waitFor instead of manual querySelector and dispatchEvent. Pure-logic test files (matcher, tree, activity, paths, reconnect, keys, webgl, paneTitle, commands, daemonLink, events, layout, persistence, previewSchedule, projectList, spawnSimilar, structuredDiff, toolIcon, fastForward, spawnForm) are untouched, and preview.test.ts needed no changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
128 lines
4.2 KiB
TypeScript
128 lines
4.2 KiB
TypeScript
// @vitest-environment happy-dom
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
import { fireEvent, screen } from "@testing-library/react";
|
|
|
|
import { defineCommands, keyCaps, publishCommands, publishedCommands } from "./commands.js";
|
|
import { closeHelp, groupedCommands, installHelpKeybind, isHelpOpen, openHelp } from "./help.js";
|
|
|
|
beforeEach(() => {
|
|
installHelpKeybind();
|
|
});
|
|
|
|
afterEach(() => {
|
|
closeHelp();
|
|
document.body.replaceChildren();
|
|
});
|
|
|
|
function press(key: string, init: KeyboardEventInit = {}): void {
|
|
fireEvent.keyDown(window, { key, ...init });
|
|
}
|
|
|
|
function overlay(): HTMLElement {
|
|
return screen.getByRole("dialog", { name: "Keyboard shortcuts" });
|
|
}
|
|
|
|
function rows(root: HTMLElement): string[] {
|
|
return [...root.querySelectorAll(".help-row")].map((r) =>
|
|
[...r.querySelectorAll("kbd")].map((k) => k.textContent).join(" "),
|
|
);
|
|
}
|
|
|
|
describe("help overlay", () => {
|
|
it("renders exactly the commands the registry has bound, grouped", () => {
|
|
openHelp();
|
|
const dialog = overlay();
|
|
const groups = groupedCommands();
|
|
expect([...dialog.querySelectorAll(".help-group-title")].map((h) => h.textContent)).toEqual(
|
|
groups.map((g) => g.title),
|
|
);
|
|
expect(rows(dialog)).toEqual(groups.flatMap((g) => g.items.map((c) => keyCaps(c.keys[0]).join(" "))));
|
|
expect([...dialog.querySelectorAll(".help-desc")].map((d) => d.textContent)).toEqual(
|
|
groups.flatMap((g) => g.items.map((c) => c.label)),
|
|
);
|
|
});
|
|
|
|
it("names each row by its command id, so a row can't drift from its command", () => {
|
|
openHelp();
|
|
const dialog = overlay();
|
|
expect(
|
|
[...dialog.querySelectorAll<HTMLElement>(".help-row")].map((r) => r.dataset.commandId),
|
|
).toEqual(publishedCommands().map((c) => c.id));
|
|
});
|
|
|
|
// #159: the leader comes from the daemon, so the overlay must render the
|
|
// configured chord — a hardcoded `Ctrl A` is the visible half of the bug.
|
|
it("renders the configured leader's chord, not a hardcoded Ctrl A", () => {
|
|
const bound = defineCommands(
|
|
{ "pane.literalCtrlK": () => {}, "pane.literalLeader": () => {} },
|
|
"ctrl-b",
|
|
);
|
|
publishCommands(bound);
|
|
try {
|
|
openHelp();
|
|
const dialog = overlay();
|
|
const keysOf = (id: string) =>
|
|
[...dialog.querySelectorAll(`.help-row[data-command-id="${id}"] kbd`)]
|
|
.map((k) => k.textContent)
|
|
.join(" ");
|
|
expect(keysOf("pane.literalCtrlK")).toBe("Ctrl B then Ctrl K");
|
|
expect(keysOf("pane.literalLeader")).toBe("Ctrl B then Ctrl B");
|
|
} finally {
|
|
// Leave the registry as the rest of the suite expects it.
|
|
publishCommands(
|
|
defineCommands({ "pane.literalCtrlK": () => {}, "pane.literalLeader": () => {} }),
|
|
);
|
|
}
|
|
});
|
|
|
|
it("opens on ? and closes on a second ?", () => {
|
|
press("?", { shiftKey: true });
|
|
expect(isHelpOpen()).toBe(true);
|
|
press("?", { shiftKey: true });
|
|
expect(isHelpOpen()).toBe(false);
|
|
});
|
|
|
|
it("closes on Escape, on the close button, and on a click outside the panel", () => {
|
|
openHelp();
|
|
press("Escape");
|
|
expect(isHelpOpen()).toBe(false);
|
|
|
|
openHelp();
|
|
fireEvent.click(screen.getByRole("button", { name: "Close" }));
|
|
expect(isHelpOpen()).toBe(false);
|
|
|
|
openHelp();
|
|
fireEvent.click(overlay());
|
|
expect(isHelpOpen()).toBe(false);
|
|
});
|
|
|
|
it("stays open for a click inside the panel", () => {
|
|
openHelp();
|
|
fireEvent.click(screen.getByRole("heading", { name: "Keyboard shortcuts", level: 2 }));
|
|
expect(isHelpOpen()).toBe(true);
|
|
});
|
|
|
|
it("opening twice leaves one overlay", () => {
|
|
openHelp();
|
|
openHelp();
|
|
expect(screen.getAllByRole("dialog")).toHaveLength(1);
|
|
});
|
|
|
|
it("ignores ? while typing and when a non-shift modifier is held", () => {
|
|
const input = document.createElement("input");
|
|
document.body.appendChild(input);
|
|
fireEvent.keyDown(input, { key: "?", shiftKey: true });
|
|
expect(isHelpOpen()).toBe(false);
|
|
|
|
press("?", { ctrlKey: true });
|
|
expect(isHelpOpen()).toBe(false);
|
|
});
|
|
|
|
it("installing the keybind twice still toggles once", () => {
|
|
installHelpKeybind();
|
|
press("?", { shiftKey: true });
|
|
expect(isHelpOpen()).toBe(true);
|
|
expect(screen.getAllByRole("dialog")).toHaveLength(1);
|
|
});
|
|
});
|