import { describe, it, expect } from 'vitest'; import { ApplicationErrorCode } from './ApplicationErrorCode'; describe('ApplicationErrorCode', () => { describe('ApplicationErrorCode type', () => { it('should create error code with code only', () => { const errorCode: ApplicationErrorCode<'USER_NOT_FOUND'> = { code: 'USER_NOT_FOUND' }; expect(errorCode.code).toBe('USER_NOT_FOUND'); }); it('should create error code with code and details', () => { const errorCode: ApplicationErrorCode<'INSUFFICIENT_FUNDS', { balance: number; required: number }> = { code: 'INSUFFICIENT_FUNDS', details: { balance: 50, required: 100 } }; expect(errorCode.code).toBe('INSUFFICIENT_FUNDS'); expect(errorCode.details).toEqual({ balance: 50, required: 100 }); }); it('should support different error code types', () => { const notFoundCode: ApplicationErrorCode<'USER_NOT_FOUND'> = { code: 'USER_NOT_FOUND' }; const validationCode: ApplicationErrorCode<'VALIDATION_ERROR', { field: string }> = { code: 'VALIDATION_ERROR', details: { field: 'email' } }; const permissionCode: ApplicationErrorCode<'PERMISSION_DENIED', { resource: string }> = { code: 'PERMISSION_DENIED', details: { resource: 'admin-panel' } }; expect(notFoundCode.code).toBe('USER_NOT_FOUND'); expect(validationCode.code).toBe('VALIDATION_ERROR'); expect(validationCode.details).toEqual({ field: 'email' }); expect(permissionCode.code).toBe('PERMISSION_DENIED'); expect(permissionCode.details).toEqual({ resource: 'admin-panel' }); }); it('should support complex details types', () => { interface PaymentErrorDetails { amount: number; currency: string; retryAfter?: number; attempts: number; } const paymentErrorCode: ApplicationErrorCode<'PAYMENT_FAILED', PaymentErrorDetails> = { code: 'PAYMENT_FAILED', details: { amount: 100, currency: 'USD', retryAfter: 60, attempts: 3 } }; expect(paymentErrorCode.code).toBe('PAYMENT_FAILED'); expect(paymentErrorCode.details).toEqual({ amount: 100, currency: 'USD', retryAfter: 60, attempts: 3 }); }); it('should support optional details', () => { const errorCodeWithDetails: ApplicationErrorCode<'ERROR', { message: string }> = { code: 'ERROR', details: { message: 'Something went wrong' } }; const errorCodeWithoutDetails: ApplicationErrorCode<'ERROR', undefined> = { code: 'ERROR' }; expect(errorCodeWithDetails.code).toBe('ERROR'); expect(errorCodeWithDetails.details).toEqual({ message: 'Something went wrong' }); expect(errorCodeWithoutDetails.code).toBe('ERROR'); }); }); describe('ApplicationErrorCode behavior', () => { it('should be assignable to Result error type', () => { // ApplicationErrorCode is designed to be used with Result type // This test verifies the type compatibility type MyErrorCodes = 'USER_NOT_FOUND' | 'VALIDATION_ERROR' | 'PERMISSION_DENIED'; const userNotFound: ApplicationErrorCode = { code: 'USER_NOT_FOUND' }; const validationError: ApplicationErrorCode = { code: 'VALIDATION_ERROR', details: { field: 'email' } }; const permissionError: ApplicationErrorCode = { code: 'PERMISSION_DENIED', details: { resource: 'admin-panel' } }; expect(userNotFound.code).toBe('USER_NOT_FOUND'); expect(validationError.code).toBe('VALIDATION_ERROR'); expect(validationError.details).toEqual({ field: 'email' }); expect(permissionError.code).toBe('PERMISSION_DENIED'); expect(permissionError.details).toEqual({ resource: 'admin-panel' }); }); it('should support error code patterns', () => { // Common error code patterns const notFoundPattern: ApplicationErrorCode<'NOT_FOUND', { resource: string; id?: string }> = { code: 'NOT_FOUND', details: { resource: 'user', id: '123' } }; const conflictPattern: ApplicationErrorCode<'CONFLICT', { resource: string; existingId: string }> = { code: 'CONFLICT', details: { resource: 'order', existingId: '456' } }; const validationPattern: ApplicationErrorCode<'VALIDATION_ERROR', { field: string; value: unknown; reason: string }> = { code: 'VALIDATION_ERROR', details: { field: 'email', value: 'invalid', reason: 'must contain @' } }; expect(notFoundPattern.code).toBe('NOT_FOUND'); expect(notFoundPattern.details).toEqual({ resource: 'user', id: '123' }); expect(conflictPattern.code).toBe('CONFLICT'); expect(conflictPattern.details).toEqual({ resource: 'order', existingId: '456' }); expect(validationPattern.code).toBe('VALIDATION_ERROR'); expect(validationPattern.details).toEqual({ field: 'email', value: 'invalid', reason: 'must contain @' }); }); it('should support error code with metadata', () => { interface ErrorMetadata { timestamp: string; requestId?: string; userId?: string; sessionId?: string; } const errorCode: ApplicationErrorCode<'AUTH_ERROR', ErrorMetadata> = { code: 'AUTH_ERROR', details: { timestamp: new Date().toISOString(), requestId: 'req-123', userId: 'user-456', sessionId: 'session-789' } }; expect(errorCode.code).toBe('AUTH_ERROR'); expect(errorCode.details).toBeDefined(); expect(errorCode.details?.timestamp).toBeDefined(); expect(errorCode.details?.requestId).toBe('req-123'); }); it('should support error code with retry information', () => { interface RetryInfo { retryAfter: number; maxRetries: number; currentAttempt: number; } const retryableError: ApplicationErrorCode<'RATE_LIMIT_EXCEEDED', RetryInfo> = { code: 'RATE_LIMIT_EXCEEDED', details: { retryAfter: 60, maxRetries: 3, currentAttempt: 1 } }; expect(retryableError.code).toBe('RATE_LIMIT_EXCEEDED'); expect(retryableError.details).toEqual({ retryAfter: 60, maxRetries: 3, currentAttempt: 1 }); }); it('should support error code with validation details', () => { interface ValidationErrorDetails { field: string; value: unknown; constraints: string[]; message: string; } const validationError: ApplicationErrorCode<'VALIDATION_ERROR', ValidationErrorDetails> = { code: 'VALIDATION_ERROR', details: { field: 'email', value: 'invalid-email', constraints: ['must be a valid email', 'must not be empty'], message: 'Email validation failed' } }; expect(validationError.code).toBe('VALIDATION_ERROR'); expect(validationError.details).toEqual({ field: 'email', value: 'invalid-email', constraints: ['must be a valid email', 'must not be empty'], message: 'Email validation failed' }); }); }); describe('ApplicationErrorCode implementation patterns', () => { it('should support error code factory pattern', () => { function createErrorCode( code: Code, details?: Details ): ApplicationErrorCode { return details ? { code, details } : { code }; } const notFound = createErrorCode('USER_NOT_FOUND'); const validation = createErrorCode('VALIDATION_ERROR', { field: 'email' }); const permission = createErrorCode('PERMISSION_DENIED', { resource: 'admin' }); expect(notFound.code).toBe('USER_NOT_FOUND'); expect(validation.code).toBe('VALIDATION_ERROR'); expect(validation.details).toEqual({ field: 'email' }); expect(permission.code).toBe('PERMISSION_DENIED'); expect(permission.details).toEqual({ resource: 'admin' }); }); it('should support error code builder pattern', () => { class ErrorCodeBuilder { private code: Code = '' as Code; private details?: Details; withCode(code: Code): this { this.code = code; return this; } withDetails(details: Details): this { this.details = details; return this; } build(): ApplicationErrorCode { return this.details ? { code: this.code, details: this.details } : { code: this.code }; } } const errorCode = new ErrorCodeBuilder<'USER_NOT_FOUND'>() .withCode('USER_NOT_FOUND') .build(); const errorCodeWithDetails = new ErrorCodeBuilder<'VALIDATION_ERROR', { field: string }>() .withCode('VALIDATION_ERROR') .withDetails({ field: 'email' }) .build(); expect(errorCode.code).toBe('USER_NOT_FOUND'); expect(errorCodeWithDetails.code).toBe('VALIDATION_ERROR'); expect(errorCodeWithDetails.details).toEqual({ field: 'email' }); }); it('should support error code categorization', () => { const errorCodes: ApplicationErrorCode[] = [ { code: 'USER_NOT_FOUND' }, { code: 'VALIDATION_ERROR', details: { field: 'email' } }, { code: 'PERMISSION_DENIED', details: { resource: 'admin' } }, { code: 'NETWORK_ERROR' } ]; const notFoundCodes = errorCodes.filter(e => e.code === 'USER_NOT_FOUND'); const validationCodes = errorCodes.filter(e => e.code === 'VALIDATION_ERROR'); const permissionCodes = errorCodes.filter(e => e.code === 'PERMISSION_DENIED'); const networkCodes = errorCodes.filter(e => e.code === 'NETWORK_ERROR'); expect(notFoundCodes).toHaveLength(1); expect(validationCodes).toHaveLength(1); expect(permissionCodes).toHaveLength(1); expect(networkCodes).toHaveLength(1); }); it('should support error code with complex details', () => { interface ComplexErrorDetails { error: { code: string; message: string; stack?: string; }; context: { service: string; operation: string; timestamp: string; }; metadata: { retryCount: number; timeout: number; }; } const complexError: ApplicationErrorCode<'SYSTEM_ERROR', ComplexErrorDetails> = { code: 'SYSTEM_ERROR', details: { error: { code: 'E001', message: 'System failure', stack: 'Error stack trace...' }, context: { service: 'payment-service', operation: 'processPayment', timestamp: new Date().toISOString() }, metadata: { retryCount: 3, timeout: 5000 } } }; expect(complexError.code).toBe('SYSTEM_ERROR'); expect(complexError.details).toBeDefined(); expect(complexError.details?.error.code).toBe('E001'); expect(complexError.details?.context.service).toBe('payment-service'); expect(complexError.details?.metadata.retryCount).toBe(3); }); }); });