mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-25 07:42:20 +10:00
feat: add semantic CSS stylesheets (#3274)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor Agent
parent
4ac19f81b3
commit
d2ffbf9618
@@ -1,5 +1,6 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import type { PublicStyleProjection } from "@reactive-resume/pdf/public-projection";
|
||||
import type { ResumeData } from "@reactive-resume/schema/resume/data";
|
||||
import type { ReactNode } from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
@@ -11,24 +12,46 @@ import { sampleResumeData } from "@reactive-resume/schema/resume/sample";
|
||||
type PdfViewerProps = {
|
||||
className?: string;
|
||||
data: ResumeData;
|
||||
stylesheetMode?: "legacy" | "semantic";
|
||||
styleProjection?: PublicStyleProjection;
|
||||
refetchStyleProjection?: () => Promise<PublicStyleProjection | undefined>;
|
||||
publicResume?: { username: string; slug: string };
|
||||
};
|
||||
|
||||
const publicResumeMock = vi.hoisted(() => ({
|
||||
createResumePdfBlob: vi.fn(async () => new Blob(["%PDF"], { type: "application/pdf" })),
|
||||
downloadWithAnchor: vi.fn(),
|
||||
generateFilename: vi.fn((name: string, extension: string) => `${name}.${extension}`),
|
||||
onDownloadPDF: vi.fn(),
|
||||
PdfViewer: vi.fn<(_props: PdfViewerProps) => ReactNode>(() => null),
|
||||
projection: {
|
||||
formatVersion: 1,
|
||||
languageVersion: 1,
|
||||
semanticTreeVersion: 1,
|
||||
registryFingerprint: "1".repeat(64),
|
||||
adapterFingerprint: "2".repeat(64),
|
||||
renderDataHash: "3".repeat(64),
|
||||
nodes: { resume: {} },
|
||||
} as PublicStyleProjection,
|
||||
refetchProjection: vi.fn(),
|
||||
projectionResult: {
|
||||
data: undefined as PublicStyleProjection | undefined,
|
||||
isError: false,
|
||||
isPending: false,
|
||||
},
|
||||
useResumeExport: vi.fn(),
|
||||
resume: undefined as
|
||||
| undefined
|
||||
| {
|
||||
data: ResumeData;
|
||||
name: string;
|
||||
slug: string;
|
||||
stylesheetMode: "legacy" | "semantic";
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({
|
||||
useQuery: () => ({ data: publicResumeMock.resume }),
|
||||
useQuery: (options: { query: "resume" | "projection" }) =>
|
||||
options.query === "resume"
|
||||
? { data: publicResumeMock.resume }
|
||||
: { ...publicResumeMock.projectionResult, refetch: publicResumeMock.refetchProjection },
|
||||
}));
|
||||
|
||||
vi.mock("@tanstack/react-router", () => ({
|
||||
@@ -37,21 +60,21 @@ vi.mock("@tanstack/react-router", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@reactive-resume/utils/file", () => ({
|
||||
downloadWithAnchor: publicResumeMock.downloadWithAnchor,
|
||||
generateFilename: publicResumeMock.generateFilename,
|
||||
}));
|
||||
|
||||
vi.mock("./pdf-viewer", () => ({
|
||||
PdfViewer: publicResumeMock.PdfViewer,
|
||||
}));
|
||||
|
||||
vi.mock("@/libs/orpc/client", () => ({
|
||||
orpc: { resume: { getBySlug: { queryOptions: () => ({}) } } },
|
||||
orpc: {
|
||||
resume: {
|
||||
getBySlug: { queryOptions: () => ({ query: "resume" }) },
|
||||
getStyleProjection: { queryOptions: () => ({ query: "projection" }) },
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("@/features/resume/export/pdf-document", () => ({
|
||||
createResumePdfBlob: publicResumeMock.createResumePdfBlob,
|
||||
vi.mock("@/features/resume/export/use-resume-export", () => ({
|
||||
useResumeExport: publicResumeMock.useResumeExport,
|
||||
}));
|
||||
|
||||
const { PublicResumeRoute } = await import("./public-resume");
|
||||
@@ -65,8 +88,21 @@ beforeEach(() => {
|
||||
data: sampleResumeData,
|
||||
name: "Sample Resume",
|
||||
slug: "sample",
|
||||
stylesheetMode: "semantic",
|
||||
};
|
||||
publicResumeMock.projectionResult = {
|
||||
data: publicResumeMock.projection,
|
||||
isError: false,
|
||||
isPending: false,
|
||||
};
|
||||
publicResumeMock.PdfViewer.mockClear();
|
||||
publicResumeMock.refetchProjection.mockReset();
|
||||
publicResumeMock.refetchProjection.mockResolvedValue({ data: publicResumeMock.projection });
|
||||
publicResumeMock.useResumeExport.mockReset();
|
||||
publicResumeMock.useResumeExport.mockReturnValue({
|
||||
onDownloadPDF: publicResumeMock.onDownloadPDF,
|
||||
isExporting: false,
|
||||
});
|
||||
publicResumeMock.PdfViewer.mockImplementation(({ className }) => (
|
||||
<div className={className} data-testid="pdf-viewer" />
|
||||
));
|
||||
@@ -88,6 +124,62 @@ describe("PublicResumeRoute", () => {
|
||||
expect.objectContaining({ data: sampleResumeData }),
|
||||
undefined,
|
||||
);
|
||||
expect(publicResumeMock.useResumeExport).toHaveBeenCalledWith(publicResumeMock.resume, {
|
||||
publicResumePdf: expect.objectContaining({
|
||||
stylesheetMode: "semantic",
|
||||
styleProjection: publicResumeMock.projection,
|
||||
publicResume: { username: "amruth", slug: "sample" },
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("routes a missing semantic projection to the shared fallback seam", () => {
|
||||
publicResumeMock.projectionResult = { data: undefined, isError: true, isPending: false };
|
||||
|
||||
renderPublicResumeRoute();
|
||||
|
||||
expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
stylesheetMode: "semantic",
|
||||
styleProjection: undefined,
|
||||
refetchStyleProjection: expect.any(Function),
|
||||
publicResume: { username: "amruth", slug: "sample" },
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
expect(publicResumeMock.useResumeExport).toHaveBeenCalledWith(
|
||||
publicResumeMock.resume,
|
||||
expect.objectContaining({
|
||||
publicResumePdf: expect.objectContaining({
|
||||
stylesheetMode: "semantic",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps missing legacy projections on the local rendering path", () => {
|
||||
if (publicResumeMock.resume) publicResumeMock.resume.stylesheetMode = "legacy";
|
||||
publicResumeMock.projectionResult = { data: undefined, isError: false, isPending: false };
|
||||
|
||||
renderPublicResumeRoute();
|
||||
|
||||
expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ stylesheetMode: "legacy", styleProjection: undefined }),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it("loads the public projection and passes it to the shared viewer", () => {
|
||||
renderPublicResumeRoute();
|
||||
|
||||
expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
styleProjection: publicResumeMock.projection,
|
||||
refetchStyleProjection: expect.any(Function),
|
||||
publicResume: { username: "amruth", slug: "sample" },
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it("lets the public resume page grow to the full PDF length", () => {
|
||||
|
||||
Reference in New Issue
Block a user