import { createId } from "@paralleldrive/cuid2"; import { describe, expect, it } from "vitest"; import { idSchema, resumeDataSchema, skillSchema } from "./rxresume-schema"; describe("RxResume Schema Validation", () => { describe("idSchema (CUID2)", () => { it("should accept valid CUID2 IDs generated by the library", () => { // Generate real CUID2 IDs using the official library const validIds = [createId(), createId(), createId()]; validIds.forEach((id) => { const result = idSchema.safeParse(id); expect(result.success, `ID "${id}" should be valid`).toBe(true); }); }); it('should reject invalid IDs like "skill-0"', () => { const invalidIds = [ "skill-0", // contains hyphen "skill-1", // contains hyphen "skill-123", // contains hyphen "item_1", // contains underscore "ABC123", // uppercase letters "", // empty ]; invalidIds.forEach((id) => { const result = idSchema.safeParse(id); expect(result.success, `ID "${id}" should be invalid`).toBe(false); }); }); }); describe("skillSchema", () => { it("should accept valid skill with CUID2 ID", () => { const validSkill = { id: createId(), visible: true, name: "JavaScript", description: "", level: 3, keywords: ["ES6", "TypeScript"], }; const result = skillSchema.safeParse(validSkill); expect(result.success).toBe(true); }); it("should reject skill with invalid ID format", () => { const invalidSkill = { id: "skill-0", // Invalid CUID2 visible: true, name: "JavaScript", description: "", level: 3, keywords: ["ES6"], }; const result = skillSchema.safeParse(invalidSkill); expect(result.success).toBe(false); if (!result.success) { expect(result.error.issues[0].path).toContain("id"); expect(result.error.issues[0].message).toContain("cuid2"); } }); }); describe("resumeDataSchema", () => { it("should reject resume with invalid skill IDs", () => { const resumeWithInvalidIds = { basics: { name: "John Doe", headline: "Developer", email: "john@example.com", phone: "", location: "", url: { label: "", href: "" }, customFields: [], picture: { url: "", size: 64, aspectRatio: 1, borderRadius: 0, effects: { hidden: false, border: false, grayscale: false }, }, }, sections: { summary: { id: "summary", name: "Summary", columns: 1, separateLinks: true, visible: true, content: "", }, skills: { id: "skills", name: "Skills", columns: 1, separateLinks: true, visible: true, items: [ { id: "skill-0", // Invalid! visible: true, name: "JavaScript", description: "", level: 1, keywords: [], }, ], }, // Minimal required sections awards: { id: "awards", name: "Awards", columns: 1, separateLinks: true, visible: true, items: [], }, certifications: { id: "certifications", name: "Certifications", columns: 1, separateLinks: true, visible: true, items: [], }, education: { id: "education", name: "Education", columns: 1, separateLinks: true, visible: true, items: [], }, experience: { id: "experience", name: "Experience", columns: 1, separateLinks: true, visible: true, items: [], }, volunteer: { id: "volunteer", name: "Volunteer", columns: 1, separateLinks: true, visible: true, items: [], }, interests: { id: "interests", name: "Interests", columns: 1, separateLinks: true, visible: true, items: [], }, languages: { id: "languages", name: "Languages", columns: 1, separateLinks: true, visible: true, items: [], }, profiles: { id: "profiles", name: "Profiles", columns: 1, separateLinks: true, visible: true, items: [], }, projects: { id: "projects", name: "Projects", columns: 1, separateLinks: true, visible: true, items: [], }, publications: { id: "publications", name: "Publications", columns: 1, separateLinks: true, visible: true, items: [], }, references: { id: "references", name: "References", columns: 1, separateLinks: true, visible: true, items: [], }, custom: {}, }, metadata: { template: "rhyhorn", layout: [[["summary"], ["skills"]]], css: { value: "", visible: false }, page: { margin: 18, format: "a4", options: { breakLine: true, pageNumbers: true }, }, theme: { background: "#ffffff", text: "#000000", primary: "#dc2626" }, typography: { font: { family: "IBM Plex Serif", subset: "latin", variants: ["regular"], size: 14, }, lineHeight: 1.5, hideIcons: false, underlineLinks: true, }, notes: "", }, }; const result = resumeDataSchema.safeParse(resumeWithInvalidIds); expect(result.success).toBe(false); if (!result.success) { // Should have error about the skill ID const idError = result.error.issues.find( (issue) => issue.path.join(".").includes("skills.items") && issue.path.includes("id"), ); expect(idError).toBeDefined(); } }); }); });