import { lstat, mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, describe, expect, it } from 'vitest'; import { assertPreparedAssetDirectoryIdentity, materializeEmptyAssetSet, } from '../../scripts/materialize-empty-asset-set.mjs'; const temporaryRoots = []; const createScratchRepository = async () => { const root = await mkdtemp(join(tmpdir(), 'portfolio-empty-assets-')); temporaryRoots.push(root); await mkdir(join(root, 'content/public'), { recursive: true }); await writeFile(join(root, 'content/public/asset-manifest.json'), '{"assets":[]}'); return root; }; afterEach(async () => { await Promise.all(temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); }); describe('empty asset materialization', () => { it('creates an empty prepared-asset directory in the supplied repository root', async () => { const root = await createScratchRepository(); await materializeEmptyAssetSet(root); expect((await lstat(join(root, 'inputs/prepared-assets'))).isDirectory()).toBe(true); }); it('rejects a symbolic-link prepared-asset directory', async () => { const root = await createScratchRepository(); const target = join(root, 'outside'); await mkdir(target); await mkdir(join(root, 'inputs'), { recursive: true }); await symlink(target, join(root, 'inputs/prepared-assets')); await expect(materializeEmptyAssetSet(root)).rejects.toThrow(/non-symlink directory/i); }); it('rejects unexpected prepared-asset members in its supplied repository root', async () => { const root = await createScratchRepository(); const preparedAssetsPath = join(root, 'inputs/prepared-assets'); await mkdir(preparedAssetsPath, { recursive: true }); await writeFile(join(preparedAssetsPath, 'unexpected.webp'), 'not an asset'); await expect(materializeEmptyAssetSet(root)).rejects.toThrow(/must be empty/i); }); it('rejects a prepared-asset directory replaced after its identity was captured', async () => { const root = await createScratchRepository(); const preparedAssetsPath = join(root, 'inputs/prepared-assets'); await mkdir(preparedAssetsPath, { recursive: true }); const original = await lstat(preparedAssetsPath); await rm(preparedAssetsPath, { recursive: true }); await mkdir(preparedAssetsPath); await expect(assertPreparedAssetDirectoryIdentity(preparedAssetsPath, original)) .rejects.toThrow(/identity changed/i); }); });