mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-23 14:52:18 +10:00
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.
260 lines
8.0 KiB
TypeScript
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");
|
|
});
|
|
});
|