mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-22 22:32:17 +10:00
- drop dotenv (Node 24 process.loadEnvFile) and dompurify (only used by dead code) - delete unused ui components/hooks (card, progress, checkbox, use-confirm, use-prompt) - delete dead sanitizeHtml/sanitizeCss, url-security helpers, patch-resume tool, schema/page, createResumePatches, patch-proposal preview builder, fonts fallback helpers - inline single-caller wrappers (flags service, auth getSession, pdf renderer passthrough) - deduplicate template color helpers into shared/color-helpers - unexport 50+ internal-only symbols, remove dead export-map entries - replace hand-rolled unique()/useIsMobile with Set spread and usehooks-ts
260 lines
9.1 KiB
TypeScript
260 lines
9.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
fontList,
|
|
getFont,
|
|
getFontDisplayName,
|
|
getFontSearchKeywords,
|
|
getPdfFallbackFontFamilies,
|
|
getWebFont,
|
|
getWebFontSource,
|
|
isStandardPdfFontFamily,
|
|
resolveLegacyFontAlias,
|
|
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("getPdfFallbackFontFamilies", () => {
|
|
it("puts the Korean Noto font first for the ko-KR locale (Hangul needs KR, not SC)", () => {
|
|
expect(getPdfFallbackFontFamilies("Times-Roman", { locale: "ko-KR" })).toEqual(["Noto Serif KR", "Noto Serif SC"]);
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { locale: "ko-KR" })).toEqual(["Noto Sans KR", "Noto Sans SC"]);
|
|
});
|
|
|
|
it("uses the Japanese Noto font for the ja-JP locale", () => {
|
|
expect(getPdfFallbackFontFamilies("Times-Roman", { locale: "ja-JP" })).toEqual(["Noto Serif JP", "Noto Serif SC"]);
|
|
});
|
|
|
|
it("uses the Traditional Chinese Noto font for the zh-TW locale", () => {
|
|
expect(getPdfFallbackFontFamilies("Times-Roman", { locale: "zh-TW" })).toEqual(["Noto Serif TC", "Noto Serif SC"]);
|
|
});
|
|
|
|
it("returns only the Simplified Chinese font for zh-CN (unchanged behavior)", () => {
|
|
expect(getPdfFallbackFontFamilies("Times-Roman", { locale: "zh-CN" })).toEqual(["Noto Serif SC"]);
|
|
});
|
|
|
|
it("uses the Arabic Noto font for the fa-IR (Persian) and ar-SA locales", () => {
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { locale: "fa-IR" })).toEqual(["Noto Sans Arabic"]);
|
|
expect(getPdfFallbackFontFamilies("Times-Roman", { locale: "ar-SA" })).toEqual(["Noto Naskh Arabic"]);
|
|
});
|
|
|
|
it("uses the Hebrew Noto font for he-IL, reusing the sans font for serif (no Noto Serif Hebrew)", () => {
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { locale: "he-IL" })).toEqual(["Noto Sans Hebrew"]);
|
|
expect(getPdfFallbackFontFamilies("Times-Roman", { locale: "he-IL" })).toEqual(["Noto Sans Hebrew"]);
|
|
});
|
|
|
|
it("uses the Thai Noto font for th-TH", () => {
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { locale: "th-TH" })).toEqual(["Noto Sans Thai"]);
|
|
});
|
|
|
|
it("does not append the Simplified Chinese safety net for non-CJK scripts", () => {
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { scripts: ["arabic"] })).toEqual(["Noto Sans Arabic"]);
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { scripts: ["thai"] })).not.toContain("Noto Sans SC");
|
|
});
|
|
|
|
it("orders the locale script first, then content scripts (mixed RTL + CJK resume)", () => {
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { locale: "ko-KR", scripts: ["arabic"] })).toEqual([
|
|
"Noto Sans KR",
|
|
"Noto Sans Arabic",
|
|
"Noto Sans SC",
|
|
]);
|
|
});
|
|
|
|
it("includes a Korean font before SC when Hangul is detected in Latin-locale content", () => {
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { scripts: ["hangul"] })).toEqual(["Noto Sans KR", "Noto Sans SC"]);
|
|
});
|
|
|
|
it("dedupes the locale script and content scripts", () => {
|
|
expect(getPdfFallbackFontFamilies("Helvetica", { locale: "ko-KR", scripts: ["hangul", "han-simplified"] })).toEqual(
|
|
["Noto Sans KR", "Noto Sans SC"],
|
|
);
|
|
});
|
|
|
|
it("excludes the family itself when it already is a fallback", () => {
|
|
expect(getPdfFallbackFontFamilies("Noto Sans KR", { locale: "ko-KR" })).toEqual(["Noto Sans SC"]);
|
|
});
|
|
|
|
it("only returns fonts that exist in the webfontlist", () => {
|
|
const families = getPdfFallbackFontFamilies("Helvetica", {
|
|
locale: "ko-KR",
|
|
scripts: ["hangul", "kana", "han-simplified", "arabic", "hebrew", "thai"],
|
|
});
|
|
for (const family of families) {
|
|
expect(getWebFont(family)).toBeDefined();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("legacy font compatibility (#2989)", () => {
|
|
it.each([
|
|
["Times New Roman", "Times-Roman"],
|
|
["Arial", "Arimo"],
|
|
["Garamond", "EB Garamond"],
|
|
["Calibri", "Carlito"],
|
|
["Cambria", "Tinos"],
|
|
])("aliases %s → %s", (legacy, target) => {
|
|
expect(resolveLegacyFontAlias(legacy)).toBe(target);
|
|
});
|
|
|
|
it("returns null for non-aliased families", () => {
|
|
expect(resolveLegacyFontAlias("Roboto")).toBeNull();
|
|
expect(resolveLegacyFontAlias("IBM Plex Serif")).toBeNull();
|
|
expect(resolveLegacyFontAlias("UnknownFont")).toBeNull();
|
|
});
|
|
|
|
it("every alias target is actually registered as a known font", () => {
|
|
const aliasTargets = ["Times-Roman", "Tinos", "Arimo", "EB Garamond", "Carlito"];
|
|
for (const target of aliasTargets) {
|
|
expect(getFont(target), `alias target ${target} must be a known font`).toBeDefined();
|
|
}
|
|
});
|
|
|
|
it("getFont resolves a legacy family to its alias target", () => {
|
|
const tnr = getFont("Times New Roman");
|
|
expect(tnr).toBeDefined();
|
|
expect(tnr?.family).toBe("Times-Roman");
|
|
});
|
|
|
|
it("getFont still returns the direct font when both legacy and direct lookup would succeed", () => {
|
|
// Sanity check: for non-aliased families the direct path is used.
|
|
expect(getFont("Roboto")?.family).toBe("Roboto");
|
|
});
|
|
|
|
it("getFontDisplayName preserves the legacy family name (UI is not rewritten)", () => {
|
|
// Users who picked "Times New Roman" should keep seeing that label
|
|
// in the typography sidebar — the alias is a render-time concern only.
|
|
expect(getFontDisplayName("Times New Roman")).toBe("Times New Roman");
|
|
});
|
|
});
|