/** * Filesystem Test Utilities * * Provides functions for creating and managing temporary directories and files * for test isolation. */ import { cp, mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; /** * Create temporary directory for test * * Directory is created in system temp dir with unique name. * Caller is responsible for cleanup via removeTempDirectory(). * * @returns Path to temporary directory * * @example * ```typescript * const tempDir = await createTempDirectory(); * // Use tempDir... * await removeTempDirectory(tempDir); * ``` */ export async function createTempDirectory(): Promise { return await mkdtemp(join(tmpdir(), 'celilo-test-')); } /** * Remove temporary directory (with retry for locked files) * * Handles file locking issues by retrying once after a short delay. * Useful on Windows where files may be locked briefly. * * @param dir - Directory to remove * * @example * ```typescript * const tempDir = await createTempDirectory(); * // Use tempDir... * await removeTempDirectory(tempDir); * ``` */ export async function removeTempDirectory(dir: string): Promise { try { await rm(dir, { recursive: true, force: true }); } catch (_error) { // Retry once after 100ms (helps with file locking issues) await new Promise((resolve) => setTimeout(resolve, 100)); await rm(dir, { recursive: true, force: true }); } } /** * Copy test fixture to temporary directory * * Recursively copies source to destination. * Useful for setting up test data from fixtures. * * @param fixturePath - Source path (relative to cwd) * @param destPath - Destination path * * @example * ```typescript * const tempDir = await createTempDirectory(); * await copyFixture('./test-fixtures/modules/artifact-test', tempDir); * // tempDir now contains copy of artifact-test module * await removeTempDirectory(tempDir); * ``` */ export async function copyFixture(fixturePath: string, destPath: string): Promise { await cp(fixturePath, destPath, { recursive: true }); } /** * Create multiple temporary directories * * Useful for tests that need multiple isolated directories. * * @param count - Number of directories to create * @returns Array of directory paths * * @example * ```typescript * const [dir1, dir2] = await createMultipleTempDirectories(2); * // Use dir1 and dir2... * await removeMultipleTempDirectories([dir1, dir2]); * ``` */ export async function createMultipleTempDirectories(count: number): Promise { const directories: string[] = []; for (let i = 0; i < count; i++) { directories.push(await createTempDirectory()); } return directories; } /** * Remove multiple temporary directories * * @param directories - Array of directory paths to remove * * @example * ```typescript * const dirs = await createMultipleTempDirectories(3); * // Use dirs... * await removeMultipleTempDirectories(dirs); * ``` */ export async function removeMultipleTempDirectories(directories: string[]): Promise { for (const dir of directories) { await removeTempDirectory(dir); } } /** * Create temporary directory with cleanup function * * Returns both directory path and cleanup function. * Convenient pattern for use in test setup/teardown. * * @returns Object with directory path and cleanup function * * @example * ```typescript * const { path: tempDir, cleanup } = await createTempDirectoryWithCleanup(); * // Use tempDir... * await cleanup(); * ``` */ export async function createTempDirectoryWithCleanup(): Promise<{ path: string; cleanup: () => Promise; }> { const path = await createTempDirectory(); const cleanup = async () => { await removeTempDirectory(path); }; return { path, cleanup }; }