import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { mkdtemp, mkdir, readFile, writeFile, rm, copyFile, readdir } from 'node:fs/promises'; import { join, resolve } from 'node:path'; import { tmpdir } from 'node:os'; const PROJECT_ROOT = resolve(import.meta.dirname, '..', '..'); const REAL_SEED_DIR = join(PROJECT_ROOT, 'public', 'content'); let workDir: string; type ContentModule = typeof import('../../src/lib/content'); let content: ContentModule; async function setupTmpRoot() { workDir = await mkdtemp(join(tmpdir(), 'portfolio-content-')); await mkdir(join(workDir, 'data', 'content'), { recursive: true }); const tmpSeedDir = join(workDir, 'public', 'content'); await mkdir(tmpSeedDir, { recursive: true }); for (const file of await readdir(REAL_SEED_DIR)) { await copyFile(join(REAL_SEED_DIR, file), join(tmpSeedDir, file)); } vi.spyOn(process, 'cwd').mockReturnValue(workDir); vi.resetModules(); content = await import('../../src/lib/content'); } async function cleanup() { vi.restoreAllMocks(); if (workDir) await rm(workDir, { recursive: true, force: true }); } beforeEach(setupTmpRoot); afterEach(cleanup); describe('loadContent', () => { it('copie le seed depuis public/content quand data/content/.json est absent', async () => { const profile = await content.loadContent('profile'); expect(profile.name).toBeTruthy(); const dataFile = await readFile(join(workDir, 'data', 'content', 'profile.json'), 'utf-8'); expect(JSON.parse(dataFile).name).toBe(profile.name); }); it('lit data/content/.json quand il existe (pas le seed)', async () => { const seed = JSON.parse( await readFile(join(workDir, 'public', 'content', 'profile.json'), 'utf-8'), ); const customized = { ...seed, name: 'CustomFromData' }; await writeFile( join(workDir, 'data', 'content', 'profile.json'), JSON.stringify(customized), 'utf-8', ); const profile = await content.loadContent('profile'); expect(profile.name).toBe('CustomFromData'); }); }); describe('saveContent', () => { it('écrit data/content/.json et retourne les données validées', async () => { const seed = JSON.parse( await readFile(join(workDir, 'public', 'content', 'profile.json'), 'utf-8'), ); const updated = { ...seed, name: 'NouveauNom' }; const saved = await content.saveContent('profile', updated); expect(saved.name).toBe('NouveauNom'); const onDisk = JSON.parse( await readFile(join(workDir, 'data', 'content', 'profile.json'), 'utf-8'), ); expect(onDisk.name).toBe('NouveauNom'); }); it('rejette un payload invalide (ZodError)', async () => { await expect(content.saveContent('profile', { bogus: true })).rejects.toThrow(); }); it('rejette null', async () => { await expect(content.saveContent('profile', null)).rejects.toThrow(); }); });