import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { SectionTitleResolver } from "./section-title"; import { Buffer } from "node:buffer"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { sampleResumeData } from "@reactive-resume/schema/resume/sample"; const rendererMock = vi.hoisted(() => ({ renderToBuffer: vi.fn(async () => Buffer.from("%PDF")), })); const createRendererUnsafeResumeData = (): ResumeData => { const data = structuredClone(sampleResumeData); data.customSections = [ { id: "custom-experience", type: "experience", title: "Experience", icon: "", columns: 1, hidden: false, keepTogether: false, startOnNewPage: false, items: [{ id: "summary-shaped-item", hidden: false, content: "

Missing company

" }], } as never, ]; return data; }; const createLegacyRendererSafeResumeData = (): ResumeData => ({ ...structuredClone(sampleResumeData), customSections: [ { id: "custom-experience", type: "experience", title: "Experience", icon: "", columns: 1, hidden: false, keepTogether: false, startOnNewPage: false, items: [ { id: "experience-item", hidden: false, company: "Analytical Engines", position: "Programmer", location: "London", period: "1842–1843", description: "

Wrote the first algorithm.

", content: "

Compatible overlap

", }, ], }, ], }) as unknown as ResumeData; vi.mock("#react-pdf-renderer", async (importOriginal) => ({ ...(await importOriginal()), renderToBuffer: rendererMock.renderToBuffer, })); vi.mock("./document", () => ({ ResumeDocument: () => null, })); describe("createResumePdfFile", () => { beforeEach(() => { rendererMock.renderToBuffer.mockClear(); }); it("renders ResumeDocument with data, filename, template, and section title resolver", async () => { const resolveSectionTitle: SectionTitleResolver = (input) => input.defaultEnglishTitle ?? input.sectionId; const { createResumePdfFile } = await import("./server"); const data = createLegacyRendererSafeResumeData(); const file = await createResumePdfFile({ data, filename: "resume.pdf", template: "azurill", resolveSectionTitle, }); expect(file.name).toBe("resume.pdf"); expect(file.type).toBe("application/pdf"); expect(await file.text()).toBe("%PDF"); expect(rendererMock.renderToBuffer).toHaveBeenCalledTimes(1); expect(rendererMock.renderToBuffer).toHaveBeenCalledWith( expect.objectContaining({ props: expect.objectContaining({ template: "azurill", resolveSectionTitle, data: expect.objectContaining({ customSections: [ expect.objectContaining({ items: [ expect.objectContaining({ content: "

Compatible overlap

", roles: [], website: { url: "", label: "", inlineLink: false }, }), ], }), ], }), }), }), ); }); it("returns semantic diagnostics without rendering an invalid applied source", async () => { const data = structuredClone(sampleResumeData); const invalid = { languageVersion: 1, text: "@version 1; section { color: ; }" }; data.metadata.stylesheet = { mode: "semantic", source: invalid, applied: invalid }; const { createResumePdfFileResult } = await import("./server"); const result = await createResumePdfFileResult({ data, filename: "resume.pdf" }); expect(result).toMatchObject({ ok: false, diagnostics: [expect.objectContaining({ severity: "error" })], }); expect(rendererMock.renderToBuffer).not.toHaveBeenCalled(); }); it("rejects unchecked rendering instead of producing an unstyled PDF for semantic errors", async () => { const data = structuredClone(sampleResumeData); const invalid = { languageVersion: 1, text: "@version 1; section { color: ; }" }; data.metadata.stylesheet = { mode: "semantic", source: invalid, applied: invalid }; const { createResumePdfFile } = await import("./server"); await expect(createResumePdfFile({ data, filename: "resume.pdf" })).rejects.toMatchObject({ cause: [expect.objectContaining({ severity: "error" })], }); expect(rendererMock.renderToBuffer).not.toHaveBeenCalled(); }); it("rejects renderer-unsafe data at the server boundary before React PDF dispatch", async () => { const { createResumePdfFile } = await import("./server"); const error = await createResumePdfFile({ data: createRendererUnsafeResumeData(), filename: "resume.pdf", }).catch((caught: unknown) => caught); expect(error).toHaveProperty("issues.0.path", ["customSections", 0, "items", 0, "company"]); expect(rendererMock.renderToBuffer).not.toHaveBeenCalled(); }); });