import type { PublicStyleProjection } from "@reactive-resume/pdf/public-projection"; import { describe, expect, it, vi } from "vitest"; import { createPublicStyleProjection } from "@reactive-resume/pdf/public-projection"; import { defaultResumeData } from "@reactive-resume/schema/resume/default"; import { resumeDto } from "../../dto/resume"; import { getStyleProjection } from "./public-style-projection"; const source = { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n", }; const buildResume = () => { const data = structuredClone(defaultResumeData); data.metadata.stylesheet = { mode: "semantic", source, applied: source }; return { id: "resume-1", userId: "owner-1", name: "Private dashboard title", slug: "resume", data, isPublic: true, passwordHash: null, }; }; const input = { username: "jane", slug: "resume", requestHeaders: new Headers({ "x-forwarded-for": "203.0.113.7" }), trustedClient: "203.0.113.9", }; describe("getStyleProjection", () => { it("authorizes before consuming budget or looking up a cached projection", async () => { const consume = vi.fn(); const createProjection = vi.fn(); const cache = new Map([ ["cached", { renderDataHash: "cached" } as PublicStyleProjection], ]); await expect( getStyleProjection(input, { findResume: vi.fn().mockResolvedValue({ ...buildResume(), isPublic: false }), hasPasswordAccess: vi.fn(), rateLimiter: { consume }, createProjection, cache, }), ).rejects.toMatchObject({ code: "NOT_FOUND" }); expect(consume).not.toHaveBeenCalled(); expect(createProjection).not.toHaveBeenCalled(); }); it("preserves password authorization before consuming the shared render budget", async () => { const consume = vi.fn(); await expect( getStyleProjection(input, { findResume: vi.fn().mockResolvedValue({ ...buildResume(), passwordHash: "hash" }), hasPasswordAccess: vi.fn().mockReturnValue(false), rateLimiter: { consume }, createProjection: vi.fn(), cache: new Map(), }), ).rejects.toMatchObject({ code: "NEED_PASSWORD", status: 401 }); expect(consume).not.toHaveBeenCalled(); }); it("returns a source-free resolved projection and consumes one render token", async () => { const consume = vi.fn(); const result = await getStyleProjection(input, { findResume: vi.fn().mockResolvedValue(buildResume()), hasPasswordAccess: vi.fn(), rateLimiter: { consume }, createProjection: createPublicStyleProjection, cache: new Map(), }); expect(result).toEqual(expect.objectContaining({ formatVersion: 1, nodes: expect.any(Object) })); expect(JSON.stringify(result)).not.toContain("@version"); expect(consume).toHaveBeenCalledOnce(); expect(consume).toHaveBeenCalledWith({ trustedClient: "203.0.113.9", resumeId: "resume-1" }); }); it("normalizes stored data before public projection", async () => { const resume = buildResume(); resume.data.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 never, ]; const projection = { formatVersion: 1, languageVersion: 1, semanticTreeVersion: 1, registryFingerprint: "registry", adapterFingerprint: "adapter", renderDataHash: "render-hash", nodes: {}, } satisfies PublicStyleProjection; const createProjection = vi.fn().mockResolvedValue(projection); await getStyleProjection(input, { findResume: vi.fn().mockResolvedValue(resume), hasPasswordAccess: vi.fn(), rateLimiter: { consume: vi.fn() }, createProjection, cache: new Map(), }); expect(createProjection.mock.calls[0]?.[0].data.customSections[0]?.items[0]).toMatchObject({ content: "

Compatible overlap

", roles: [], website: { url: "", label: "", inlineLink: false }, }); }); it("caches only authorized projections by renderDataHash", async () => { const projection = { formatVersion: 1, languageVersion: 1, semanticTreeVersion: 1, registryFingerprint: "registry", adapterFingerprint: "adapter", renderDataHash: "render-hash", nodes: {}, } satisfies PublicStyleProjection; const createProjection = vi .fn() .mockResolvedValueOnce(projection) .mockResolvedValueOnce({ ...projection }); const cache = new Map(); const dependencies = { findResume: vi.fn().mockResolvedValue(buildResume()), hasPasswordAccess: vi.fn(), rateLimiter: { consume: vi.fn() }, createProjection, cache, }; const first = await getStyleProjection(input, dependencies); const second = await getStyleProjection(input, dependencies); expect(cache.get("render-hash")).toBe(first); expect(second).toBe(first); }); it("uses a strict source-free public projection DTO", async () => { const projection = await createPublicStyleProjection({ data: buildResume().data }); expect(resumeDto.getStyleProjection.output.safeParse(projection).success).toBe(true); expect( resumeDto.getStyleProjection.output.safeParse({ ...projection, source, }).success, ).toBe(false); expect( resumeDto.getStyleProjection.output.safeParse({ ...projection, nodes: { ...projection.nodes, private: { diagnostics: [{ message: "source location" }] }, }, }).success, ).toBe(false); }); });