From 600377151e0e37af050d9e19517f1f7de6281f8a Mon Sep 17 00:00:00 2001 From: Tony Casey Date: Thu, 12 Feb 2026 21:16:47 +0000 Subject: [PATCH] test: complete unit test coverage for DI container and EventBus (GIT-55) Add missing test cases: - EventBus: logger.warn called on handler failure with event/handler context - EventBus: explicit no-logger safety test (no crash on failure) - Container: memoryContextLoader and contextFormatter resolution checks - Container: hook services expose expected interface methods Co-Authored-By: Claude Opus 4.6 --- .../unit/infrastructure/di/container.test.ts | 13 +++++++ .../infrastructure/events/EventBus.test.ts | 39 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/tests/unit/infrastructure/di/container.test.ts b/tests/unit/infrastructure/di/container.test.ts index d83a381e..65b10a60 100644 --- a/tests/unit/infrastructure/di/container.test.ts +++ b/tests/unit/infrastructure/di/container.test.ts @@ -47,6 +47,8 @@ describe('createContainer', () => { assert.ok(cradle.contextService); assert.ok(cradle.liberateService); assert.ok(cradle.sessionCaptureService); + assert.ok(cradle.memoryContextLoader); + assert.ok(cradle.contextFormatter); }); it('should return singletons within container scope', () => { @@ -160,6 +162,17 @@ describe('createContainer', () => { }); }); + describe('hook services', () => { + it('should resolve hook services with expected interfaces', () => { + const container = createContainer(); + const { memoryContextLoader, contextFormatter, sessionCaptureService } = container.cradle; + + assert.equal(typeof memoryContextLoader.load, 'function'); + assert.equal(typeof contextFormatter.format, 'function'); + assert.equal(typeof sessionCaptureService.capture, 'function'); + }); + }); + describe('service wiring', () => { it('should wire memoryService to use correct repository', () => { const container = createContainer(); diff --git a/tests/unit/infrastructure/events/EventBus.test.ts b/tests/unit/infrastructure/events/EventBus.test.ts index 872e9bed..70dc9886 100644 --- a/tests/unit/infrastructure/events/EventBus.test.ts +++ b/tests/unit/infrastructure/events/EventBus.test.ts @@ -8,6 +8,7 @@ import { EventBus } from '../../../../src/infrastructure/events/EventBus'; import type { HookEvent } from '../../../../src/domain/events/HookEvents'; import type { IEventHandler } from '../../../../src/domain/interfaces/IEventHandler'; import type { IEventResult } from '../../../../src/domain/interfaces/IEventResult'; +import type { ILogger } from '../../../../src/domain/interfaces/ILogger'; function createSessionStartEvent(overrides?: Partial): HookEvent { return { @@ -131,6 +132,44 @@ describe('EventBus', () => { assert.deepEqual(results, []); }); + + it('should log warning when handler fails', async () => { + const warnCalls: { message: string; context?: Record }[] = []; + const mockLogger: ILogger = { + trace: () => {}, + debug: () => {}, + info: () => {}, + warn: (message: string, context?: Record) => { + warnCalls.push({ message, context }); + }, + error: () => {}, + fatal: () => {}, + child: () => mockLogger, + isLevelEnabled: () => true, + }; + + const bus = new EventBus(mockLogger); + bus.on('session:start', createFailingHandler('BrokenHandler', new Error('oops'))); + + await bus.emit(createSessionStartEvent()); + + assert.equal(warnCalls.length, 1); + assert.equal(warnCalls[0].message, 'Event handler failed'); + assert.equal(warnCalls[0].context?.event, 'session:start'); + assert.equal(warnCalls[0].context?.handler, 'BrokenHandler'); + assert.equal(warnCalls[0].context?.error, 'oops'); + }); + + it('should not crash without logger when handler fails', async () => { + const bus = new EventBus(); // no logger + bus.on('session:start', createFailingHandler('NoLogHandler', new Error('fail'))); + + const results = await bus.emit(createSessionStartEvent()); + + assert.equal(results.length, 1); + assert.equal(results[0].success, false); + assert.equal(results[0].handler, 'NoLogHandler'); + }); }); describe('on', () => {