/** * #69 lot 3 — the mobile key toolbar. * * Guards the two properties that make the terminal drivable from a phone: * the chips emit the exact byte sequences a physical key would, and tapping one * never steals focus from xterm (which would collapse the virtual keyboard). */ import { describe, it, expect } from "vitest"; import { fireEvent, render, screen } from "@testing-library/react"; import type { TerminalInputApi } from "@/features/terminals"; import { TerminalKeyBar } from "./TerminalKeyBar"; function mockApi(): TerminalInputApi & { sent: string[]; focused: () => number } { const sent: string[] = []; let focusCount = 0; return { sent, focused: () => focusCount, send: (d) => void sent.push(d), focus: () => void focusCount++, }; } describe("TerminalKeyBar", () => { it("sends the byte sequence a physical key would emit", () => { const api = mockApi(); render(); fireEvent.click(screen.getByRole("button", { name: "Ctrl-C (interrompre)" })); fireEvent.click(screen.getByRole("button", { name: "Esc" })); fireEvent.click(screen.getByRole("button", { name: "Tab" })); fireEvent.click(screen.getByRole("button", { name: "Flèche haut" })); expect(api.sent).toEqual(["\x03", "\x1b", "\t", "\x1b[A"]); }); it("emits the CSI sequences for every arrow key", () => { const api = mockApi(); render(); for (const name of ["Flèche haut", "Flèche bas", "Flèche gauche", "Flèche droite"]) { fireEvent.click(screen.getByRole("button", { name })); } expect(api.sent).toEqual(["\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C"]); }); it("keeps the virtual keyboard up: cancels the tap's focus shift, refocuses xterm", () => { const api = mockApi(); render(); const ctrlC = screen.getByRole("button", { name: "Ctrl-C (interrompre)" }); // `fireEvent` returns false when the handler called preventDefault — that is // what stops the browser blurring xterm's textarea and closing the keyboard. expect(fireEvent.pointerDown(ctrlC)).toBe(false); fireEvent.click(ctrlC); expect(api.focused()).toBe(1); }); it("renders disabled until the terminal reports its input API", () => { render(); for (const button of screen.getAllByRole("button")) { expect((button as HTMLButtonElement).disabled).toBe(true); } }); it("exposes the keys as an accessible toolbar", () => { const api = mockApi(); render(); expect(screen.getByRole("toolbar", { name: "Touches du terminal" })).toBeTruthy(); }); });