import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join, resolve } from 'node:path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { findNearestKtxProjectDir, resolveKtxProjectDir } from '../src/project-resolver.js'; describe('resolveKtxProjectDir', () => { let tempDir: string; beforeEach(async () => { tempDir = await mkdtemp(join(tmpdir(), 'ktx-project-resolver-')); }); afterEach(async () => { await rm(tempDir, { recursive: true, force: true }); }); it('prefers an explicit project directory', async () => { const explicit = join(tempDir, 'explicit'); const envProject = join(tempDir, 'env'); await mkdir(explicit, { recursive: true }); await mkdir(envProject, { recursive: true }); expect( resolveKtxProjectDir({ explicitProjectDir: explicit, env: { KTX_PROJECT_DIR: envProject }, cwd: tempDir, }), ).toBe(resolve(explicit)); }); it('uses KTX_PROJECT_DIR when no explicit project directory is set', async () => { const envProject = join(tempDir, 'env-project'); await mkdir(envProject, { recursive: true }); expect(resolveKtxProjectDir({ env: { KTX_PROJECT_DIR: envProject }, cwd: tempDir })).toBe(resolve(envProject)); }); it('resolves a relative KTX_PROJECT_DIR value from cwd', () => { expect(resolveKtxProjectDir({ env: { KTX_PROJECT_DIR: 'env-project' }, cwd: tempDir })).toBe( resolve(tempDir, 'env-project'), ); }); it('uses the nearest ancestor containing ktx.yaml', async () => { const project = join(tempDir, 'warehouse'); const nested = join(project, 'nested', 'deeper'); await mkdir(nested, { recursive: true }); await writeFile(join(project, 'ktx.yaml'), '{}\n', 'utf-8'); expect(resolveKtxProjectDir({ env: {}, cwd: nested })).toBe(resolve(project)); expect(findNearestKtxProjectDir(nested)).toBe(resolve(project)); }); it('falls back to the current directory when no project marker exists', () => { expect(resolveKtxProjectDir({ env: {}, cwd: tempDir })).toBe(resolve(tempDir)); expect(findNearestKtxProjectDir(tempDir)).toBeUndefined(); }); it('rejects empty explicit and environment project directory values', () => { expect(() => resolveKtxProjectDir({ explicitProjectDir: ' ', cwd: tempDir })).toThrow( '--project-dir requires a value', ); expect(() => resolveKtxProjectDir({ env: { KTX_PROJECT_DIR: ' ' }, cwd: tempDir })).toThrow( 'KTX_PROJECT_DIR must not be empty', ); }); });