Skip to main content
Glama
hiltonbrown

Next.js MCP Server Template

by hiltonbrown
error-handler.test.ts6.27 kB
// Unit tests for error handler import { errorHandler, ErrorType, ErrorSeverity } from '@/lib/error-handler'; describe('Error Handler', () => { beforeEach(() => { // Clear error log before each test errorHandler['errorLog'] = []; }); describe('Error Creation', () => { it('should create a user input error', () => { const error = errorHandler.createError( ErrorType.USER_INPUT, 'INVALID_EMAIL', 'Invalid email format', { severity: ErrorSeverity.LOW, statusCode: 400, requestId: 'test-request' } ); expect(error.type).toBe(ErrorType.USER_INPUT); expect(error.code).toBe('INVALID_EMAIL'); expect(error.message).toBe('Invalid email format'); expect(error.severity).toBe(ErrorSeverity.LOW); expect(error.statusCode).toBe(400); expect(error.requestId).toBe('test-request'); }); it('should use default user message for known error types', () => { const error = errorHandler.createError( ErrorType.AUTHENTICATION, 'TOKEN_EXPIRED', 'JWT token has expired' ); expect(error.userMessage).toBe('Authentication failed. Please sign in again.'); }); it('should use custom user message when provided', () => { const customMessage = 'Custom error message'; const error = errorHandler.createError( ErrorType.SYSTEM, 'INTERNAL_ERROR', 'Internal server error', { userMessage: customMessage } ); expect(error.userMessage).toBe(customMessage); }); }); describe('Xero Error Handling', () => { it('should handle Xero authentication errors', () => { const xeroError = { response: { status: 401, data: { Type: 'Unauthorized', Title: 'Unauthorized' } } }; const error = errorHandler.handleXeroError(xeroError, { requestId: 'test' }); expect(error.type).toBe(ErrorType.AUTHENTICATION); expect(error.code).toBe('XERO_UNAUTHORIZED'); expect(error.severity).toBe(ErrorSeverity.HIGH); expect(error.statusCode).toBe(401); }); it('should handle Xero rate limit errors', () => { const xeroError = { response: { status: 429, data: { Type: 'RateLimitError', Title: 'Rate limit exceeded' } } }; const error = errorHandler.handleXeroError(xeroError); expect(error.type).toBe(ErrorType.RATE_LIMIT); expect(error.code).toBe('XERO_RATE_LIMIT'); expect(error.retryable).toBe(true); expect(error.statusCode).toBe(429); }); it('should handle network errors', () => { const networkError = new Error('Connection timeout'); const error = errorHandler.handleXeroError(networkError); expect(error.type).toBe(ErrorType.NETWORK); expect(error.code).toBe('XERO_CONNECTION_ERROR'); expect(error.retryable).toBe(true); expect(error.statusCode).toBe(503); }); }); describe('Database Error Handling', () => { it('should handle Prisma unique constraint errors', () => { const dbError = { code: 'P2002', message: 'Unique constraint failed' }; const error = errorHandler.handleDatabaseError(dbError); expect(error.type).toBe(ErrorType.VALIDATION); expect(error.code).toBe('DB_UNIQUE_CONSTRAINT'); expect(error.statusCode).toBe(409); }); it('should handle database connection errors', () => { const dbError = { code: 'P1001', message: 'Database connection failed' }; const error = errorHandler.handleDatabaseError(dbError); expect(error.type).toBe(ErrorType.DATABASE); expect(error.code).toBe('DB_CONNECTION_ERROR'); expect(error.severity).toBe(ErrorSeverity.CRITICAL); expect(error.statusCode).toBe(503); }); }); describe('OAuth Error Handling', () => { it('should handle OAuth access denied', () => { const oauthError = { error: 'access_denied' }; const error = errorHandler.handleOAuthError(oauthError); expect(error.type).toBe(ErrorType.AUTHENTICATION); expect(error.code).toBe('OAUTH_ACCESS_DENIED'); expect(error.severity).toBe(ErrorSeverity.LOW); expect(error.retryable).toBe(false); }); it('should handle OAuth invalid request', () => { const oauthError = { error: 'invalid_request' }; const error = errorHandler.handleOAuthError(oauthError); expect(error.type).toBe(ErrorType.VALIDATION); expect(error.code).toBe('OAUTH_INVALID_REQUEST'); expect(error.statusCode).toBe(400); }); }); describe('Response Formatting', () => { it('should format error for HTTP response', () => { const error = errorHandler.createError( ErrorType.USER_INPUT, 'TEST_ERROR', 'Test error message' ); const response = errorHandler.toHTTPResponse(error); expect(response.status).toBe(500); expect(response.json.error.code).toBe('TEST_ERROR'); expect(response.json.error.message).toBe('An unexpected error occurred. Please try again.'); }); it('should format error for MCP response', () => { const error = errorHandler.createError( ErrorType.VALIDATION, 'MCP_INVALID_PARAMS', 'Invalid parameters' ); const response = errorHandler.toMCPResponse(error, 123); expect(response.jsonrpc).toBe('2.0'); expect(response.id).toBe(123); expect(response.error.code).toBe(-32602); // Invalid params expect(response.error.message).toBe('Please check your input and try again.'); }); }); describe('Error Statistics', () => { it('should track error statistics', () => { errorHandler.createError(ErrorType.DATABASE, 'DB_ERROR_1', 'Database error 1'); errorHandler.createError(ErrorType.DATABASE, 'DB_ERROR_2', 'Database error 2'); errorHandler.createError(ErrorType.NETWORK, 'NETWORK_ERROR', 'Network error'); const stats = errorHandler.getErrorStats(); expect(stats.total).toBe(3); expect(stats.byType[ErrorType.DATABASE]).toBe(2); expect(stats.byType[ErrorType.NETWORK]).toBe(1); expect(stats.recent).toHaveLength(3); }); }); });

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/hiltonbrown/xero-mcp-with-next-js'

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