import { describe, expect, test } from '@jest/globals';
import { ArgumentValidationError } from '../../../src/shared/utils/errorHandling.js';
import type {
SchemaValidationIssue,
PromptDefinitionForError,
} from '../../../src/shared/utils/errorHandling.js';
describe('ArgumentValidationError', () => {
const basePromptDef: PromptDefinitionForError = {
id: 'test_prompt',
arguments: [
{
name: 'topic',
type: 'string',
required: true,
validation: { minLength: 10 },
},
{
name: 'url',
type: 'string',
required: false,
validation: { pattern: '^https://' },
},
],
};
describe('message formatting', () => {
test('formats error message with issue details', () => {
const issues: SchemaValidationIssue[] = [
{ argument: 'topic', message: 'Value must contain at least 10 characters' },
];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.message).toContain('Argument validation failed');
expect(error.message).toContain('topic');
expect(error.message).toContain('at least 10 characters');
});
test('includes retry hint in message', () => {
const issues: SchemaValidationIssue[] = [
{ argument: 'topic', message: 'Value must contain at least 10 characters' },
];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.message).toContain('Retry with:');
expect(error.message).toContain('>>test_prompt');
});
test('formats multiple issues correctly', () => {
const issues: SchemaValidationIssue[] = [
{ argument: 'topic', message: 'Value must contain at least 10 characters' },
{ argument: 'url', message: 'Value must match pattern ^https://' },
];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.message).toContain('topic');
expect(error.message).toContain('url');
});
});
describe('retry hint generation', () => {
test('generates hint with minLength placeholder', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const promptDef: PromptDefinitionForError = {
id: 'length_prompt',
arguments: [
{
name: 'topic',
required: true,
validation: { minLength: 10 },
},
],
};
const error = new ArgumentValidationError(issues, promptDef);
expect(error.message).toContain('at least 10 chars');
});
test('generates hint with maxLength placeholder', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too long' }];
const promptDef: PromptDefinitionForError = {
id: 'length_prompt',
arguments: [
{
name: 'topic',
required: true,
validation: { maxLength: 50 },
},
],
};
const error = new ArgumentValidationError(issues, promptDef);
expect(error.message).toContain('max 50 chars');
});
test('generates hint with minLength and maxLength combined', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Length issue' }];
const promptDef: PromptDefinitionForError = {
id: 'length_prompt',
arguments: [
{
name: 'topic',
required: true,
validation: { minLength: 10, maxLength: 50 },
},
],
};
const error = new ArgumentValidationError(issues, promptDef);
expect(error.message).toContain('10-50 chars');
});
test('generates hint with URL pattern placeholder', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'url', message: 'Pattern mismatch' }];
const promptDef: PromptDefinitionForError = {
id: 'url_prompt',
arguments: [
{
name: 'url',
required: true,
validation: { pattern: '^https://' },
},
],
};
const error = new ArgumentValidationError(issues, promptDef);
expect(error.message).toContain('https://example.com');
});
test('generates hint with http pattern placeholder', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'url', message: 'Pattern mismatch' }];
const promptDef: PromptDefinitionForError = {
id: 'url_prompt',
arguments: [
{
name: 'url',
required: true,
validation: { pattern: '^http://' },
},
],
};
const error = new ArgumentValidationError(issues, promptDef);
expect(error.message).toContain('http://example.com');
});
test('includes only required and failed arguments in retry hint', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'url', message: 'Pattern mismatch' }];
const error = new ArgumentValidationError(issues, basePromptDef);
// Should include required 'topic' and failed 'url'
expect(error.message).toContain('topic=');
expect(error.message).toContain('url=');
});
});
describe('error properties', () => {
test('has correct error code', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.code).toBe('ARGUMENT_VALIDATION_ERROR');
});
test('stores issues for inspection', () => {
const issues: SchemaValidationIssue[] = [
{ argument: 'topic', message: 'Too short', code: 'too_small' },
];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.issues).toEqual(issues);
});
test('stores prompt definition for inspection', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.promptDefinition).toEqual(basePromptDef);
});
test('has error context with suggestions', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.context.suggestions).toBeDefined();
expect(error.context.suggestions?.length).toBeGreaterThan(0);
});
test('has recovery options', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.context.recoveryOptions).toBeDefined();
expect(error.context.recoveryOptions).toContain('Retry with corrected arguments');
});
});
describe('enhanced message', () => {
test('getEnhancedMessage includes structured format', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
const enhanced = error.getEnhancedMessage();
expect(enhanced).toContain('Argument Validation Failed');
expect(enhanced).toContain('Issues Found');
expect(enhanced).toContain('Retry Command');
expect(enhanced).toContain('Tips');
});
test('getEnhancedMessage includes code block for retry', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
const enhanced = error.getEnhancedMessage();
expect(enhanced).toContain('```');
expect(enhanced).toContain('>>test_prompt');
});
});
describe('extends BaseError', () => {
test('is instance of Error', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error).toBeInstanceOf(Error);
});
test('has name property', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.name).toBe('ArgumentValidationError');
});
test('has timestamp', () => {
const issues: SchemaValidationIssue[] = [{ argument: 'topic', message: 'Too short' }];
const error = new ArgumentValidationError(issues, basePromptDef);
expect(error.timestamp).toBeDefined();
expect(new Date(error.timestamp).getTime()).not.toBeNaN();
});
});
});