cmte
Version:
Design by Committee™ except it's just you and LLMs
136 lines (118 loc) • 5.74 kB
JavaScript
import { describe, beforeEach, test, expect, vi } from 'vitest';
import { TemplateRenderer } from '../task/template-renderer.js';
import { FileCollectionManager } from '../file-collection-manager.js';
import { OutputReferenceResolver } from '../task/output-reference-resolver.js';
// Mock dependencies
vi.mock('../file-collection-manager.js');
vi.mock('../task/output-reference-resolver.js');
describe('TemplateRenderer', () => {
let renderer;
const basePath = '/test/base/path';
const context = { variable: 'value' };
let mockFileCollectionManagerInstance;
let mockOutputReferenceResolverInstance;
beforeEach(() => {
// Create mock instances
mockFileCollectionManagerInstance = {
loadAndRenderFiles: vi.fn(),
getFiles: vi.fn(),
readFileFromCollection: vi.fn(),
hasCollection: vi.fn().mockReturnValue(true)
};
mockOutputReferenceResolverInstance = {
resolveReference: vi.fn(),
};
// Instantiate TemplateRenderer with mock instances
renderer = new TemplateRenderer(
context,
basePath,
mockOutputReferenceResolverInstance,
mockFileCollectionManagerInstance
);
});
describe('constructor', () => {
test('initializes with context, basePath, resolver, and manager', () => {
expect(renderer.context).toBe(context);
expect(renderer.basePath).toBe(basePath);
expect(renderer.referenceResolver).toBe(mockOutputReferenceResolverInstance);
expect(renderer.fileCollectionManager).toBe(mockFileCollectionManagerInstance);
});
});
describe('render', () => {
beforeEach(() => {
mockFileCollectionManagerInstance.hasCollection.mockImplementation(
name => name === 'test'
);
mockFileCollectionManagerInstance.getFiles.mockImplementation((name, pattern) => {
if (name !== 'test') return [];
if (!pattern) return ['file1.js', 'file2.js'];
if (pattern === '*.js') return ['file1.js'];
return [];
});
mockFileCollectionManagerInstance.readFileFromCollection.mockImplementation(async (collectionName, filePath) => {
if (collectionName === 'test' && filePath === 'file1.js') return 'content1';
if (collectionName === 'test' && filePath === 'file2.js') return 'content2';
throw new Error(`Mock readFileFromCollection: Unknown file ${collectionName}/${filePath}`);
});
mockOutputReferenceResolverInstance.resolveReference.mockImplementation((ref) => {
if (ref === 'task.output') return 'output_value';
throw new Error(`Mock resolveReference: Unknown reference ${ref}`);
});
});
test('renders collection references', async () => {
mockFileCollectionManagerInstance.loadAndRenderFiles.mockResolvedValue('content1\\ncontent2');
const template = 'Files: {{files.test}}';
const result = await renderer.render(template);
expect(result).toBe('Files: content1\\ncontent2');
expect(mockFileCollectionManagerInstance.loadAndRenderFiles).toHaveBeenCalledWith('test');
});
test('renders context variables', async () => {
const template = 'Value: {{variable}}';
const result = await renderer.render(template);
expect(result).toBe('Value: value');
});
test('renders output references', async () => {
const template = 'Output: {{task.output}}';
const result = await renderer.render(template);
expect(result).toBe('Output: output_value');
expect(mockOutputReferenceResolverInstance.resolveReference).toHaveBeenCalledWith('task.output');
});
test('preserves unknown placeholders (non-collection, non-output, non-context)', async () => {
const template = 'Keep: {{unknown.ref}}';
const result = await renderer.render(template);
// Expect empty string for unresolved variables
expect(result).toBe('Keep: ');
});
test('handles empty collection file list', async () => {
mockFileCollectionManagerInstance.loadAndRenderFiles.mockResolvedValue('');
const template = 'Empty: {{files.test}}';
const result = await renderer.render(template);
expect(result).toBe('Empty: ');
expect(mockFileCollectionManagerInstance.loadAndRenderFiles).toHaveBeenCalledWith('test');
});
test('handles error during file collection loading', async () => {
const collectionError = new Error("Test loadAndRenderFiles error");
mockFileCollectionManagerInstance.loadAndRenderFiles.mockRejectedValue(collectionError);
const template = 'Error: {{files.test}}';
const result = await renderer.render(template);
expect(result).toBe(`Error: [Error: ${collectionError.message}]`);
expect(mockFileCollectionManagerInstance.loadAndRenderFiles).toHaveBeenCalledWith('test');
});
test('handles error during output reference resolution', async () => {
mockOutputReferenceResolverInstance.resolveReference.mockImplementation(() => {
throw new Error('Test output resolve error');
});
const template = 'Output Error: {{task.output}}';
const result = await renderer.render(template);
expect(result).toBe('Output Error: [Error: Test output resolve error]');
});
test('handles collection errors gracefully', async () => {
const collectionError = new Error("Test loadAndRenderFiles error");
mockFileCollectionManagerInstance.loadAndRenderFiles.mockRejectedValue(collectionError);
const template = 'Error: {{files.test}}';
const result = await renderer.render(template);
expect(result).toBe(`Error: [Error: ${collectionError.message}]`);
expect(mockFileCollectionManagerInstance.loadAndRenderFiles).toHaveBeenCalledWith('test');
});
});
});