import { loadConfig } from '../../src/shared/infrastructure/Config'; import { InProcessEventBus } from '../../src/shared/infrastructure/InProcessEventBus'; import { LocalStorageProvider } from '../../src/shared/infrastructure/StorageProvider'; import { createLogger } from '../../src/shared/infrastructure/Logger'; import { DomainEvent } from '../../src/shared/domain/DomainEvent'; import { randomUUID } from 'crypto'; import path from 'path'; import os from 'os'; import fs from 'fs'; // --- Config --- describe('Config', () => { it('loads with defaults when no env vars set', () => { const config = loadConfig(); expect(config.port).toBe(3001); expect(config.db.driver).toBe('sqlite'); expect(['development', 'test']).toContain(config.nodeEnv); }); it('picks up PORT env var', () => { process.env['ABE_PORT'] = '4000'; const config = loadConfig(); expect(config.port).toBe(4000); delete process.env['ABE_PORT']; }); }); // --- EventBus --- describe('InProcessEventBus', () => { const logger = createLogger({ level: 'silent', nodeEnv: 'test' }); it('publishes and subscribes to events', async () => { const bus = new InProcessEventBus(logger); const received: DomainEvent[] = []; bus.subscribe('test.event', { handle: async (event) => { received.push(event); }, }); const event: DomainEvent = { eventId: randomUUID(), eventName: 'test.event', aggregateId: 'agg-1', occurredOn: new Date(), payload: { foo: 'bar' }, }; await bus.publish(event); await new Promise(r => setTimeout(r, 10)); expect(received).toHaveLength(1); expect(received[0]?.aggregateId).toBe('agg-1'); }); it('does not crash when handler throws', async () => { const bus = new InProcessEventBus(logger); bus.subscribe('error.event', { handle: async () => { throw new Error('handler error'); }, }); const event: DomainEvent = { eventId: randomUUID(), eventName: 'error.event', aggregateId: 'agg-2', occurredOn: new Date(), payload: {}, }; await expect(bus.publish(event)).resolves.not.toThrow(); }); }); // --- StorageProvider --- describe('LocalStorageProvider', () => { let tmpDir: string; beforeEach(() => { tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'abe-test-')); }); afterEach(() => { fs.rmSync(tmpDir, { recursive: true, force: true }); }); it('saves and retrieves data', async () => { const storage = new LocalStorageProvider(tmpDir); const data = Buffer.from('hello world'); await storage.save('subdir/test.txt', data); const result = await storage.get('subdir/test.txt'); expect(result?.toString()).toBe('hello world'); }); it('returns null for missing file', async () => { const storage = new LocalStorageProvider(tmpDir); const result = await storage.get('nonexistent.txt'); expect(result).toBeNull(); }); it('exists returns true after save', async () => { const storage = new LocalStorageProvider(tmpDir); await storage.save('file.bin', Buffer.from([1, 2, 3])); expect(await storage.exists('file.bin')).toBe(true); expect(await storage.exists('other.bin')).toBe(false); }); it('delete removes file', async () => { const storage = new LocalStorageProvider(tmpDir); await storage.save('file.txt', Buffer.from('data')); await storage.delete('file.txt'); expect(await storage.exists('file.txt')).toBe(false); }); });