// Error handler tests
import {
MCPError,
DatabaseError,
ValidationError,
QueryError,
handleMCPError,
validateDateRange,
validateLimit,
validateMonths,
validateProvider,
validateBankingQuery,
validateDataOperation,
} from '../src/error-handler.js';
describe('Error Handling', () => {
describe('Custom Error Classes', () => {
it('should create MCPError with correct properties', () => {
const error = new MCPError('Test error', 'TEST_ERROR', 400, {
message: 'Test error',
timestamp: new Date().toISOString(),
detail: 'test',
});
expect(error.message).toBe('Test error');
expect(error.code).toBe('TEST_ERROR');
expect(error.statusCode).toBe(400);
expect(error.details).toEqual({
message: 'Test error',
timestamp: expect.any(String),
detail: 'test',
});
expect(error.name).toBe('MCPError');
});
it('should create DatabaseError with correct properties', () => {
const error = new DatabaseError('Database error', {
message: 'Database error',
timestamp: new Date().toISOString(),
table: 'test',
});
expect(error.message).toBe('Database error');
expect(error.code).toBe('DATABASE_ERROR');
expect(error.statusCode).toBe(500);
expect(error.details).toEqual({
message: 'Database error',
timestamp: expect.any(String),
table: 'test',
});
expect(error.name).toBe('DatabaseError');
});
it('should create ValidationError with correct properties', () => {
const error = new ValidationError('Validation error', {
message: 'Validation error',
timestamp: new Date().toISOString(),
field: 'test',
});
expect(error.message).toBe('Validation error');
expect(error.code).toBe('VALIDATION_ERROR');
expect(error.statusCode).toBe(400);
expect(error.details).toEqual({
message: 'Validation error',
timestamp: expect.any(String),
field: 'test',
});
expect(error.name).toBe('ValidationError');
});
it('should create QueryError with correct properties', () => {
const error = new QueryError('Query error', {
message: 'Query error',
timestamp: new Date().toISOString(),
query: 'test',
});
expect(error.message).toBe('Query error');
expect(error.code).toBe('QUERY_ERROR');
expect(error.statusCode).toBe(400);
expect(error.details).toEqual({
message: 'Query error',
timestamp: expect.any(String),
query: 'test',
});
expect(error.name).toBe('QueryError');
});
});
describe('handleMCPError', () => {
it('should handle MCPError correctly', () => {
const error = new MCPError('Test error', 'TEST_ERROR', 400);
const result = handleMCPError(error, 'test_context');
expect(result.success).toBe(false);
expect(result.error).toBe('Test error');
expect(result.code).toBe('TEST_ERROR');
expect(result.context).toBe('test_context');
expect(result.timestamp).toBeDefined();
});
it('should handle regular Error correctly', () => {
const error = new Error('Regular error');
const result = handleMCPError(error, 'test_context');
expect(result.success).toBe(false);
expect(result.error).toBe('Regular error');
expect(result.code).toBe('UNKNOWN_ERROR');
expect(result.context).toBe('test_context');
expect(result.timestamp).toBeDefined();
});
it('should handle unknown error types', () => {
const error = 'String error';
const result = handleMCPError(error, 'test_context');
expect(result.success).toBe(false);
expect(result.error).toBe('String error');
expect(result.code).toBe('UNKNOWN_ERROR');
expect(result.context).toBe('test_context');
expect(result.timestamp).toBeDefined();
});
});
describe('Validation Functions', () => {
describe('validateDateRange', () => {
it('should pass with valid dates', () => {
expect(() =>
validateDateRange('2025-01-01', '2025-12-31')
).not.toThrow();
});
it('should pass with only dateFrom', () => {
expect(() => validateDateRange('2025-01-01')).not.toThrow();
});
it('should pass with only dateTo', () => {
expect(() => validateDateRange(undefined, '2025-12-31')).not.toThrow();
});
it('should throw for invalid dateFrom format', () => {
expect(() => validateDateRange('invalid-date', '2025-12-31')).toThrow(
ValidationError
);
});
it('should throw for invalid dateTo format', () => {
expect(() => validateDateRange('2025-01-01', 'invalid-date')).toThrow(
ValidationError
);
});
it('should throw when dateFrom is after dateTo', () => {
expect(() => validateDateRange('2025-12-31', '2025-01-01')).toThrow(
ValidationError
);
});
});
describe('validateLimit', () => {
it('should pass with valid limits', () => {
expect(() => validateLimit(1)).not.toThrow();
expect(() => validateLimit(1000)).not.toThrow();
expect(() => validateLimit(10000)).not.toThrow();
});
it('should pass with undefined', () => {
expect(() => validateLimit(undefined)).not.toThrow();
});
it('should throw for limit too small', () => {
expect(() => validateLimit(0)).toThrow(ValidationError);
expect(() => validateLimit(-1)).toThrow(ValidationError);
});
it('should throw for limit too large', () => {
expect(() => validateLimit(10001)).toThrow(ValidationError);
});
});
describe('validateMonths', () => {
it('should pass with valid months', () => {
expect(() => validateMonths(1)).not.toThrow();
expect(() => validateMonths(12)).not.toThrow();
expect(() => validateMonths(60)).not.toThrow();
});
it('should pass with undefined', () => {
expect(() => validateMonths(undefined)).not.toThrow();
});
it('should throw for months too small', () => {
expect(() => validateMonths(0)).toThrow(ValidationError);
expect(() => validateMonths(-1)).toThrow(ValidationError);
});
it('should throw for months too large', () => {
expect(() => validateMonths(61)).toThrow(ValidationError);
});
});
describe('validateProvider', () => {
it('should pass with valid provider', () => {
expect(() => validateProvider('deutsche-bank')).not.toThrow();
expect(() => validateProvider('tink')).not.toThrow();
});
it('should pass with undefined', () => {
expect(() => validateProvider(undefined)).not.toThrow();
});
it('should throw for non-string provider', () => {
expect(() => validateProvider(123 as any)).toThrow(ValidationError);
expect(() => validateProvider({} as any)).toThrow(ValidationError);
});
});
describe('validateBankingQuery', () => {
it('should pass with valid queries', () => {
const validQueries = [
'accounts',
'transactions',
'balance',
'overview',
'spending_analysis',
'cashflow_analysis',
'providers',
];
validQueries.forEach(query => {
expect(() => validateBankingQuery(query)).not.toThrow();
});
});
it('should throw for invalid query', () => {
expect(() => validateBankingQuery('invalid_query')).toThrow(QueryError);
expect(() => validateBankingQuery('')).toThrow(QueryError);
});
});
describe('validateDataOperation', () => {
it('should pass with valid operations', () => {
const validOperations = [
'get_stats',
'validate_data',
'export_data',
'cleanup_data',
];
validOperations.forEach(operation => {
expect(() => validateDataOperation(operation)).not.toThrow();
});
});
it('should throw for invalid operation', () => {
expect(() => validateDataOperation('invalid_operation')).toThrow(
QueryError
);
expect(() => validateDataOperation('')).toThrow(QueryError);
});
});
});
});