Files
Reactive-Resume/packages/fonts/src/index.test.ts
T
Amruth Pillai 6a01207b6b test: add unit and component tests across the monorepo
Adds ~1000 tests to bring the previously-untested packages and apps
under coverage:

- packages/utils — string, color, date, file, level, locale, sanitize,
  field, html, network-icons, rate-limit, url, url-security, monorepo,
  resume/patch, resume/docx/link-utils, style helpers (~97% on the
  testable utility files)
- packages/ui — 28 component test files plus the use-controlled-state,
  use-mobile, use-confirm, use-prompt hooks (95% statements)
- packages/pdf — shared template helpers (filtering, columns, picture,
  metrics, section-links, page-size, rich-text-html, section-title)
- packages/schema — resumeDataSchema, page, templates, default
- packages/fonts — expanded coverage on font helpers
- packages/ai — resume sanitize and extraction template
- packages/api — resume-access-policy
- apps/web — error-message, locale, theme, pwa, dialogs/store, and
  the resume/move-item / section-actions / make-section-item helpers

Adds jsdom polyfills (ResizeObserver, IntersectionObserver,
scrollIntoView, matchMedia) and an explicit React Testing Library
cleanup hook to vitest.setup.ts so portal- and overlay-based components
work without per-test setup.
2026-05-10 20:00:07 +02:00

