import { ErrorHandler } from '../src/error-handler'; import { OllamaError, ErrorType, NetworkError, ApiError, ValidationError, StreamingError, ToolExecutionError, PathValidationError, } from '../src/types'; // Mock Notice from Obsidian jest.mock('obsidian', () => ({ Notice: jest.fn(), })); describe('ErrorHandler', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('handleError', () => { it('should handle OllamaError with user-friendly message', () => { const error = new NetworkError('Connection failed'); ErrorHandler.handleError(error); expect(require('obsidian').Notice).toHaveBeenCalledWith( 'Connection error. Please check if Ollama is running.' ); }); it('should handle generic Error with user-friendly message', () => { const error = new Error('Network timeout occurred'); ErrorHandler.handleError(error); expect(require('obsidian').Notice).toHaveBeenCalledWith( 'Request timed out. Please check your Ollama connection.' ); }); it('should handle unknown error type with generic message', () => { const error = 'some string error'; ErrorHandler.handleError(error); expect(require('obsidian').Notice).toHaveBeenCalledWith('An unexpected error occurred'); }); it('should log detailed error information to console', () => { const error = new Error('Test error'); const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); ErrorHandler.handleError(error); expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Test error')); consoleSpy.mockRestore(); }); }); describe('NetworkError handling', () => { it('should create user-friendly message for network errors', () => { const error = new NetworkError('Connection failed'); const message = ErrorHandler['getUserFriendlyMessage'](error); expect(message).toBe('Connection error. Please check if Ollama is running.'); }); it('should include status code in error details', () => { const error = new NetworkError('Connection failed', 500); expect(error.statusCode).toBe(500); }); }); describe('ValidationError handling', () => { it('should create user-friendly message for validation errors', () => { const error = new ValidationError('Invalid input', { field: 'path', message: 'Path is required', }); const message = ErrorHandler['getUserFriendlyMessage'](error); expect(message).toContain('Invalid path'); }); it('should handle validation errors without field details', () => { const error = new ValidationError('Invalid input'); const message = ErrorHandler['getUserFriendlyMessage'](error); expect(message).toBe('Input validation error. Please correct your input.'); }); }); describe('StreamingError handling', () => { it('should create user-friendly message for streaming errors', () => { const error = new StreamingError('Response too long'); const message = ErrorHandler['getUserFriendlyMessage'](error); expect(message).toBe('Response too long. Please try a shorter request.'); }); }); describe('ToolExecutionError handling', () => { it('should create user-friendly message for tool errors', () => { const error = new ToolExecutionError('Tool failed', 'create_file'); const message = ErrorHandler['getUserFriendlyMessage'](error); expect(message).toContain('Tool error'); expect(message).toContain('create_file'); }); }); describe('PathValidationError handling', () => { it('should create user-friendly message for path errors', () => { const error = new PathValidationError('Invalid path', '/../test.md'); const message = ErrorHandler['getUserFriendlyMessage'](error); expect(message).toContain('Invalid file path'); }); }); describe('Error creation methods', () => { it('should create NetworkError with proper type', () => { const error = ErrorHandler.createNetworkError('Connection failed'); expect(error).toBeInstanceOf(NetworkError); expect(error.type).toBe(ErrorType.NETWORK_ERROR); }); it('should create ApiError with proper type', () => { const error = ErrorHandler.createApiError('API error'); expect(error).toBeInstanceOf(ApiError); expect(error.type).toBe(ErrorType.API_ERROR); }); it('should create ValidationError with proper type', () => { const error = ErrorHandler.createValidationError('Validation failed', 'path'); expect(error).toBeInstanceOf(ValidationError); expect(error.type).toBe(ErrorType.VALIDATION_ERROR); }); it('should create StreamingError with proper type', () => { const error = ErrorHandler.createStreamingError('Streaming failed'); expect(error).toBeInstanceOf(StreamingError); expect(error.type).toBe(ErrorType.STREAMING_ERROR); }); it('should create ToolExecutionError with proper type', () => { const error = ErrorHandler.createToolExecutionError('Tool failed'); expect(error).toBeInstanceOf(ToolExecutionError); expect(error.type).toBe(ErrorType.TOOL_EXECUTION_ERROR); }); it('should create PathValidationError with proper type', () => { const error = ErrorHandler.createPathValidationError('Path invalid'); expect(error).toBeInstanceOf(PathValidationError); expect(error.type).toBe(ErrorType.PATH_VALIDATION_ERROR); }); it('should create UnknownError with proper type', () => { const error = ErrorHandler.createUnknownError('Unknown error'); expect(error).toBeInstanceOf(OllamaError); expect(error.type).toBe(ErrorType.UNKNOWN_ERROR); }); }); describe('Error message detection', () => { it('should detect network-related errors in generic Error', () => { const error = new Error('Network connection failed'); const message = ErrorHandler['getUserFriendlyMessageFromError'](error); expect(message).toContain('Connection error'); }); it('should detect timeout errors in generic Error', () => { const error = new Error('Request timeout occurred'); const message = ErrorHandler['getUserFriendlyMessageFromError'](error); expect(message).toContain('timed out'); }); it('should detect validation errors in generic Error', () => { const error = new Error('Validation format error'); const message = ErrorHandler['getUserFriendlyMessageFromError'](error); expect(message).toContain('Invalid input'); }); it('should detect streaming errors in generic Error', () => { const error = new Error('Streaming chunk error'); const message = ErrorHandler['getUserFriendlyMessageFromError'](error); expect(message).toContain('Response too long'); }); it('should detect tool errors in generic Error', () => { const error = new Error('Tool function error'); const message = ErrorHandler['getUserFriendlyMessageFromError'](error); expect(message).toContain('Tool error'); }); it('should detect path errors in generic Error', () => { const error = new Error('Path file error'); const message = ErrorHandler['getUserFriendlyMessageFromError'](error); expect(message).toContain('Invalid file path'); }); }); });