/** * cli:run-ui-test — validate.ts */ import path from 'node:path'; import { promises as fs } from 'node:fs'; import { RunUiTestInputSchema, type RunUiTestInput } from './types.js'; export interface ValidationResult { valid: boolean; errors: string[]; warnings: string[]; data?: RunUiTestInput; } export async function validate(raw: unknown): Promise { const result = RunUiTestInputSchema.safeParse(raw); if (!result.success) { return { valid: false, errors: result.error.issues.map((i) => `[${i.path.join('.')}] ${i.message}`), warnings: [], }; } const spec = result.data; const errors: string[] = []; const warnings: string[] = []; // Verify the manifest + users files exist (so we fail fast with a clear message). const manifestAbs = path.resolve(spec.projectPath, spec.manifestPath); const usersAbs = path.resolve(spec.projectPath, spec.usersPath); try { await fs.access(manifestAbs); } catch { errors.push(`Manifest not found at ${manifestAbs}. Run build-manifest first.`); } try { await fs.access(usersAbs); } catch { errors.push(`Test users manifest not found at ${usersAbs}. Run scaffold-seed with testUsers[] first.`); } // Verify dev-browser is reachable. We don't actually invoke it — just check // that npx can find it. Better to fail fast than spend 60s per test on ENOENT. // (CLI side: a synchronous existsSync of node_modules/dev-browser/package.json) try { const devBrowserPkg = path.resolve(spec.projectPath, 'node_modules/dev-browser/package.json'); await fs.access(devBrowserPkg); } catch { errors.push('dev-browser not installed in this project. Run: npm install --save-dev dev-browser@0.2.7 && npx dev-browser install'); } return { valid: errors.length === 0, errors, warnings, data: spec }; }