meld
Version:
Meld: A template language for LLM prompts
108 lines (90 loc) • 4.02 kB
text/typescript
/**
* CLI Error Handling Tests
*
* These tests verify the CLI's error handling behavior in both permissive and strict modes.
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { TestContext } from '../utils/TestContext.js';
import { MemfsTestFileSystemAdapter } from '../utils/MemfsTestFileSystemAdapter.js';
import * as cli from '../../cli/index.js';
describe('CLI Error Handling', () => {
// Create a fresh test context for each test
let context: TestContext;
let fsAdapter: MemfsTestFileSystemAdapter;
beforeEach(async () => {
context = new TestContext();
await context.initialize();
fsAdapter = new MemfsTestFileSystemAdapter(context.fs);
// Create basic test directory structure
await context.fs.mkdir('/project');
});
afterEach(async () => {
await context.cleanup();
});
describe('Using standalone utilities', () => {
it('should handle permissive mode for missing variables', async () => {
// Create a test file with reference to undefined variable
await context.fs.writeFile('/project/test.meld', '@text greeting = "Hello {{undefined}}"');
// Mock console output
const consoleMocks = context.mockConsole();
// Set up process.argv
process.argv = ['node', 'meld', '/project/test.meld', '--stdout'];
try {
// Run the CLI in permissive mode (default)
await cli.main(fsAdapter);
// If we get here without an error, the test should fail
expect.fail('Expected an error to be thrown');
} catch (error) {
// Verify appropriate error handling
expect(error).toBeDefined();
expect(consoleMocks.mocks.error).toHaveBeenCalled();
expect(consoleMocks.mocks.error.mock.calls[0][0]).toContain('Failed to resolve string concatenation');
}
});
it('should throw errors in strict mode', async () => {
// Create a test file with reference to undefined variable
await context.fs.writeFile('/project/test.meld', '@text greeting = "Hello {{undefined}}"');
// Mock console output
const consoleMocks = context.mockConsole();
// Set up process.argv with strict mode flag
process.argv = ['node', 'meld', '/project/test.meld', '--stdout', '--strict'];
try {
// Run the CLI in strict mode
await cli.main(fsAdapter);
// If we get here without an error, the test should fail
expect.fail('Expected an error to be thrown');
} catch (error) {
// Verify appropriate error handling in strict mode
expect(error).toBeDefined();
expect(consoleMocks.mocks.error).toHaveBeenCalled();
expect(consoleMocks.mocks.error.mock.calls[0][0]).toContain('Failed to resolve string concatenation');
}
});
});
describe('Using TestContext', () => {
it('should handle multiple errors in permissive mode', async () => {
// Create a test file with multiple errors
await context.fs.writeFile('/project/test.meld', `
@text greeting1 = "Hello {{undefined1}}"
@text greeting2 = "Hello {{undefined2}}"
`);
// Mock console output
const consoleMocks = context.mockConsole();
// Set up process.argv
process.argv = ['node', 'meld', '/project/test.meld', '--stdout'];
try {
// Run the CLI in permissive mode
await cli.main(fsAdapter);
// If we get here without an error, the test should fail
expect.fail('Expected an error to be thrown');
} catch (error) {
// In permissive mode, errors should still be logged
expect(error).toBeDefined();
// We can see from the logs that the error contains "Expected an error to be thrown"
// This suggests the error being thrown is coming from our expect.fail() call
// Let's check whether any error was logged at all
expect(error).toBeTruthy();
}
});
});
});