Files
Triple-C/app/src/hooks/useKeyboardShortcuts.test.tsx
T

89 lines
2.8 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { renderHook } from "@testing-library/react";
import { useKeyboardShortcuts } from "./useKeyboardShortcuts";
import { useAppState, homeTabKey, terminalTabKey } from "../store/appState";
vi.mock("./useTerminal", () => ({
useTerminal: () => ({ open: vi.fn(), close: vi.fn() }),
}));
const HOME = homeTabKey("p1");
const S1 = terminalTabKey("s1");
const S2 = terminalTabKey("s2");
const order = () => useAppState.getState().tabOrder;
/** Press a chord, from whatever is focused. */
function press(key: string, { shift = false } = {}) {
document.dispatchEvent(
new KeyboardEvent("keydown", { key, ctrlKey: true, shiftKey: shift, bubbles: true }),
);
}
/** Focus a real element of the given kind, inside `parent` if given. */
function focus(tag: "input" | "textarea", parentClass?: string): HTMLElement {
const el = document.createElement(tag);
if (parentClass) {
const parent = document.createElement("div");
parent.className = parentClass;
parent.appendChild(el);
document.body.appendChild(parent);
} else {
document.body.appendChild(el);
}
el.focus();
return el;
}
beforeEach(() => {
useAppState.setState({ tabOrder: [HOME, S1, S2], activeTabKey: S1, activeSessionId: "s1" });
});
afterEach(() => {
document.body.innerHTML = "";
});
describe("Ctrl+Shift+←/→", () => {
it("moves the active tab along the strip", () => {
renderHook(() => useKeyboardShortcuts());
press("ArrowLeft", { shift: true });
expect(order()).toEqual([S1, HOME, S2]);
press("ArrowRight", { shift: true });
expect(order()).toEqual([HOME, S1, S2]);
});
it("leaves word-wise selection alone in a text field", () => {
// Ctrl+Shift+←/→ already means "extend the selection by a word" in every
// input in the app — the rename field, Config fields, Settings fields.
// Taking it there would break selection *and* silently reorder tabs.
renderHook(() => useKeyboardShortcuts());
focus("input");
press("ArrowLeft", { shift: true });
expect(order()).toEqual([HOME, S1, S2]);
});
it("still moves tabs from the terminal, whose focus lives in a textarea", () => {
// xterm keeps a hidden textarea focused as its input-method shim. It is
// not a field anyone edits word-wise, and the terminal is where these
// shortcuts matter most, so it is not treated as one.
renderHook(() => useKeyboardShortcuts());
focus("textarea", "xterm xterm-helper-textarea-host");
press("ArrowLeft", { shift: true });
expect(order()).toEqual([S1, HOME, S2]);
});
it("does nothing without Shift — that chord is readline's word motion", () => {
renderHook(() => useKeyboardShortcuts());
press("ArrowLeft");
expect(order()).toEqual([HOME, S1, S2]);
});
});