Skip to main content
Glama
errors.test.ts12.7 kB
import { describe, it, expect } from '@jest/globals'; import { RepositoryError, NotFoundError, ValidationError, ConflictError, TransactionError, LockError, StorageError, QueryError, IndexError, BulkOperationError, MigrationError, isRepositoryError, isErrorType, extractErrorInfo, } from '../../../src/domain/repositories/errors.js'; describe('Repository Error System', () => { describe('RepositoryError', () => { it('should create base repository error', () => { const error = new RepositoryError('Test error', 'TEST_CODE', { foo: 'bar' }); expect(error).toBeInstanceOf(Error); expect(error).toBeInstanceOf(RepositoryError); expect(error.name).toBe('RepositoryError'); expect(error.message).toBe('Test error'); expect(error.code).toBe('TEST_CODE'); expect(error.details).toEqual({ foo: 'bar' }); }); it('should serialize to JSON', () => { const error = new RepositoryError('Test error', 'TEST_CODE', { foo: 'bar' }); const json = error.toJSON(); expect(json.name).toBe('RepositoryError'); expect(json.message).toBe('Test error'); expect(json.code).toBe('TEST_CODE'); expect(json.details).toEqual({ foo: 'bar' }); expect(json.stack).toBeDefined(); }); it('should work without details', () => { const error = new RepositoryError('Test error', 'TEST_CODE'); expect(error.details).toBeUndefined(); }); }); describe('NotFoundError', () => { it('should create not found error with entity info', () => { const error = new NotFoundError('Requirement', 'req-123'); expect(error).toBeInstanceOf(NotFoundError); expect(error).toBeInstanceOf(RepositoryError); expect(error.name).toBe('NotFoundError'); expect(error.message).toBe("Requirement with ID 'req-123' not found"); expect(error.code).toBe('NOT_FOUND'); expect(error.details).toEqual({ entityType: 'Requirement', entityId: 'req-123', }); }); it('should include additional details', () => { const error = new NotFoundError('Phase', 'phase-456', { planId: 'plan-1' }); expect(error.details).toEqual({ entityType: 'Phase', entityId: 'phase-456', planId: 'plan-1', }); }); }); describe('ValidationError', () => { it('should create validation error with error list', () => { const errors = [ { field: 'title', message: 'Title is required' }, { field: 'priority', message: 'Invalid priority value', value: 'invalid' }, ]; const error = new ValidationError('Validation failed', errors); expect(error).toBeInstanceOf(ValidationError); expect(error.name).toBe('ValidationError'); expect(error.message).toBe('Validation failed'); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.errors).toEqual(errors); }); it('should include additional details', () => { const errors = [{ field: 'status', message: 'Invalid status' }]; const error = new ValidationError('Validation failed', errors, { entityType: 'Solution' }); expect(error.details).toMatchObject({ errors, entityType: 'Solution', }); }); }); describe('ConflictError', () => { it('should create conflict error with conflict type', () => { const error = new ConflictError('Entity already exists', 'duplicate'); expect(error).toBeInstanceOf(ConflictError); expect(error.name).toBe('ConflictError'); expect(error.message).toBe('Entity already exists'); expect(error.code).toBe('CONFLICT'); expect(error.conflictType).toBe('duplicate'); }); it('should support all conflict types', () => { const types: ('duplicate' | 'version' | 'constraint' | 'state')[] = ['duplicate', 'version', 'constraint', 'state']; types.forEach(type => { const error = new ConflictError(`Conflict: ${type}`, type); expect(error.conflictType).toBe(type); }); }); it('should include version info for version conflicts', () => { const error = new ConflictError( 'Version mismatch', 'version', { expected: 1, actual: 2 } ); expect(error.details).toMatchObject({ conflictType: 'version', expected: 1, actual: 2, }); }); }); describe('TransactionError', () => { it('should create transaction error with operation', () => { const error = new TransactionError('Failed to commit', 'commit'); expect(error).toBeInstanceOf(TransactionError); expect(error.name).toBe('TransactionError'); expect(error.code).toBe('TRANSACTION_ERROR'); expect(error.operation).toBe('commit'); }); it('should support all operation types', () => { const operations: ('begin' | 'commit' | 'rollback')[] = ['begin', 'commit', 'rollback']; operations.forEach(op => { const error = new TransactionError(`Failed to ${op}`, op); expect(error.operation).toBe(op); }); }); }); describe('LockError', () => { it('should create lock error with lock type', () => { const error = new LockError('Failed to acquire lock', 'acquire'); expect(error).toBeInstanceOf(LockError); expect(error.name).toBe('LockError'); expect(error.code).toBe('LOCK_ERROR'); expect(error.lockType).toBe('acquire'); }); it('should support all lock types', () => { const types: ('acquire' | 'release' | 'timeout' | 'deadlock')[] = ['acquire', 'release', 'timeout', 'deadlock']; types.forEach(type => { const error = new LockError(`Lock ${type} error`, type); expect(error.lockType).toBe(type); }); }); it('should include timeout info for timeout errors', () => { const error = new LockError('Lock timeout', 'timeout', { timeout: 5000, entityId: 'entity-1', }); expect(error.details).toMatchObject({ lockType: 'timeout', timeout: 5000, entityId: 'entity-1', }); }); }); describe('StorageError', () => { it('should create storage error with storage type', () => { const error = new StorageError('File system error', 'file'); expect(error).toBeInstanceOf(StorageError); expect(error.name).toBe('StorageError'); expect(error.code).toBe('STORAGE_ERROR'); expect(error.storageType).toBe('file'); }); it('should include cause error', () => { const cause = new Error('ENOENT: file not found'); const error = new StorageError('Storage failed', 'sqlite', cause); expect(error.cause).toBe(cause); expect(error.details).toMatchObject({ storageType: 'sqlite', cause: 'ENOENT: file not found', }); }); }); describe('QueryError', () => { it('should create query error with query type', () => { const error = new QueryError('Invalid filter', 'filter'); expect(error).toBeInstanceOf(QueryError); expect(error.name).toBe('QueryError'); expect(error.code).toBe('QUERY_ERROR'); expect(error.queryType).toBe('filter'); }); it('should support all query types', () => { const types: ('filter' | 'sort' | 'pagination' | 'syntax')[] = ['filter', 'sort', 'pagination', 'syntax']; types.forEach(type => { const error = new QueryError(`Query ${type} error`, type); expect(error.queryType).toBe(type); }); }); }); describe('IndexError', () => { it('should create index error with operation', () => { const error = new IndexError('Index creation failed', 'create'); expect(error).toBeInstanceOf(IndexError); expect(error.name).toBe('IndexError'); expect(error.code).toBe('INDEX_ERROR'); expect(error.operation).toBe('create'); }); it('should support all operation types', () => { const operations: ('create' | 'update' | 'delete' | 'rebuild')[] = ['create', 'update', 'delete', 'rebuild']; operations.forEach(op => { const error = new IndexError(`Index ${op} failed`, op); expect(error.operation).toBe(op); }); }); }); describe('BulkOperationError', () => { it('should create bulk operation error with statistics', () => { const failures = [ { index: 0, error: new Error('Failed'), operation: 'create' as const }, { index: 2, error: new Error('Failed'), operation: 'update' as const }, ]; const error = new BulkOperationError('Bulk operation failed', 3, 2, failures); expect(error).toBeInstanceOf(BulkOperationError); expect(error.name).toBe('BulkOperationError'); expect(error.code).toBe('BULK_OPERATION_ERROR'); expect(error.successCount).toBe(3); expect(error.failureCount).toBe(2); expect(error.failures).toEqual(failures); }); it('should include entity IDs in failures', () => { const failures = [ { entityId: 'entity-1', index: 0, error: new Error('Failed'), operation: 'delete' as const }, ]; const error = new BulkOperationError('Delete failed', 0, 1, failures); expect(error.failures[0].entityId).toBe('entity-1'); }); }); describe('MigrationError', () => { it('should create migration error with version and direction', () => { const error = new MigrationError('Migration failed', '2.0.0', 'up'); expect(error).toBeInstanceOf(MigrationError); expect(error.name).toBe('MigrationError'); expect(error.code).toBe('MIGRATION_ERROR'); expect(error.migrationVersion).toBe('2.0.0'); expect(error.direction).toBe('up'); }); it('should support both directions', () => { const upError = new MigrationError('Migration up failed', '2.0.0', 'up'); const downError = new MigrationError('Migration down failed', '1.0.0', 'down'); expect(upError.direction).toBe('up'); expect(downError.direction).toBe('down'); }); }); describe('isRepositoryError', () => { it('should return true for repository errors', () => { expect(isRepositoryError(new RepositoryError('test', 'TEST'))).toBe(true); expect(isRepositoryError(new NotFoundError('Entity', 'id'))).toBe(true); expect(isRepositoryError(new ValidationError('test', []))).toBe(true); }); it('should return false for non-repository errors', () => { expect(isRepositoryError(new Error('test'))).toBe(false); expect(isRepositoryError('not an error')).toBe(false); expect(isRepositoryError(null)).toBe(false); expect(isRepositoryError(undefined)).toBe(false); }); }); describe('isErrorType', () => { it('should correctly identify specific error types', () => { const notFoundError = new NotFoundError('Entity', 'id'); const validationError = new ValidationError('test', []); expect(isErrorType(notFoundError, NotFoundError)).toBe(true); expect(isErrorType(notFoundError, ValidationError)).toBe(false); expect(isErrorType(validationError, ValidationError)).toBe(true); expect(isErrorType(validationError, NotFoundError)).toBe(false); }); it('should return false for non-errors', () => { expect(isErrorType('not an error', NotFoundError)).toBe(false); expect(isErrorType(null, ValidationError)).toBe(false); }); }); describe('extractErrorInfo', () => { it('should extract info from repository errors', () => { const error = new NotFoundError('Entity', 'id-123'); const info = extractErrorInfo(error); expect(info.name).toBe('NotFoundError'); expect(info.message).toContain('id-123'); expect(info.code).toBe('NOT_FOUND'); expect(info.details).toBeDefined(); expect(info.stack).toBeDefined(); }); it('should extract info from regular errors', () => { const error = new Error('Regular error'); const info = extractErrorInfo(error); expect(info.name).toBe('Error'); expect(info.message).toBe('Regular error'); expect(info.code).toBeUndefined(); expect(info.stack).toBeDefined(); }); it('should handle non-error values', () => { const info1 = extractErrorInfo('string error'); expect(info1.name).toBe('UnknownError'); expect(info1.message).toBe('string error'); const info2 = extractErrorInfo(null); expect(info2.name).toBe('UnknownError'); expect(info2.message).toBe('null'); const info3 = extractErrorInfo({ custom: 'object' }); expect(info3.name).toBe('UnknownError'); expect(info3.message).toBe('[object Object]'); }); }); });

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/cppmyjob/cpp-mcp-planner'

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