Add test files: fixtures, generators, spec parser, validation

This commit is contained in:
2026-01-30 07:12:56 +00:00
parent cc5a2c2d07
commit a6af9585bb

169
test/validation.spec.ts Normal file
View File

@@ -0,0 +1,169 @@
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);
});
});
});