import { validateSpec } from '../src/validators/schema.js'; describe('Spec Validation', () => { describe('valid specs', () => { it('should validate a minimal spec', () => { const spec = { name: 'test', version: '1.0.0', description: 'A test CLI', commands: [{ name: 'test', description: 'Test command' }], }; const result = validateSpec(spec); expect(result.success).toBe(true); expect((result as { success: true; data: unknown }).data).toBeDefined(); }); it('should validate a full spec with all options', () => { const spec = { name: 'my-cli', version: '1.0.0', description: 'A full featured CLI', author: 'John Doe', license: 'MIT', bin: 'my-cli', globalOptions: [ { name: 'verbose', short: 'v', description: 'Verbose output', type: 'boolean' as const, default: false, }, ], commands: [ { name: 'start', description: 'Start the service', aliases: ['run'], options: [ { name: 'port', description: 'Port number', type: 'number' as const, default: 8080, }, ], arguments: [ { name: 'service', description: 'Service name', required: true, }, ], }, ], examples: [ { description: 'Start service', command: 'my-cli start api', output: 'Started api', }, ], }; const result = validateSpec(spec); expect(result.success).toBe(true); }); }); describe('invalid specs', () => { it('should fail on empty name', () => { const spec = { name: '', version: '1.0.0', description: 'test', commands: [{ name: 'test', description: 'test' }], }; const result = validateSpec(spec); expect(result.success).toBe(false); expect((result as { success: false; errors: string[] }).errors?.some((e) => e.includes('name'))).toBe(true); }); it('should fail on invalid version format', () => { const spec = { name: 'test', version: 'invalid', description: 'test', commands: [{ name: 'test', description: 'test' }], }; const result = validateSpec(spec); expect(result.success).toBe(false); expect((result as { success: false; errors: string[] }).errors?.some((e) => e.includes('version'))).toBe(true); }); it('should fail on empty description', () => { const spec = { name: 'test', version: '1.0.0', description: '', commands: [{ name: 'test', description: 'test' }], }; const result = validateSpec(spec); expect(result.success).toBe(false); }); it('should fail on invalid option type', () => { const spec = { name: 'test', version: '1.0.0', description: 'test', commands: [{ name: 'test', description: 'test' }], globalOptions: [ { name: 'opt', description: 'An option', type: 'invalid-type' as const, }, ], }; const result = validateSpec(spec); expect(result.success).toBe(false); expect((result as { success: false; errors: string[] }).errors?.some((e) => e.includes('type'))).toBe(true); }); }); describe('nested commands', () => { it('should validate nested subcommands', () => { const spec = { name: 'test', version: '1.0.0', description: 'test', commands: [ { name: 'parent', description: 'Parent command', subcommands: [ { name: 'child', description: 'Child command', options: [ { name: 'flag', description: 'A flag', type: 'boolean' as const, }, ], }, ], }, ], }; const result = validateSpec(spec); expect(result.success).toBe(true); }); }); });