mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-21 05:51:46 +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
168 lines
5.3 KiB
TypeScript
168 lines
5.3 KiB
TypeScript
// biome-ignore-all lint/style/noNonNullAssertion: These tests assert imported section lengths before inspecting the first item.
|
|
import { describe, expect, it } from "vitest";
|
|
import { parseJSONResume } from "./json-resume";
|
|
|
|
describe("parseJSONResume", () => {
|
|
it("throws when input is not valid JSON", () => {
|
|
expect(() => parseJSONResume("not json")).toThrow();
|
|
});
|
|
|
|
it("throws a serialized validation error for an obviously invalid shape", () => {
|
|
// Email field is validated; a non-email string should fail the loose schema.
|
|
const invalid = JSON.stringify({ basics: { email: "not-an-email" } });
|
|
expect(() => parseJSONResume(invalid)).toThrow();
|
|
});
|
|
|
|
it("imports an empty JSON Resume into a baseline ResumeData", () => {
|
|
const result = parseJSONResume("{}");
|
|
// Defaults preserve a name field even when unset by input.
|
|
expect(typeof result.basics.name).toBe("string");
|
|
});
|
|
|
|
it("imports basics fields into ResumeData", () => {
|
|
const json = JSON.stringify({
|
|
basics: {
|
|
name: "Jane Doe",
|
|
label: "Engineer",
|
|
email: "jane@example.com",
|
|
phone: "+1 555 123 4567",
|
|
url: "https://janedoe.dev",
|
|
summary: "Software engineer with 10+ years building products.",
|
|
location: { city: "Berlin", region: "BE", countryCode: "DE" },
|
|
},
|
|
});
|
|
|
|
const result = parseJSONResume(json);
|
|
expect(result.basics.name).toBe("Jane Doe");
|
|
expect(result.basics.headline).toBe("Engineer");
|
|
expect(result.basics.email).toBe("jane@example.com");
|
|
expect(result.basics.phone).toBe("+1 555 123 4567");
|
|
expect(result.basics.location).toBe("Berlin, BE, DE");
|
|
expect(result.summary.content).toContain("Software engineer");
|
|
expect(result.summary.hidden).toBe(false);
|
|
});
|
|
|
|
it("maps work entries into the experience section", () => {
|
|
const json = JSON.stringify({
|
|
work: [
|
|
{
|
|
name: "Acme Corp",
|
|
position: "Senior Engineer",
|
|
location: "Berlin",
|
|
startDate: "2020-01-15",
|
|
endDate: "2024",
|
|
url: "https://acme.example",
|
|
summary: "Built cool stuff.",
|
|
highlights: ["Shipped X", "Improved Y by 30%"],
|
|
},
|
|
// Entry with neither name nor position is filtered out.
|
|
{ startDate: "2010", endDate: "2015" },
|
|
],
|
|
});
|
|
|
|
const result = parseJSONResume(json);
|
|
expect(result.sections.experience.items).toHaveLength(1);
|
|
|
|
const item = result.sections.experience.items[0]!;
|
|
expect(item.company).toBe("Acme Corp");
|
|
expect(item.position).toBe("Senior Engineer");
|
|
expect(item.location).toBe("Berlin");
|
|
expect(item.period.length).toBeGreaterThan(0);
|
|
expect(item.description).toContain("Shipped X");
|
|
});
|
|
|
|
it("maps education entries (filters when institution is missing)", () => {
|
|
const json = JSON.stringify({
|
|
education: [
|
|
{
|
|
institution: "MIT",
|
|
studyType: "BS",
|
|
area: "Computer Science",
|
|
startDate: "2010",
|
|
endDate: "2014",
|
|
score: "3.9",
|
|
courses: ["Algorithms", "Distributed Systems"],
|
|
},
|
|
{ studyType: "BS" }, // no institution → filtered
|
|
],
|
|
});
|
|
|
|
const result = parseJSONResume(json);
|
|
expect(result.sections.education.items).toHaveLength(1);
|
|
|
|
const edu = result.sections.education.items[0]!;
|
|
expect(edu.school).toBe("MIT");
|
|
expect(edu.degree).toBe("BS in Computer Science");
|
|
expect(edu.description).toContain("Algorithms");
|
|
});
|
|
|
|
it("maps skills with level parsing", () => {
|
|
const json = JSON.stringify({
|
|
skills: [{ name: "TypeScript", level: "Master", keywords: ["node", "react"] }],
|
|
});
|
|
|
|
const result = parseJSONResume(json);
|
|
const skill = result.sections.skills.items[0]!;
|
|
|
|
expect(skill.name).toBe("TypeScript");
|
|
expect(skill.keywords).toEqual(["node", "react"]);
|
|
expect(skill.level).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("maps profiles from basics.profiles into the profiles section", () => {
|
|
const json = JSON.stringify({
|
|
basics: {
|
|
profiles: [
|
|
{ network: "GitHub", username: "janedoe", url: "https://github.com/janedoe" },
|
|
{ username: "no-network" }, // missing network → filtered
|
|
],
|
|
},
|
|
});
|
|
|
|
const result = parseJSONResume(json);
|
|
expect(result.sections.profiles.items).toHaveLength(1);
|
|
|
|
const profile = result.sections.profiles.items[0]!;
|
|
expect(profile.network).toBe("GitHub");
|
|
expect(profile.username).toBe("janedoe");
|
|
});
|
|
|
|
it("imports a picture URL from basics.image", () => {
|
|
const json = JSON.stringify({
|
|
basics: { image: "https://example.com/pic.jpg" },
|
|
});
|
|
|
|
const result = parseJSONResume(json);
|
|
expect(result.picture.url).toBe("https://example.com/pic.jpg");
|
|
expect(result.picture.hidden).toBe(false);
|
|
});
|
|
|
|
it("leaves the summary content empty when basics.summary is absent", () => {
|
|
const result = parseJSONResume(JSON.stringify({ basics: { name: "Jane" } }));
|
|
expect(result.summary.content).toBe("");
|
|
});
|
|
|
|
it("imports projects with description and period", () => {
|
|
const json = JSON.stringify({
|
|
projects: [
|
|
{
|
|
name: "Open source CLI",
|
|
description: "Built a CLI tool",
|
|
highlights: ["10k stars", "Used in production"],
|
|
startDate: "2022",
|
|
endDate: "2023",
|
|
url: "https://github.com/x/y",
|
|
},
|
|
{ description: "no name" }, // filtered
|
|
],
|
|
});
|
|
|
|
const result = parseJSONResume(json);
|
|
expect(result.sections.projects.items).toHaveLength(1);
|
|
|
|
const project = result.sections.projects.items[0]!;
|
|
expect(project.name).toBe("Open source CLI");
|
|
expect(project.description).toContain("10k stars");
|
|
});
|
|
});
|