UNPKG

cmte

Version:

Design by Committee™ except it's just you and LLMs

126 lines (109 loc) 5.78 kB
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; // Remove static import: import { OutputReferenceResolver } from "../output-reference-resolver.js"; import { logger } from '../../../utils/logger.js'; // Corrected path // Mock the logger module vi.mock('../../../utils/logger.js', () => ({ logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } })); // Helper function - uses dynamically imported class function setupResolver(ResolverClass) { const resolver = new ResolverClass(); resolver.registerOutput('set1', 'task_noniter', 'original_noniter'); resolver.registerIteratedOutput('set1', 'task1', 'item1', 'result1_iter'); resolver.registerIteratedOutput('set1', 'task1', 'item2', 'result2_iter'); resolver.registerIteratedOutput('set1', 'task1', 'item3', 'result3_iter'); resolver.registerOutput('set2', 'task2', 'result2_set2'); resolver.registerOutput('set3', 'task_obj', { nested: { value: 'nested_value' } }); resolver.registerIteratedOutput('set3', 'task_iter_obj', 'key1', { itemVal: 'iter_val1' }); resolver.registerIteratedOutput('set3', 'task_iter_obj', 'key2', { itemVal: 'iter_val2' }); return resolver; } describe('OutputReferenceResolver', () => { let OutputReferenceResolver; // For dynamic import let resolver; beforeEach(async () => { // Ensure mocks are applied *before* dynamic import vi.clearAllMocks(); // Dynamically import the class AFTER mocks are set up for the logger const module = await import("../output-reference-resolver.js"); OutputReferenceResolver = module.OutputReferenceResolver; // Setup resolver instance resolver = setupResolver(OutputReferenceResolver); }); // No afterEach needed for vi.mock (it's handled by Vitest) it('throws error for invalid reference format', () => { expect(() => resolver.resolveReference('invalid-format')).toThrow('Invalid output reference format'); // Check the initial debug log expect(logger.debug).toHaveBeenCalledWith('Resolving reference: invalid-format'); }); it('getAllOutputs returns copy of outputs', () => { const outputs = resolver.getAllOutputs(); outputs.set1.task_noniter = 'modified'; expect(resolver.resolveReference('set1.task_noniter')).toBe('original_noniter'); }); it('clear removes all outputs and iteration context', () => { resolver.setIterationContext('some_key'); resolver.clear(); expect(resolver.getAllOutputs()).toEqual({}); expect(resolver.currentIteration).toBeNull(); expect(() => resolver.resolveReference('set1.task1[item1]')).toThrow('Set not found'); }); describe('basic references', () => { it('resolves basic task reference', () => { expect(resolver.resolveReference('set1.task_noniter')).toBe('original_noniter'); // Check the initial debug log for this call expect(logger.debug).toHaveBeenCalledWith('Resolving reference: set1.task_noniter'); }); // ... (Keep other basic reference tests, they should pass now) ... it('throws error for non-existent set', () => { expect(() => resolver.resolveReference('nonExistentSet.task_noniter')).toThrow('Set not found'); }); it('throws error for non-existent task', () => { expect(() => resolver.resolveReference('set1.nonExistentTask')).toThrow('Task output not found'); }); it('throws error when referencing iterated output without key', () => { expect(() => resolver.resolveReference('set1.task1')).toThrow('Ambiguous reference'); }); }); describe('iteration references', () => { it('resolves specific iteration reference', () => { expect(resolver.resolveReference('set1.task1[item2]')).toBe('result2_iter'); // Check the initial debug log for this call expect(logger.debug).toHaveBeenCalledWith('Resolving reference: set1.task1[item2]'); }); it('resolves wildcard iteration reference', () => { expect(resolver.resolveReference('set1.task1[*]')).toEqual(['result1_iter', 'result2_iter', 'result3_iter']); // Check the initial debug log for this call expect(logger.debug).toHaveBeenCalledWith('Resolving reference: set1.task1[*]'); }); it('resolves [this] reference in iteration context', () => { resolver.setIterationContext('item2'); expect(resolver.resolveReference('set1.task1[this]')).toBe('result2_iter'); // Check the initial debug log for this call (includes context) expect(logger.debug).toHaveBeenCalledWith('Resolving reference: set1.task1[this] (Current Context: item2)'); resolver.clearIterationContext(); }); // ... (Keep other iteration tests, they should pass now) ... it('throws error for [this] reference outside iteration context', () => { expect(() => resolver.resolveReference('set1.task1[this]')).toThrow('Cannot use [this] iteration key'); }); it('throws error for non-existent iteration', () => { expect(() => resolver.resolveReference('set1.task1[nonExistentItem]')).toThrow('Iteration key \'nonExistentItem\' not found'); }); it('throws error when using iteration key on non-iterated output', () => { expect(() => resolver.resolveReference('set1.task_noniter[item1]')).toThrow('Cannot use iteration key'); }); }); // ... (Keep property path tests, they should pass now) ... describe('property path resolution', () => { it('resolves nested property on non-iterated output', () => { /* ... */ }); it('resolves nested property on specific iterated output', () => { /* ... */ }); it('resolves nested property using [this]', () => { /* ... */ }); it('throws reasonable error if property path is invalid', () => { /* ... */ }); }); });