mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-15 22:21:20 +00:00
113 lines
3.5 KiB
TypeScript
113 lines
3.5 KiB
TypeScript
import { describe, it, expect } from 'bun:test';
|
|
import { runCommandWithContract } from '../../../src/commands/command-execution-contract';
|
|
|
|
describe('runCommandWithContract', () => {
|
|
it('runs parse -> validate -> execute -> render in order', async () => {
|
|
const lifecycle: string[] = [];
|
|
|
|
const result = await runCommandWithContract(['--flag'], {
|
|
parse: (rawArgs) => {
|
|
lifecycle.push('parse');
|
|
expect(rawArgs).toEqual(['--flag']);
|
|
return { parsed: true, value: rawArgs[0] };
|
|
},
|
|
validate: (parsedArgs) => {
|
|
lifecycle.push('validate');
|
|
expect(parsedArgs).toEqual({ parsed: true, value: '--flag' });
|
|
},
|
|
execute: async (parsedArgs) => {
|
|
lifecycle.push('execute');
|
|
return { output: parsedArgs.value.toUpperCase() };
|
|
},
|
|
render: (executionResult, context) => {
|
|
lifecycle.push('render');
|
|
expect(executionResult).toEqual({ output: '--FLAG' });
|
|
expect(context.rawArgs).toEqual(['--flag']);
|
|
expect(context.parsedArgs).toEqual({ parsed: true, value: '--flag' });
|
|
},
|
|
});
|
|
|
|
expect(lifecycle).toEqual(['parse', 'validate', 'execute', 'render']);
|
|
expect(result.parsedArgs).toEqual({ parsed: true, value: '--flag' });
|
|
expect(result.result).toEqual({ output: '--FLAG' });
|
|
});
|
|
|
|
it('short-circuits after validate failure', async () => {
|
|
const lifecycle: string[] = [];
|
|
|
|
const promise = runCommandWithContract([], {
|
|
parse: () => {
|
|
lifecycle.push('parse');
|
|
return { valid: false };
|
|
},
|
|
validate: () => {
|
|
lifecycle.push('validate');
|
|
throw new Error('validation failed');
|
|
},
|
|
execute: () => {
|
|
lifecycle.push('execute');
|
|
return { ok: true };
|
|
},
|
|
render: () => {
|
|
lifecycle.push('render');
|
|
},
|
|
});
|
|
|
|
await expect(promise).rejects.toThrow('validation failed');
|
|
expect(lifecycle).toEqual(['parse', 'validate']);
|
|
});
|
|
|
|
it('awaits async validate before execute and render', async () => {
|
|
const lifecycle: string[] = [];
|
|
|
|
const result = await runCommandWithContract(['--flag'], {
|
|
parse: (rawArgs) => {
|
|
lifecycle.push('parse');
|
|
return { parsed: true, value: rawArgs[0] };
|
|
},
|
|
validate: async () => {
|
|
lifecycle.push('validate:start');
|
|
await Promise.resolve();
|
|
lifecycle.push('validate:end');
|
|
},
|
|
execute: (parsedArgs) => {
|
|
lifecycle.push('execute');
|
|
return { output: parsedArgs.value.toUpperCase() };
|
|
},
|
|
render: () => {
|
|
lifecycle.push('render');
|
|
},
|
|
});
|
|
|
|
expect(lifecycle).toEqual(['parse', 'validate:start', 'validate:end', 'execute', 'render']);
|
|
expect(result.result).toEqual({ output: '--FLAG' });
|
|
});
|
|
|
|
it('short-circuits after async validate failure', async () => {
|
|
const lifecycle: string[] = [];
|
|
|
|
const promise = runCommandWithContract([], {
|
|
parse: () => {
|
|
lifecycle.push('parse');
|
|
return { valid: false };
|
|
},
|
|
validate: async () => {
|
|
lifecycle.push('validate:start');
|
|
await Promise.resolve();
|
|
lifecycle.push('validate:reject');
|
|
throw new Error('async validation failed');
|
|
},
|
|
execute: () => {
|
|
lifecycle.push('execute');
|
|
return { ok: true };
|
|
},
|
|
render: () => {
|
|
lifecycle.push('render');
|
|
},
|
|
});
|
|
|
|
await expect(promise).rejects.toThrow('async validation failed');
|
|
expect(lifecycle).toEqual(['parse', 'validate:start', 'validate:reject']);
|
|
});
|
|
});
|