feat(FN-2612): merge fusion/fn-2612 (auto-resolved)
- test(FN-2612): complete Step 4 — cover shortcut helpers and panel interactions - feat(FN-2612): complete Step 3 — style shortcut panel controls - feat(FN-2612): complete Step 2 — add terminal shortcut panel UI - feat(FN-2612): complete Step 1 — add control sequence helpers
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
|
||||
import { TerminalModal, _resetInitialViewportHeight } from "../TerminalModal";
|
||||
import { TerminalModal, _resetInitialViewportHeight, ctrlChar, altChar } from "../TerminalModal";
|
||||
import * as useTerminalModule from "../../hooks/useTerminal";
|
||||
import * as useTerminalSessionsModule from "../../hooks/useTerminalSessions";
|
||||
import * as apiModule from "../../api";
|
||||
@@ -64,6 +64,18 @@ const mockCreateTerminalSession = vi.mocked(apiModule.createTerminalSession);
|
||||
const mockKillPtyTerminalSession = vi.mocked(apiModule.killPtyTerminalSession);
|
||||
const TERMINAL_FONT_SIZE_KEY = "kb-terminal-font-size";
|
||||
|
||||
describe("ctrlChar/altChar helpers", () => {
|
||||
it("maps Ctrl+C/D/Z/L and Alt sequences correctly", () => {
|
||||
expect(ctrlChar("c")).toBe("\x03");
|
||||
expect(ctrlChar("d")).toBe("\x04");
|
||||
expect(ctrlChar("z")).toBe("\x1a");
|
||||
expect(ctrlChar("l")).toBe("\x0c");
|
||||
|
||||
expect(altChar("c")).toBe("\x1bc");
|
||||
expect(altChar("[")).toBe("\x1b[");
|
||||
});
|
||||
});
|
||||
|
||||
// Default tab state
|
||||
const defaultTab = {
|
||||
id: "tab-1",
|
||||
@@ -519,6 +531,104 @@ describe("TerminalModal", () => {
|
||||
expect(mockTerminalInstance.open).toHaveBeenCalledWith(terminalDiv);
|
||||
});
|
||||
|
||||
describe("shortcut panel", () => {
|
||||
it("is hidden by default and toggles from header action", async () => {
|
||||
render(<TerminalModal isOpen={true} onClose={mockOnClose} />);
|
||||
|
||||
expect(screen.queryByTestId("terminal-shortcut-panel")).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByTestId("terminal-shortcut-toggle"));
|
||||
expect(screen.getByTestId("terminal-shortcut-panel")).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByTestId("terminal-shortcut-toggle"));
|
||||
expect(screen.queryByTestId("terminal-shortcut-panel")).toBeNull();
|
||||
});
|
||||
|
||||
it("supports sticky modifier toggle semantics", async () => {
|
||||
render(<TerminalModal isOpen={true} onClose={mockOnClose} />);
|
||||
|
||||
fireEvent.click(screen.getByTestId("terminal-shortcut-toggle"));
|
||||
|
||||
const ctrlBtn = screen.getByTestId("terminal-modifier-ctrl");
|
||||
const altBtn = screen.getByTestId("terminal-modifier-alt");
|
||||
|
||||
fireEvent.click(ctrlBtn);
|
||||
expect(ctrlBtn.getAttribute("aria-pressed")).toBe("true");
|
||||
|
||||
fireEvent.click(ctrlBtn);
|
||||
expect(ctrlBtn.getAttribute("aria-pressed")).toBe("false");
|
||||
|
||||
fireEvent.click(ctrlBtn);
|
||||
fireEvent.click(altBtn);
|
||||
expect(ctrlBtn.getAttribute("aria-pressed")).toBe("false");
|
||||
expect(altBtn.getAttribute("aria-pressed")).toBe("true");
|
||||
});
|
||||
|
||||
it("sends modified and literal keys, then clears sticky modifier", async () => {
|
||||
render(<TerminalModal isOpen={true} onClose={mockOnClose} />);
|
||||
|
||||
fireEvent.click(screen.getByTestId("terminal-shortcut-toggle"));
|
||||
|
||||
const ctrlBtn = screen.getByTestId("terminal-modifier-ctrl");
|
||||
const altBtn = screen.getByTestId("terminal-modifier-alt");
|
||||
|
||||
fireEvent.click(ctrlBtn);
|
||||
fireEvent.click(screen.getByRole("button", { name: "C" }));
|
||||
expect(mockSendInput).toHaveBeenCalledWith("\x03");
|
||||
expect(ctrlBtn.getAttribute("aria-pressed")).toBe("false");
|
||||
|
||||
fireEvent.click(altBtn);
|
||||
fireEvent.click(screen.getByRole("button", { name: "D" }));
|
||||
expect(mockSendInput).toHaveBeenCalledWith("\x1bd");
|
||||
expect(altBtn.getAttribute("aria-pressed")).toBe("false");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Z" }));
|
||||
expect(mockSendInput).toHaveBeenCalledWith("z");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "ESC" }));
|
||||
expect(mockSendInput).toHaveBeenCalledWith("\x1b");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Tab" }));
|
||||
expect(mockSendInput).toHaveBeenCalledWith("\t");
|
||||
});
|
||||
|
||||
it("renders shortcut controls on mobile viewport", async () => {
|
||||
const previousInnerWidth = window.innerWidth;
|
||||
const previousOntouchstart = window.ontouchstart;
|
||||
|
||||
Object.defineProperty(window, "innerWidth", {
|
||||
value: 375,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
Object.defineProperty(window, "ontouchstart", {
|
||||
value: null,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
try {
|
||||
render(<TerminalModal isOpen={true} onClose={mockOnClose} />);
|
||||
fireEvent.click(screen.getByTestId("terminal-shortcut-toggle"));
|
||||
|
||||
expect(screen.getByTestId("terminal-shortcut-panel")).toBeTruthy();
|
||||
expect(screen.getByTestId("terminal-modifier-ctrl")).toBeTruthy();
|
||||
expect(screen.getByTestId("terminal-modifier-alt")).toBeTruthy();
|
||||
} finally {
|
||||
Object.defineProperty(window, "innerWidth", {
|
||||
value: previousInnerWidth,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
Object.defineProperty(window, "ontouchstart", {
|
||||
value: previousOntouchstart,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("font size controls", () => {
|
||||
it("renders controls in the status bar with default font-size value", async () => {
|
||||
render(<TerminalModal isOpen={true} onClose={mockOnClose} />);
|
||||
|
||||
Reference in New Issue
Block a user