/**
* Error Handler Unit Tests
*/
import { ErrorHandler, MCPError, ErrorCategory, ErrorStatistics } from '../../src/utils/error-handler.js';
describe('ErrorHandler', () => {
beforeEach(() => {
// Clear error statistics before each test
ErrorStatistics.clear();
});
describe('MCPError', () => {
it('should create error with all properties', () => {
const error = new MCPError(
'Test error message',
ErrorCategory.NETWORK,
'TEST_ERROR',
500
);
expect(error.message).toBe('Test error message');
expect(error.category).toBe(ErrorCategory.NETWORK);
expect(error.code).toBe('TEST_ERROR');
expect(error.statusCode).toBe(500);
expect(error.timestamp).toBeInstanceOf(Date);
expect(error.recoverable).toBe(true);
});
it('should set recoverable based on category', () => {
const networkError = new MCPError(
'Network error',
ErrorCategory.NETWORK,
'NETWORK_ERROR'
);
expect(networkError.recoverable).toBe(true);
const authError = new MCPError(
'Auth error',
ErrorCategory.AUTHENTICATION,
'AUTH_ERROR'
);
expect(authError.recoverable).toBe(true);
const validationError = new MCPError(
'Validation error',
ErrorCategory.VALIDATION,
'VALIDATION_ERROR'
);
expect(validationError.recoverable).toBe(false);
});
it('should serialize to JSON correctly', () => {
const error = new MCPError(
'Test error',
ErrorCategory.NETWORK,
'TEST_ERROR',
500
);
const serialized = error.toJSON();
expect(serialized).toEqual({
message: 'Test error',
category: ErrorCategory.NETWORK,
code: 'TEST_ERROR',
statusCode: 500,
timestamp: error.timestamp.toISOString(),
recoverable: true
});
});
});
describe('ErrorHandler.handle', () => {
it('should handle MCPError correctly', () => {
const originalError = new MCPError(
'Test error',
ErrorCategory.NETWORK,
'TEST_ERROR'
);
const handledError = ErrorHandler.handle(originalError);
expect(handledError).toBe(originalError);
});
it('should handle AxiosError correctly', () => {
const axiosError = {
name: 'AxiosError',
message: 'Request failed with status code 404',
response: {
status: 404,
statusText: 'Not Found',
data: { message: 'Resource not found' }
},
config: {
url: '/wp-json/wp/v2/posts/999',
method: 'get'
}
};
const handledError = ErrorHandler.handle(axiosError);
expect(handledError).toBeInstanceOf(MCPError);
expect(handledError.message).toContain('Request failed with status code 404');
expect(handledError.category).toBe(ErrorCategory.NETWORK);
expect(handledError.statusCode).toBe(404);
});
it('should handle generic Error correctly', () => {
const genericError = new Error('Generic error message');
const handledError = ErrorHandler.handle(genericError);
expect(handledError).toBeInstanceOf(MCPError);
expect(handledError.message).toBe('Generic error message');
expect(handledError.category).toBe(ErrorCategory.UNKNOWN);
expect(handledError.code).toBe('UNKNOWN_ERROR');
});
it('should handle unknown error types', () => {
const unknownError = 'String error';
const handledError = ErrorHandler.handle(unknownError);
expect(handledError).toBeInstanceOf(MCPError);
expect(handledError.message).toBe('String error');
expect(handledError.category).toBe(ErrorCategory.UNKNOWN);
});
});
describe('ErrorStatistics', () => {
it('should track errors correctly', () => {
const error1 = new MCPError('Error 1', ErrorCategory.NETWORK, 'NET_ERROR_1');
const error2 = new MCPError('Error 2', ErrorCategory.NETWORK, 'NET_ERROR_2');
const error3 = new MCPError('Error 3', ErrorCategory.VALIDATION, 'VAL_ERROR_1');
ErrorStatistics.recordError(error1);
ErrorStatistics.recordError(error2);
ErrorStatistics.recordError(error3);
const stats = ErrorStatistics.getStatistics();
expect(stats.totalErrors).toBe(3);
expect(stats.byCategory[ErrorCategory.NETWORK]).toBe(2);
expect(stats.byCategory[ErrorCategory.VALIDATION]).toBe(1);
expect(stats.byCode['NET_ERROR_1']).toBe(1);
expect(stats.byCode['NET_ERROR_2']).toBe(1);
expect(stats.byCode['VAL_ERROR_1']).toBe(1);
});
it('should clear statistics', () => {
const error = new MCPError('Test error', ErrorCategory.NETWORK, 'TEST_ERROR');
ErrorStatistics.recordError(error);
expect(ErrorStatistics.getStatistics().totalErrors).toBe(1);
ErrorStatistics.clear();
expect(ErrorStatistics.getStatistics().totalErrors).toBe(0);
expect(ErrorStatistics.getStatistics().byCategory).toEqual({});
expect(ErrorStatistics.getStatistics().byCode).toEqual({});
});
it('should track recoverable errors', () => {
const recoverableError = new MCPError('Recoverable', ErrorCategory.NETWORK, 'REC_ERROR');
const nonRecoverableError = new MCPError('Non-recoverable', ErrorCategory.VALIDATION, 'NON_REC_ERROR');
ErrorStatistics.recordError(recoverableError);
ErrorStatistics.recordError(nonRecoverableError);
const stats = ErrorStatistics.getStatistics();
expect(stats.recoverableErrors).toBe(1);
expect(stats.nonRecoverableErrors).toBe(1);
});
it('should track error rates', () => {
const error = new MCPError('Test error', ErrorCategory.NETWORK, 'TEST_ERROR');
ErrorStatistics.recordError(error);
ErrorStatistics.recordError(error);
const stats = ErrorStatistics.getStatistics();
expect(stats.errorRate).toBeCloseTo(1.0, 2); // 100% error rate if no successful operations
});
});
describe('isRecoverableError', () => {
it('should identify recoverable errors', () => {
const networkError = new MCPError('Network error', ErrorCategory.NETWORK, 'NET_ERROR');
const authError = new MCPError('Auth error', ErrorCategory.AUTHENTICATION, 'AUTH_ERROR');
expect(ErrorHandler.isRecoverableError(networkError)).toBe(true);
expect(ErrorHandler.isRecoverableError(authError)).toBe(true);
});
it('should identify non-recoverable errors', () => {
const validationError = new MCPError('Validation error', ErrorCategory.VALIDATION, 'VAL_ERROR');
const unknownError = new MCPError('Unknown error', ErrorCategory.UNKNOWN, 'UNKNOWN_ERROR');
expect(ErrorHandler.isRecoverableError(validationError)).toBe(false);
expect(ErrorHandler.isRecoverableError(unknownError)).toBe(false);
});
});
describe('getSuggestion', () => {
it('should provide suggestions for different error types', () => {
const networkError = new MCPError('Network error', ErrorCategory.NETWORK, 'NET_ERROR');
const authError = new MCPError('Auth error', ErrorCategory.AUTHENTICATION, 'AUTH_ERROR');
const validationError = new MCPError('Validation error', ErrorCategory.VALIDATION, 'VAL_ERROR');
expect(ErrorHandler.getSuggestion(networkError)).toContain('network');
expect(ErrorHandler.getSuggestion(authError)).toContain('credentials');
expect(ErrorHandler.getSuggestion(validationError)).toContain('parameters');
});
it('should provide generic suggestion for unknown errors', () => {
const unknownError = new MCPError('Unknown error', ErrorCategory.UNKNOWN, 'UNKNOWN_ERROR');
expect(ErrorHandler.getSuggestion(unknownError)).toContain('contact support');
});
});
});