Keep terminal wide-glyph fallback out of xterm's measured font path while preserving Nerd Font symbols in DOM rendering. - Split terminal font resolution into symbols-free xterm font families and scoped glyph fallback families. - Apply the glyph fallback CSS variable to both TerminalModal and SessionTerminal surfaces. - Update regression coverage and the documented mobile xterm wide-glyph recurrence analysis. Files changed: .changeset/fn-6659-terminal-render.md | 5 +++ .../xterm-symbols-nerd-font-unicode-range.md | 22 +++++++----- .../dashboard/app/__tests__/terminal-input.test.ts | 42 +++++++++++++--------- .../dashboard/app/components/SessionTerminal.css | 8 +++++ .../dashboard/app/components/SessionTerminal.tsx | 21 +++++++++-- .../dashboard/app/components/TerminalModal.css | 8 +++++ .../dashboard/app/components/TerminalModal.tsx | 13 ++++++- .../__tests__/SessionTerminal.mobile.test.tsx | 6 ++-- .../components/__tests__/SessionTerminal.test.tsx | 14 ++++---- .../components/__tests__/TerminalModal.test.tsx | 9 +++-- .../utils/__tests__/terminalPreferences.test.ts | 2 +- .../dashboard/app/utils/terminalPreferences.ts | 16 +++++---- 12 files changed, 117 insertions(+), 49 deletions(-) Fusion-Task-Id: FN-6659 Fusion-Task-Lineage: e29a709d-9d9d-4a90-9616-8f08c41b126d
118 lines
3.4 KiB
TypeScript
118 lines
3.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import {
|
|
DEFAULT_TERMINAL_PREFERENCES,
|
|
LEGACY_TERMINAL_FONT_SIZE_KEY,
|
|
TERMINAL_PREFERENCES_KEY,
|
|
XTERM_FONT_FAMILY,
|
|
readTerminalPreferences,
|
|
waitForTerminalFontMetrics,
|
|
writeTerminalPreferences,
|
|
} from "../terminalPreferences";
|
|
|
|
describe("terminalPreferences", () => {
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
});
|
|
|
|
it("returns defaults when storage is empty", () => {
|
|
expect(readTerminalPreferences()).toEqual(DEFAULT_TERMINAL_PREFERENCES);
|
|
});
|
|
|
|
it("falls back to defaults for corrupt JSON", () => {
|
|
localStorage.setItem(TERMINAL_PREFERENCES_KEY, "not-json");
|
|
|
|
expect(readTerminalPreferences()).toEqual(DEFAULT_TERMINAL_PREFERENCES);
|
|
});
|
|
|
|
it("clamps font size values", () => {
|
|
localStorage.setItem(
|
|
TERMINAL_PREFERENCES_KEY,
|
|
JSON.stringify({ ...DEFAULT_TERMINAL_PREFERENCES, fontSize: 99 }),
|
|
);
|
|
expect(readTerminalPreferences().fontSize).toBe(32);
|
|
|
|
localStorage.setItem(
|
|
TERMINAL_PREFERENCES_KEY,
|
|
JSON.stringify({ ...DEFAULT_TERMINAL_PREFERENCES, fontSize: 1 }),
|
|
);
|
|
expect(readTerminalPreferences().fontSize).toBe(8);
|
|
});
|
|
|
|
it("rejects unknown enum values to defaults", () => {
|
|
localStorage.setItem(
|
|
TERMINAL_PREFERENCES_KEY,
|
|
JSON.stringify({
|
|
fontFamily: "comic-sans",
|
|
fontSize: 16,
|
|
cursorStyle: "boxy",
|
|
cursorBlink: false,
|
|
renderer: "webgl-only",
|
|
}),
|
|
);
|
|
|
|
expect(readTerminalPreferences()).toEqual({
|
|
...DEFAULT_TERMINAL_PREFERENCES,
|
|
fontSize: 16,
|
|
cursorBlink: false,
|
|
});
|
|
});
|
|
|
|
it("migrates the legacy font-size key on first read", () => {
|
|
localStorage.setItem(LEGACY_TERMINAL_FONT_SIZE_KEY, "20");
|
|
|
|
expect(readTerminalPreferences()).toEqual({
|
|
...DEFAULT_TERMINAL_PREFERENCES,
|
|
fontSize: 20,
|
|
});
|
|
expect(JSON.parse(localStorage.getItem(TERMINAL_PREFERENCES_KEY) ?? "null")).toEqual({
|
|
...DEFAULT_TERMINAL_PREFERENCES,
|
|
fontSize: 20,
|
|
});
|
|
});
|
|
|
|
it("round-trips normalized writes", () => {
|
|
const written = writeTerminalPreferences({
|
|
fontFamily: "system-mono",
|
|
fontSize: 22,
|
|
cursorStyle: "underline",
|
|
cursorBlink: false,
|
|
renderer: "canvas",
|
|
});
|
|
|
|
expect(written).toEqual({
|
|
fontFamily: "system-mono",
|
|
fontSize: 22,
|
|
cursorStyle: "underline",
|
|
cursorBlink: false,
|
|
renderer: "canvas",
|
|
});
|
|
expect(readTerminalPreferences()).toEqual(written);
|
|
expect(localStorage.getItem(LEGACY_TERMINAL_FONT_SIZE_KEY)).toBe("22");
|
|
});
|
|
|
|
it("keeps terminal font metrics wait best-effort when iOS rejects the full stack shorthand", async () => {
|
|
let readyAwaited = false;
|
|
const load = vi.fn((font: string) => {
|
|
if (font.includes(",")) {
|
|
return Promise.reject(new DOMException("Invalid font shorthand"));
|
|
}
|
|
return Promise.resolve([]);
|
|
});
|
|
const ready = Promise.resolve().then(() => {
|
|
readyAwaited = true;
|
|
});
|
|
|
|
await expect(
|
|
waitForTerminalFontMetrics(12, XTERM_FONT_FAMILY, {
|
|
load,
|
|
ready,
|
|
}),
|
|
).resolves.toBe(true);
|
|
|
|
expect(load).toHaveBeenCalledWith(expect.stringContaining("MesloLGS NF"));
|
|
expect(load).toHaveBeenCalledWith("12px \"MesloLGS NF\"");
|
|
expect(load).not.toHaveBeenCalledWith("12px \"Fusion Terminal Nerd Font Symbols\"");
|
|
expect(readyAwaited).toBe(true);
|
|
});
|
|
});
|