1import { describe, expect, it } from "vite-plus/test";
2
3import {
4 areFontAdvancesMonospace,
5 clampCodeFontSize,
6 clampInterfaceFontSize,
7 clampPromptFontSize,
8 DEFAULT_CODE_FONT_STACK,
9 DEFAULT_SANS_FONT_STACK,
10 appearanceFontStack,
11 cssFontFamilies,
12 resolveDefaultFamilyLabel,
13 resolveTerminalFontPreference,
14 resolveTerminalFontSizePreference,
15} from "./appearanceFonts";
16
17describe("areFontAdvancesMonospace", () => {
18 it("accepts a fixed advance and rejects any proportional glyph", () => {
19 expect(areFontAdvancesMonospace([10, 10, 10, 10])).toBe(true);
20 expect(areFontAdvancesMonospace([10, 10, 7, 10])).toBe(false);
21 expect(areFontAdvancesMonospace([10, 10.02])).toBe(false);
22 });
23
24 it("fails open when canvas metrics are unavailable", () => {
25 expect(areFontAdvancesMonospace([])).toBe(true);
26 expect(areFontAdvancesMonospace([Number.NaN, Number.NaN])).toBe(true);
27 });
28});
29
30describe("cssFontFamilies", () => {
31 it("returns null for effectively empty input", () => {
32 expect(cssFontFamilies("")).toBeNull();
33 expect(cssFontFamilies(" ")).toBeNull();
34 expect(cssFontFamilies(" , , ")).toBeNull();
35 });
36
37 it("quotes names with spaces and keeps single idents bare", () => {
38 expect(cssFontFamilies("Fira Code")).toBe('"Fira Code"');
39 expect(cssFontFamilies("monospace")).toBe("monospace");
40 expect(cssFontFamilies('"Comic Mono"')).toBe('"Comic Mono"');
41 });
42
43 it("normalizes comma-separated lists and strips embedded quotes", () => {
44 expect(cssFontFamilies(" Fira Code , Menlo ")).toBe('"Fira Code", Menlo');
45 expect(cssFontFamilies('Bad"Name')).toBe('"BadName"');
46 });
47
48 it("quotes names that are not single CSS idents", () => {
49 expect(cssFontFamilies("3270 Nerd Font")).toBe('"3270 Nerd Font"');
50 expect(cssFontFamilies("M+ 1m")).toBe('"M+ 1m"');
51 });
52});
53
54describe("resolveDefaultFamilyLabel", () => {
55 it("skips generic keywords and returns null for a stack of only generics", () => {
56 expect(resolveDefaultFamilyLabel("system-ui, sans-serif")).toBeNull();
57 expect(resolveDefaultFamilyLabel("ui-monospace, monospace")).toBeNull();
58 });
59});
60
61describe("appearanceFontStack", () => {
62 it("prepends the custom family to the default stack", () => {
63 expect(appearanceFontStack("Fira Code", DEFAULT_CODE_FONT_STACK)).toBe(
64 `"Fira Code", ${DEFAULT_CODE_FONT_STACK}`,
65 );
66 });
67
68 it("falls back to the default stack when unset", () => {
69 expect(appearanceFontStack("", DEFAULT_SANS_FONT_STACK)).toBe(DEFAULT_SANS_FONT_STACK);
70 });
71});
72
73describe("resolveTerminalFontPreference", () => {
74 it("inherits the code font in simple mode", () => {
75 expect(
76 resolveTerminalFontPreference({ advanced: false, code: "Fira Code", terminal: "" }),
77 ).toBe("Fira Code");
78 expect(
79 resolveTerminalFontPreference({
80 advanced: false,
81 code: "Fira Code",
82 terminal: "Berkeley Mono",
83 }),
84 ).toBe("Fira Code");
85 });
86
87 it("keeps code and terminal fonts independent in advanced mode", () => {
88 expect(resolveTerminalFontPreference({ advanced: true, code: "Fira Code", terminal: "" })).toBe(
89 "",
90 );
91 expect(
92 resolveTerminalFontPreference({
93 advanced: true,
94 code: "Fira Code",
95 terminal: "Berkeley Mono",
96 }),
97 ).toBe("Berkeley Mono");
98 });
99});
100
101describe("resolveTerminalFontSizePreference", () => {
102 it("inherits the code font size in simple mode", () => {
103 expect(resolveTerminalFontSizePreference({ advanced: false, code: 15, terminal: 12 })).toBe(15);
104 });
105
106 it("keeps code and terminal font sizes independent in advanced mode", () => {
107 expect(resolveTerminalFontSizePreference({ advanced: true, code: 15, terminal: 12 })).toBe(12);
108 });
109});
110
111describe("font size clamping", () => {
112 it("keeps sizes inside the ranges the UI can absorb", () => {
113 expect(clampInterfaceFontSize(16)).toBe(16);
114 expect(clampInterfaceFontSize(2)).toBe(12);
115 expect(clampInterfaceFontSize(96)).toBe(20);
116 expect(clampPromptFontSize(40)).toBe(20);
117 expect(clampCodeFontSize(1)).toBe(10);
118 });
119
120 it("rounds fractional values and falls back for unusable input", () => {
121 expect(clampCodeFontSize(13.4)).toBe(13);
122 expect(clampInterfaceFontSize(Number.NaN)).toBe(16);
123 expect(clampPromptFontSize(Number.POSITIVE_INFINITY)).toBe(14);
124 });
125});