260 lines
8.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
buildResumeFontFamily,
fontList,
getFallbackWebFontFamilies,
getFont,
getFontDisplayName,
getFontSearchKeywords,
getLoadableWebFontWeights,
getPdfCjkFallbackFontFamily,
getWebFont,
getWebFontSource,
isStandardPdfFontFamily,
standardFontList,
webFontList,
webFontMap,
} from "./index";
const sortFontFamilies = (families: string[]) => {
return [...families].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }));
};
describe("fontList", () => {
it("is ordered by font family name instead of localized display name", () => {
const families = fontList.map((font) => font.family);
expect(families).toEqual(sortFontFamilies(families));
});
it("contains standard PDF fonts", () => {
const families = fontList.map((font) => font.family);
expect(families).toContain("Helvetica");
expect(families).toContain("Courier");
expect(families).toContain("Times-Roman");
});
it("merges standardFontList and webFontList without duplicates", () => {
const expectedSize = standardFontList.length + webFontList.length;
expect(fontList).toHaveLength(expectedSize);
});
});
describe("standardFontList", () => {
it("contains only fonts not present in webFontMap", () => {
for (const font of standardFontList) {
expect(webFontMap.has(font.family)).toBe(false);
}
});
it("marks all standard fonts with type='standard'", () => {
for (const font of standardFontList) {
expect(font.type).toBe("standard");
}
});
});
describe("getFont", () => {
it("returns a font record by family", () => {
expect(getFont("Helvetica")).toBeDefined();
expect(getFont("Helvetica")?.family).toBe("Helvetica");
});
it("returns undefined for unknown families", () => {
expect(getFont("DefinitelyNotAFont")).toBeUndefined();
});
});
describe("getFontDisplayName", () => {
it("returns localized name when available", () => {
expect(getFontDisplayName("Noto Sans SC")).toBe("思源黑体");
expect(getFontDisplayName("PingFang SC")).toBe("苹方");
});
it("returns the family name when no localized name exists", () => {
expect(getFontDisplayName("Helvetica")).toBe("Helvetica");
expect(getFontDisplayName("Roboto")).toBe("Roboto");
});
});
describe("getFontSearchKeywords", () => {
it("returns family for non-CJK fonts", () => {
const keywords = getFontSearchKeywords("Helvetica");
expect(keywords).toContain("Helvetica");
expect(keywords).not.toContain("中文");
});
it("includes localized display name and 中文 marker for CJK fonts", () => {
const keywords = getFontSearchKeywords("Noto Sans SC");
expect(keywords).toContain("Noto Sans SC");
expect(keywords).toContain("思源黑体");
expect(keywords).toContain("中文");
});
it("deduplicates entries", () => {
const keywords = getFontSearchKeywords("Helvetica");
expect(new Set(keywords).size).toBe(keywords.length);
});
});
describe("isStandardPdfFontFamily", () => {
it("returns true for Helvetica, Courier, Times-Roman", () => {
expect(isStandardPdfFontFamily("Helvetica")).toBe(true);
expect(isStandardPdfFontFamily("Courier")).toBe(true);
expect(isStandardPdfFontFamily("Times-Roman")).toBe(true);
});
it("returns false for unknown families", () => {
expect(isStandardPdfFontFamily("Not-A-Font")).toBe(false);
});
it("returns false for non-standard web fonts", () => {
// Roboto is a web font, not a standard PDF font
const roboto = getWebFont("Roboto");
if (roboto) expect(isStandardPdfFontFamily("Roboto")).toBe(false);
});
});
describe("getWebFont", () => {
it("returns webFont record for known web font family", () => {
// Spot-check a font that should be in the list
const font = getWebFont("Roboto");
if (font) {
expect(font.type).toBe("web");
expect(font.family).toBe("Roboto");
}
});
it("returns undefined for non-web families", () => {
expect(getWebFont("Helvetica")).toBeUndefined();
expect(getWebFont("definitely-not-a-font")).toBeUndefined();
});
});
describe("getWebFontSource", () => {
it("uses the full normal font source when an italic variant is unavailable", () => {
expect(getWebFontSource("Noto Serif SC", "400", true)).toBe(getWebFontSource("Noto Serif SC", "400", false));
});
it("returns null for unknown fonts", () => {
expect(getWebFontSource("definitely-not-a-font", "400")).toBeNull();
});
it("defaults to weight 400 when not specified", () => {
const roboto = getWebFont("Roboto");
if (roboto) {
const source = getWebFontSource("Roboto");
expect(source).toBeTruthy();
}
});
});
describe("getPdfCjkFallbackFontFamily", () => {
it("returns Noto Sans SC for sans-serif/standard PDF fonts", () => {
expect(getPdfCjkFallbackFontFamily("Helvetica")).toBe("Noto Sans SC");
});
it("returns Noto Serif SC for serif fonts", () => {
expect(getPdfCjkFallbackFontFamily("Times-Roman")).toBe("Noto Serif SC");
});
it("returns null when family already is the CJK fallback", () => {
expect(getPdfCjkFallbackFontFamily("Noto Sans SC")).toBeNull();
});
});
describe("getFallbackWebFontFamilies", () => {
it("returns empty array for standard PDF fonts", () => {
expect(getFallbackWebFontFamilies("Helvetica")).toEqual([]);
expect(getFallbackWebFontFamilies("Courier")).toEqual([]);
expect(getFallbackWebFontFamilies("Times-Roman")).toEqual([]);
});
it("returns the primary CJK web font for non-standard, non-CJK families", () => {
// e.g. Roboto (sans-serif) → Noto Sans SC fallback
const roboto = getWebFont("Roboto");
if (roboto) {
expect(getFallbackWebFontFamilies("Roboto")).toEqual(["Noto Sans SC"]);
}
});
it("returns empty when family is already its primary CJK fallback", () => {
expect(getFallbackWebFontFamilies("Noto Sans SC")).toEqual([]);
});
});
describe("getLoadableWebFontWeights", () => {
it("returns empty array for unknown fonts", () => {
expect(getLoadableWebFontWeights("definitely-not-a-font", ["400"])).toEqual([]);
});
it("returns matching weights when preferred weights are available", () => {
const roboto = getWebFont("Roboto");
if (roboto) {
const result = getLoadableWebFontWeights("Roboto", ["400", "700"]);
for (const weight of result) {
expect(roboto.weights).toContain(weight);
}
}
});
it("falls back to default weights when no preferences match", () => {
const roboto = getWebFont("Roboto");
if (roboto) {
const result = getLoadableWebFontWeights("Roboto", ["999"]);
expect(result.length).toBeGreaterThan(0);
}
});
it("deduplicates preferred weights", () => {
const roboto = getWebFont("Roboto");
if (roboto?.weights.includes("400")) {
const result = getLoadableWebFontWeights("Roboto", ["400", "400"]);
expect(result).toEqual(["400"]);
}
});
});
describe("buildResumeFontFamily", () => {
it("wraps the primary family in single quotes", () => {
const result = buildResumeFontFamily("Roboto");
expect(result.startsWith("'Roboto',")).toBe(true);
});
it("includes generic sans-serif fallback by default", () => {
const result = buildResumeFontFamily("Roboto");
expect(result.endsWith("sans-serif")).toBe(true);
});
it("uses serif fallback for serif-category fonts", () => {
expect(buildResumeFontFamily("Times-Roman").endsWith("serif")).toBe(true);
});
it("includes system-ui and Segoe UI fallbacks", () => {
const result = buildResumeFontFamily("Roboto");
expect(result).toContain("system-ui");
expect(result).toContain("Segoe UI");
});
it("includes CJK fallbacks for sans-serif fonts", () => {
const result = buildResumeFontFamily("Roboto");
expect(result).toContain("Noto Sans SC");
});
it("includes CJK serif fallbacks for serif fonts", () => {
const result = buildResumeFontFamily("Times-Roman");
expect(result).toContain("Noto Serif SC");
});
it("does not duplicate primary family in fallback list", () => {
const result = buildResumeFontFamily("Noto Sans SC");
// Family should appear once
const occurrences = result.split("Noto Sans SC").length - 1;
expect(occurrences).toBe(1);
});
it("escapes single quotes in family names", () => {
const result = buildResumeFontFamily("Bob's Font");
expect(result).toContain("Bob\\'s Font");
});
});