mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-23 14:52:18 +10:00
Finding 5: Introduce V4Url + V4Section<T> type aliases in reactive-resume-v4-json.tsx; collapse
310-line V4ResumeData type (13x 5-field section header, 11x {label,href}) into typed aliases.
Inferred shape is structurally identical.
Finding 6: Remove 9 single-caller clamp/pxToPt wrappers; replace compile-time constants
(rotation=0, sidebarWidth=35, shadowWidth=0, gapX=4, gapY=6) with literals; inline dynamic
calls (clamp(x, 32, 512) etc.) at the two body/heading typography call sites.
Finding 7: Convert three stateless single-method importer classes to plain functions.
Extract shared rethrowAsImportError() to error.ts, replacing triplicated ZodError catch blocks.
Update web import dialog + all in-package test files to use function API.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
58 lines
2.2 KiB
TypeScript
58 lines
2.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
|
|
import { parseReactiveResumeJSON } from "./reactive-resume-json";
|
|
|
|
describe("parseReactiveResumeJSON", () => {
|
|
it("round-trips the default resume data", () => {
|
|
const result = parseReactiveResumeJSON(JSON.stringify(defaultResumeData));
|
|
expect(result.basics.name).toBe(defaultResumeData.basics.name);
|
|
});
|
|
|
|
it("throws a JSON-serialised validation error for an invalid object", () => {
|
|
// Missing required top-level fields.
|
|
expect(() => parseReactiveResumeJSON(JSON.stringify({ foo: "bar" }))).toThrow();
|
|
});
|
|
|
|
it("throws when the input is not valid JSON", () => {
|
|
expect(() => parseReactiveResumeJSON("not-json")).toThrow();
|
|
});
|
|
|
|
it("creates a default layout page when the imported data has no pages", () => {
|
|
const data = structuredClone(defaultResumeData);
|
|
data.metadata.layout.pages = [];
|
|
|
|
const result = parseReactiveResumeJSON(JSON.stringify(data));
|
|
expect(result.metadata.layout.pages.length).toBe(1);
|
|
expect(result.metadata.layout.pages[0]?.main.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("recovers missing built-in sections by appending them to the first page", () => {
|
|
const data = structuredClone(defaultResumeData);
|
|
data.metadata.layout.pages = [
|
|
{
|
|
fullWidth: false,
|
|
main: ["experience"],
|
|
sidebar: ["skills"],
|
|
},
|
|
];
|
|
|
|
const result = parseReactiveResumeJSON(JSON.stringify(data));
|
|
const firstPage = result.metadata.layout.pages[0];
|
|
expect(firstPage).toBeDefined();
|
|
const allIds = new Set([...(firstPage?.main ?? []), ...(firstPage?.sidebar ?? [])]);
|
|
|
|
// Every built-in section (except cover-letter) ends up somewhere on page 1.
|
|
for (const expected of ["education", "projects", "languages", "awards"]) {
|
|
expect(allIds.has(expected), expected).toBe(true);
|
|
}
|
|
// The originally-placed sections remain where the user put them.
|
|
expect(firstPage?.sidebar).toContain("skills");
|
|
expect(firstPage?.main[0]).toBe("experience");
|
|
});
|
|
|
|
it("does not modify the layout when every built-in section is already placed", () => {
|
|
const result = parseReactiveResumeJSON(JSON.stringify(defaultResumeData));
|
|
expect(result.metadata.layout.pages.length).toBe(defaultResumeData.metadata.layout.pages.length);
|
|
});
|
|
});
|