Skip to main content
Glama
ErrorHandler.test.ts13.8 kB
/** * Unit tests for ErrorHandler utility */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { ErrorHandler, ErrorSeverity, GracefulDegradationOptions, } from "../../utils/ErrorHandler.js"; describe("ErrorHandler", () => { beforeEach(() => { // Clear error history before each test ErrorHandler.clearErrorHistory(); vi.clearAllMocks(); }); afterEach(() => { // Clean up after each test ErrorHandler.clearErrorHistory(); }); describe("handleError", () => { it("should handle Error object correctly", async () => { const error = new Error("Test error message"); const result = await ErrorHandler.handleError(error, "TestComponent"); expect(result.canContinue).toBeDefined(); expect(typeof result.canContinue).toBe("boolean"); }); it("should handle string error correctly", async () => { const result = await ErrorHandler.handleError( "String error", "TestComponent" ); expect(result.canContinue).toBeDefined(); expect(typeof result.canContinue).toBe("boolean"); }); it("should provide fallback data when graceful degradation is possible", async () => { const error = new Error("Non-critical error"); const options: Partial<GracefulDegradationOptions> = { enableFallbacks: true, criticalComponents: [], }; const result = await ErrorHandler.handleError( error, "SensoryProcessor", {}, options ); if (result.canContinue) { expect(result.fallbackData).toBeDefined(); } }); it("should not allow graceful degradation for critical errors", async () => { const error = new Error("Out of memory error"); const result = await ErrorHandler.handleError(error, "TestComponent"); expect(result.canContinue).toBe(false); expect(result.fallbackData).toBeUndefined(); }); it("should not allow graceful degradation for critical components with high severity", async () => { const error = new Error("Initialization failed"); const options: Partial<GracefulDegradationOptions> = { criticalComponents: ["CognitiveOrchestrator"], }; const result = await ErrorHandler.handleError( error, "CognitiveOrchestrator", {}, options ); expect(result.canContinue).toBe(false); }); it("should track component errors", async () => { const error1 = new Error("First error"); const error2 = new Error("Second error"); await ErrorHandler.handleError(error1, "TestComponent"); await ErrorHandler.handleError(error2, "TestComponent"); const stats = ErrorHandler.getErrorStatistics(); expect(stats.TestComponent).toBeDefined(); expect(stats.TestComponent.total).toBe(2); }); }); describe("withErrorHandling", () => { it("should execute successful operation", async () => { const mockOperation = vi.fn().mockResolvedValue("success result"); const result = await ErrorHandler.withErrorHandling( mockOperation, "TestComponent" ); expect(result.success).toBe(true); expect(result.data).toBe("success result"); expect(result.error).toBeUndefined(); expect(mockOperation).toHaveBeenCalledTimes(1); }); it("should retry failed operations", async () => { const mockOperation = vi .fn() .mockRejectedValueOnce(new Error("First failure")) .mockRejectedValueOnce(new Error("Second failure")) .mockResolvedValue("success result"); const result = await ErrorHandler.withErrorHandling( mockOperation, "TestComponent", { maxRetries: 3, retryDelayMs: 10 } ); expect(result.success).toBe(true); expect(result.data).toBe("success result"); expect(mockOperation).toHaveBeenCalledTimes(3); }); it("should fail after max retries", async () => { const mockOperation = vi .fn() .mockRejectedValue(new Error("Persistent failure")); const result = await ErrorHandler.withErrorHandling( mockOperation, "TestComponent", { maxRetries: 2, retryDelayMs: 10 } ); expect(result.success).toBe(false); expect(result.error).toBeDefined(); expect(result.error!.message).toBe("Persistent failure"); expect(mockOperation).toHaveBeenCalledTimes(2); }); it("should handle timeout", async () => { const mockOperation = vi .fn() .mockImplementation( () => new Promise((resolve) => setTimeout(resolve, 200)) ); const result = await ErrorHandler.withErrorHandling( mockOperation, "TestComponent", { timeoutMs: 50, maxRetries: 1 } ); expect(result.success).toBe(false); expect(result.error).toBeDefined(); expect(result.error!.message).toContain("timed out"); }); it("should provide fallback data on failure", async () => { const mockOperation = vi .fn() .mockRejectedValue(new Error("Operation failed")); const result = await ErrorHandler.withErrorHandling( mockOperation, "SensoryProcessor", { maxRetries: 1, retryDelayMs: 10 } ); expect(result.success).toBe(false); expect(result.error).toBeDefined(); // Fallback data might be provided depending on component if (result.data) { expect(result.data).toBeDefined(); } }); }); describe("Error severity assessment", () => { it("should assess critical errors correctly", async () => { const criticalErrors = [ "Out of memory error", "Stack overflow detected", "Segmentation fault occurred", ]; for (const errorMsg of criticalErrors) { const result = await ErrorHandler.handleError( errorMsg, "TestComponent" ); expect(result.canContinue).toBe(false); } }); it("should assess high severity errors for core components", async () => { const highSeverityErrors = [ "Initialization failed", "Configuration error detected", "Connection lost", ]; for (const errorMsg of highSeverityErrors) { const result = await ErrorHandler.handleError( errorMsg, "CognitiveOrchestrator", {}, { criticalComponents: ["CognitiveOrchestrator"] } ); expect(result.canContinue).toBe(false); } }); it("should assess medium severity errors correctly", async () => { const mediumSeverityErrors = [ "Processing timeout occurred", "Validation failed for input", "Timeout exceeded", ]; for (const errorMsg of mediumSeverityErrors) { const result = await ErrorHandler.handleError( errorMsg, "TestComponent" ); // Medium severity errors should allow graceful degradation expect(result.canContinue).toBe(true); } }); }); describe("Component fallbacks", () => { it("should provide SensoryProcessor fallback", async () => { const result = await ErrorHandler.handleError( "Processing failed", "SensoryProcessor", { input: "test input" }, { enableFallbacks: true } ); if (result.canContinue && result.fallbackData) { const fallback = result.fallbackData as any; expect(fallback.tokens).toBeDefined(); expect(fallback.patterns).toBeDefined(); expect(fallback.salience_map).toBeDefined(); } }); it("should provide EmotionalProcessor fallback", async () => { const result = await ErrorHandler.handleError( "Emotional processing failed", "EmotionalProcessor", {}, { enableFallbacks: true } ); if (result.canContinue && result.fallbackData) { const fallback = result.fallbackData as any; expect(fallback.valence).toBe(0); expect(fallback.arousal).toBe(0.5); expect(fallback.dominance).toBe(0.5); expect(fallback.specific_emotions).toBeDefined(); } }); it("should provide MetacognitionModule fallback", async () => { const result = await ErrorHandler.handleError( "Metacognition failed", "MetacognitionModule", {}, { enableFallbacks: true } ); if (result.canContinue && result.fallbackData) { const fallback = result.fallbackData as any; expect(fallback.confidence).toBe(0.5); expect(fallback.coherence).toBe(0.5); expect(fallback.completeness).toBe(0.5); expect(fallback.biases_detected).toEqual([]); expect(fallback.suggestions).toBeDefined(); expect(fallback.reasoning).toContain("Fallback assessment"); } }); it("should provide DualProcessController fallback", async () => { const result = await ErrorHandler.handleError( "Dual process failed", "DualProcessController", { input: "test input" }, { enableFallbacks: true } ); if (result.canContinue && result.fallbackData) { const fallback = result.fallbackData as any; expect(fallback.system1_response).toBeDefined(); expect(fallback.system1_response.content).toBe("test input"); expect(fallback.system2_response).toBeNull(); expect(fallback.conflict_detected).toBe(false); expect(fallback.resolution_strategy).toBe("fallback_system1_only"); } }); it("should return null for unknown components", async () => { const result = await ErrorHandler.handleError( "Unknown component failed", "UnknownComponent", {}, { enableFallbacks: true } ); if (result.canContinue) { expect(result.fallbackData).toBeNull(); } }); }); describe("Error statistics and tracking", () => { it("should track error statistics correctly", async () => { await ErrorHandler.handleError(new Error("Error 1"), "Component1"); await ErrorHandler.handleError(new Error("Error 2"), "Component1"); await ErrorHandler.handleError(new Error("Error 3"), "Component2"); const stats = ErrorHandler.getErrorStatistics(); expect(stats.Component1).toBeDefined(); expect(stats.Component1.total).toBe(2); expect(stats.Component2).toBeDefined(); expect(stats.Component2.total).toBe(1); }); it("should categorize errors by severity in statistics", async () => { await ErrorHandler.handleError( new Error("Out of memory"), "TestComponent" ); await ErrorHandler.handleError( new Error("Validation failed"), "TestComponent" ); await ErrorHandler.handleError( new Error("Processing timeout"), "TestComponent" ); const stats = ErrorHandler.getErrorStatistics(); const componentStats = stats.TestComponent; expect( componentStats.by_severity[ErrorSeverity.CRITICAL] ).toBeGreaterThan(0); expect(componentStats.by_severity[ErrorSeverity.MEDIUM]).toBeGreaterThan( 0 ); }); it("should clear error history for specific component", async () => { await ErrorHandler.handleError(new Error("Error 1"), "Component1"); await ErrorHandler.handleError(new Error("Error 2"), "Component2"); ErrorHandler.clearErrorHistory("Component1"); const stats = ErrorHandler.getErrorStatistics(); expect(stats.Component1).toBeUndefined(); expect(stats.Component2).toBeDefined(); }); it("should clear all error history", async () => { await ErrorHandler.handleError(new Error("Error 1"), "Component1"); await ErrorHandler.handleError(new Error("Error 2"), "Component2"); ErrorHandler.clearErrorHistory(); const stats = ErrorHandler.getErrorStatistics(); expect(Object.keys(stats)).toHaveLength(0); }); it("should prevent graceful degradation with too many recent errors", async () => { // Simulate many recent errors const promises = []; for (let i = 0; i < 6; i++) { promises.push( ErrorHandler.handleError(new Error(`Error ${i}`), "TestComponent") ); } await Promise.all(promises); // Next error should not allow graceful degradation const result = await ErrorHandler.handleError( new Error("Another error"), "TestComponent" ); expect(result.canContinue).toBe(false); }); }); describe("Error context and logging", () => { it("should handle errors with context information", async () => { const context = { user_id: "123", operation: "test_operation", timestamp: Date.now(), }; const result = await ErrorHandler.handleError( new Error("Context error"), "TestComponent", context ); expect(result.canContinue).toBeDefined(); // Context should be recorded in error tracking const stats = ErrorHandler.getErrorStatistics(); expect(stats.TestComponent).toBeDefined(); }); it("should handle various error types", async () => { const errors = [ new TypeError("Type error"), new ReferenceError("Reference error"), new RangeError("Range error"), new Error("Generic error"), ]; for (const error of errors) { const result = await ErrorHandler.handleError(error, "TestComponent"); expect(result.canContinue).toBeDefined(); } const stats = ErrorHandler.getErrorStatistics(); expect(stats.TestComponent.total).toBe(4); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ThoughtMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server