import { applyCvTheme, getCvPageCount, getCvPageMetrics, getCvPreviewFitZoom, getVisibleCvThemes, moveItem, normalizeCvLanguage, wrapSelection } from "./cvBuilder"; describe("moveItem", () => { test("moves an item forward", () => { expect(moveItem(["a", "b", "c"], 0, 2)).toEqual(["b", "c", "a"]); }); test("moves an item backward", () => { expect(moveItem(["a", "b", "c"], 2, 0)).toEqual(["c", "a", "b"]); }); test("no-op for equal or out-of-range indices", () => { const a = ["a", "b"]; expect(moveItem(a, 1, 1)).toBe(a); expect(moveItem(a, 5, 0)).toBe(a); expect(moveItem(a, 0, -1)).toBe(a); }); test("does not mutate the input", () => { const a = ["a", "b", "c"]; moveItem(a, 0, 2); expect(a).toEqual(["a", "b", "c"]); }); }); describe("wrapSelection", () => { test("wraps a selection and keeps the selection over the inner text", () => { const r = wrapSelection("hello world", 6, 11, "**", "**"); expect(r.text).toBe("hello **world**"); expect(r.text.slice(r.selStart, r.selEnd)).toBe("world"); }); test("inserts a placeholder when nothing is selected", () => { const r = wrapSelection("", 0, 0, "**", "**", "bold text"); expect(r.text).toBe("**bold text**"); expect(r.text.slice(r.selStart, r.selEnd)).toBe("bold text"); }); test("wraps a link with a url suffix", () => { const r = wrapSelection("see docs", 4, 8, "[", "](https://)"); expect(r.text).toBe("see [docs](https://)"); expect(r.text.slice(r.selStart, r.selEnd)).toBe("docs"); }); }); describe("CV page measurement", () => { test("uses the selected physical page size", () => { expect(getCvPageMetrics("a4")).toMatchObject({ widthMm: 210, heightMm: 297 }); expect(getCvPageMetrics("letter")).toMatchObject({ widthMm: 215.9, heightMm: 279.4 }); }); test("rounds layout pixels without hiding partial pages", () => { const { heightPx } = getCvPageMetrics("a4"); expect(getCvPageCount(Math.ceil(heightPx), heightPx)).toBe(1); expect(getCvPageCount(heightPx + 20, heightPx)).toBe(2); expect(getCvPageCount(heightPx * 2 + 20, heightPx)).toBe(3); }); }); describe("CV language compatibility", () => { test("maps legacy Norwegian values to the supported Bokmål locale", () => { expect(normalizeCvLanguage("no")).toBe("nb-NO"); expect(normalizeCvLanguage("nb")).toBe("nb-NO"); expect(normalizeCvLanguage("nb-NO")).toBe("nb-NO"); expect(normalizeCvLanguage("en")).toBe("en"); }); test("fits the physical page to the available preview width", () => { expect(getCvPreviewFitZoom(500, 800)).toBeCloseTo(0.595); expect(getCvPreviewFitZoom(1200, 800)).toBe(1); expect(getCvPreviewFitZoom(120, 800, 24, 0.2)).toBe(0.2); }); }); describe("CV template selection", () => { test("restores the selected template visual defaults without discarding user content", () => { const settings = { themeId: "minimal", layout: "single" as const, headerStyle: "plain" as const, headingStyle: "plain" as const, sidebarWidthMm: 70, sidebarSections: ["skills"], accentColor: "#123456", headingFont: "Georgia, 'Times New Roman', serif", pageMarginMm: 9, skillsStyle: "text" as const, showPhoto: false, showPageNumbers: false, showIcons: true, sections: [{ key: "experience", title: "Career" }], overrides: {}, customSections: [], }; expect(applyCvTheme(settings, "technical")).toMatchObject({ themeId: "technical", layout: null, headerStyle: null, headingStyle: null, sidebarWidthMm: null, sidebarSections: null, accentColor: null, headingFont: null, pageMarginMm: null, skillsStyle: null, sections: [{ key: "experience", title: "Career" }], }); }); test("shows ATS templates first and keeps an active non-ATS template visible", () => { const themes = [ { id: "creative", atsFriendly: false }, { id: "classic", atsFriendly: true }, { id: "minimal", atsFriendly: true }, ] as never[]; expect(getVisibleCvThemes(themes, true, "creative").map((theme) => theme.id)).toEqual(["classic", "minimal", "creative"]); expect(getVisibleCvThemes(themes, true).map((theme) => theme.id)).toEqual(["classic", "minimal"]); }); });