import { describe, expect, it } from "vitest"; import { getFirstIncompleteWizardStep, getPortfolioWizardProgress, isPortfolioAssetReady, isPortfolioSectionReady, } from "../lib/portfolio-form-progress"; import { assetInputSchema, categoryInputSchema, projectInputSchema, sectionInputSchema, } from "../lib/portfolio-validation"; describe("portfolio validation", () => { it("accepts a valid category payload", () => { expect( categoryInputSchema.parse({ slug: "branding", nameAr: "الهوية", nameEn: "Branding", nameDe: "Branding", descriptionAr: "وصف", descriptionEn: "Description", descriptionDe: "Beschreibung", sortOrder: 1, isActive: true, }).slug, ).toBe("branding"); }); it("rejects invalid project slugs", () => { expect(() => projectInputSchema.parse({ categoryId: "cat_1", slug: "Invalid Slug", viewMode: "GRID", titleAr: "عنوان", titleEn: "Title", titleDe: "Titel", summaryAr: "ملخص", summaryEn: "Summary", summaryDe: "Zusammenfassung", clientName: "Client", projectYear: 2025, serviceLabelAr: "خدمة", serviceLabelEn: "Service", serviceLabelDe: "Service", previewUrl: "https://example.com", currentCoverImagePath: "", coverMedia: { mode: "external", assetId: "", url: "https://example.com/cover.jpg", label: "Cover", kind: "IMAGE", }, sortOrder: 1, isFeatured: false, isPublished: true, sections: [], assets: [], }), ).toThrow(/slug/i); }); it("accepts valid section and asset payloads", () => { expect( sectionInputSchema.parse({ type: "RICH_TEXT", titleAr: "العنوان", titleEn: "Title", titleDe: "Titel", bodyAr: "النص", bodyEn: "Body", bodyDe: "Text", imagePath: "/uploads/media/covers/example.svg", media: { mode: "library", assetId: "asset_1", url: "", label: "Section Image", kind: "IMAGE", }, linkUrl: "https://example.com", sortOrder: 0, }).type, ).toBe("RICH_TEXT"); expect( sectionInputSchema.parse({ type: "GALLERY", titleAr: "معرض", titleEn: "Single Image", titleDe: "Einzelbild", bodyAr: "", bodyEn: "", bodyDe: "", imagePath: "/uploads/media/sections/example.svg", media: { mode: "library", assetId: "asset_2", url: "", label: "Single Image", kind: "IMAGE", }, linkUrl: "", sortOrder: 1, }).type, ).toBe("GALLERY"); expect( assetInputSchema.parse({ kind: "IMAGE", filePath: "/uploads/media/assets/example.svg", fileFieldName: "", media: { mode: "external", assetId: "", url: "https://example.com/example.svg", label: "Example", kind: "IMAGE", }, altAr: "بديل", altEn: "Alt", altDe: "Alt", sortOrder: 0, }).kind, ).toBe("IMAGE"); }); it("accepts valid project view modes", () => { expect( projectInputSchema.parse({ categoryId: "cat_1", slug: "case-study-entry", viewMode: "CASE_STUDY", titleAr: "عنوان", titleEn: "Title", titleDe: "Titel", summaryAr: "ملخص", summaryEn: "Summary", summaryDe: "Zusammenfassung", clientName: "Client", projectYear: 2025, serviceLabelAr: "خدمة", serviceLabelEn: "Service", serviceLabelDe: "Service", previewUrl: "https://example.com", currentCoverImagePath: "", coverMedia: { mode: "external", assetId: "", url: "https://example.com/cover.jpg", label: "Cover", kind: "IMAGE", }, sortOrder: 1, isFeatured: false, isPublished: true, sections: [], assets: [], }).viewMode, ).toBe("CASE_STUDY"); }); it("rejects invalid media payloads", () => { expect(() => assetInputSchema.parse({ kind: "IMAGE", filePath: "", fileFieldName: "", media: { mode: "external", assetId: "", url: "not-a-url", label: "Broken", kind: "IMAGE", }, altAr: "بديل", altEn: "Alt", altDe: "Alt", sortOrder: 0, }), ).toThrow(/url/i); }); it("rejects link sections without a link", () => { expect(() => sectionInputSchema.parse({ type: "LINK", titleAr: "رابط", titleEn: "Link", titleDe: "Link", bodyAr: "", bodyEn: "", bodyDe: "", imagePath: "", media: { mode: "upload", assetId: "", url: "", label: "", kind: "IMAGE", }, linkUrl: "", sortOrder: 0, }), ).toThrow(/link/i); }); it("calculates wizard progress and points to the first incomplete step", () => { const progress = getPortfolioWizardProgress({ basics: { categoryId: "cat_1", slug: "case-study-entry", clientName: "Client", projectYear: "2025", sortOrder: "1", viewMode: "GRID", }, content: { titleAr: "عنوان", titleEn: "Title", titleDe: "Titel", serviceLabelAr: "خدمة", serviceLabelEn: "Service", serviceLabelDe: "Service", summaryAr: "", summaryEn: "", summaryDe: "", }, sections: [ { type: "RICH_TEXT", titleAr: "العنوان", titleEn: "Title", titleDe: "Titel", bodyAr: "النص", bodyEn: "Body", bodyDe: "Text", linkUrl: "", mediaAssetId: "", }, ], assets: [ { mediaAssetId: "asset_1", altAr: "بديل", altEn: "Alt", altDe: "Alt", }, ], }); expect(progress.find((step) => step.key === "basics")?.complete).toBe(true); expect(progress.find((step) => step.key === "content")?.complete).toBe(false); expect(getFirstIncompleteWizardStep(progress)).toBe("content"); }); it("marks sections and assets ready only when required fields are present", () => { expect( isPortfolioSectionReady({ type: "LINK", titleAr: "رابط", titleEn: "Link", titleDe: "Link", bodyAr: "", bodyEn: "", bodyDe: "", linkUrl: "https://example.com", mediaAssetId: "", }), ).toBe(true); expect( isPortfolioAssetReady({ mediaAssetId: "asset_1", altAr: "بديل", altEn: "Alt", altDe: "Alt", }), ).toBe(true); expect( isPortfolioAssetReady({ mediaAssetId: "", altAr: "بديل", altEn: "Alt", altDe: "Alt", }), ).toBe(false); }); });