cmte
Version:
Design by Committee™ except it's just you and LLMs
222 lines (193 loc) • 6.71 kB
text/typescript
import { describe, it, expect, beforeEach } from 'vitest';
import { VariableResolver } from '../VariableResolver';
import { ValidationError } from '../errors';
import { Workflow, IterationContext } from '../types';
describe('VariableResolver', () => {
let workflow: Workflow;
let resolver: VariableResolver;
beforeEach(() => {
workflow = {
variables: {
globalVar: 'global-value',
config: { key: 'value' }
},
objectsForIteration: {
services: {
auth: { code: 'auth.ts' },
user: { code: 'user.ts' }
},
set1: {
auth: { output: 'auth-result' },
user: { output: 'user-result' }
},
subSet: {
config: { output: 'config-result' },
data: { output: 'data-result' }
}
}
};
resolver = new VariableResolver(workflow);
});
describe('resolve', () => {
it('should resolve global variables', () => {
expect(resolver.resolve('globalVar')).toBe('global-value');
expect(resolver.resolve('config')).toEqual({ key: 'value' });
});
it('should throw on invalid global variables', () => {
expect(() => {
resolver.resolve('invalidVar');
}).toThrow(ValidationError);
});
it('should resolve output paths', () => {
resolver.registerOutput('phase1.set1.output', 'result');
expect(resolver.resolve('$phase1.set1.output')).toBe('result');
});
it('should throw on invalid output paths', () => {
expect(() => {
resolver.resolve('$invalid.path');
}).toThrow(ValidationError);
});
it('should resolve humanInputRequired paths', () => {
resolver.registerOutput('phase1.services[auth]', { code: 'auth-code' }, {
currentIteration: 'auth',
parentIterations: ['services']
});
expect(resolver.resolve('$phase1.services[auth]')).toEqual({
code: 'auth-code'
});
});
it('should resolve humanInputRequired paths with $this', () => {
resolver.registerOutput('phase1.services[$this]', { code: 'auth-code' }, {
currentIteration: 'auth',
parentIterations: ['services']
});
expect(
resolver.resolve('$phase1.services[$this]', {
currentIteration: 'auth',
parentIterations: ['services']
})
).toEqual({
code: 'auth-code'
});
});
it('should resolve humanInputRequired paths with .all', () => {
resolver.registerOutput('phase1.services[auth]', { code: 'auth-code' }, {
currentIteration: 'auth',
parentIterations: ['services']
});
resolver.registerOutput('phase1.services[user]', { code: 'user-code' }, {
currentIteration: 'user',
parentIterations: ['services']
});
expect(resolver.resolve('$phase1.services.all')).toEqual([
{ code: 'auth-code' },
{ code: 'user-code' }
]);
});
});
describe('registerOutput', () => {
const context: IterationContext = {
currentIteration: 'auth',
parentIterations: ['services']
};
it('should register simple outputs', () => {
resolver.registerOutput('phase1.set1.output', 'result');
expect(resolver.getPhaseOutputs('phase1')).toEqual({
set1: { output: 'result' }
});
});
it('should register nested outputs', () => {
resolver.registerOutput('phase1.set1[auth].output', 'auth-result', context);
resolver.registerOutput('phase1.set1[user].output', 'user-result', context);
expect(resolver.getPhaseOutputs('phase1')).toEqual({
set1: {
auth: { output: 'auth-result' },
user: { output: 'user-result' }
}
});
});
it('should handle $this in output paths', () => {
resolver.registerOutput('phase1.set1[$this].output', 'auth-result', context);
expect(resolver.getPhaseOutputs('phase1')).toEqual({
set1: {
auth: { output: 'auth-result' }
}
});
});
it('should create intermediate objects as needed', () => {
resolver.registerOutput('phase1.set1[auth].nested.deep.output', 'result', context);
expect(resolver.getPhaseOutputs('phase1')).toEqual({
set1: {
auth: {
nested: {
deep: {
output: 'result'
}
}
}
}
});
});
});
describe('getPhaseOutputs', () => {
it('should return undefined for unknown phases', () => {
expect(resolver.getPhaseOutputs('unknown')).toBeUndefined();
});
it('should return all outputs for a phase', () => {
resolver.registerOutput('phase1.set1.output1', 'result1');
resolver.registerOutput('phase1.set2.output2', 'result2');
expect(resolver.getPhaseOutputs('phase1')).toEqual({
set1: { output1: 'result1' },
set2: { output2: 'result2' }
});
});
});
describe('clearOutputs', () => {
it('should clear all registered outputs', () => {
resolver.registerOutput('phase1.set1.output', 'result');
resolver.clearOutputs();
expect(resolver.getPhaseOutputs('phase1')).toBeUndefined();
});
});
describe('complex scenarios', () => {
const context: IterationContext = {
currentIteration: 'auth',
parentIterations: ['services']
};
it('should handle deeply nested iterations', () => {
// Register outputs for nested iterations
resolver.registerOutput(
'phase1.set1[$this].subSet[config].output',
'auth-config-result',
context
);
// Try resolving with different contexts
expect(
resolver.resolve('$phase1.set1[auth].subSet[config].output', context)
).toBe('auth-config-result');
});
it('should collect all outputs correctly', () => {
// Register multiple outputs
resolver.registerOutput('phase1.set1[auth].output', 'auth-result', context);
resolver.registerOutput('phase1.set1[user].output', 'user-result', context);
// Collect all outputs
const allResults = resolver.resolve('$phase1.set1.all', context);
expect(allResults).toEqual([
{ output: 'auth-result' },
{ output: 'user-result' }
]);
});
it('should validate against objectsForIteration consistently', () => {
// Should work with valid service
resolver.registerOutput('phase1.services[auth].output', 'result', context);
// Should fail with invalid service
expect(() => {
resolver.registerOutput(
'phase1.services[invalid].output',
'result',
context
);
}).toThrow(ValidationError);
});
});
});