import { EventBus } from '@common/EventBus'; describe('EventBus', () => { let bus: EventBus; beforeEach(() => { bus = new EventBus(); }); it('delivers emitted payload to on() subscribers', () => { const spy = jest.fn(); bus.on('hit', spy); bus.emit('hit', 42); expect(spy).toHaveBeenCalledWith(42); }); it('ignores duplicate subscriptions of the same handler', () => { const spy = jest.fn(); bus.on('hit', spy); bus.on('hit', spy); bus.emit('hit', 1); expect(spy).toHaveBeenCalledTimes(1); expect(bus.listenerCount('hit')).toBe(1); }); it('fires once() handlers exactly one time', () => { const spy = jest.fn(); bus.once('hit', spy); bus.emit('hit', 1); bus.emit('hit', 2); expect(spy).toHaveBeenCalledTimes(1); expect(bus.listenerCount('hit')).toBe(0); }); it('off(event, fn) removes only that handler', () => { const a = jest.fn(); const b = jest.fn(); bus.on('hit', a); bus.on('hit', b); bus.off('hit', a); bus.emit('hit', 1); expect(a).not.toHaveBeenCalled(); expect(b).toHaveBeenCalledTimes(1); }); it('off(event) clears all handlers of that event', () => { const a = jest.fn(); const b = jest.fn(); bus.on('hit', a); bus.on('hit', b); bus.off('hit'); bus.emit('hit', 1); expect(a).not.toHaveBeenCalled(); expect(b).not.toHaveBeenCalled(); expect(bus.listenerCount('hit')).toBe(0); }); it('isolates exceptions — one bad listener does not break fan-out', () => { const err = jest.fn(); bus.setErrorHook(err); const good = jest.fn(); bus.on('hit', () => { throw new Error('boom'); }); bus.on('hit', good); bus.emit('hit', 1); expect(good).toHaveBeenCalledTimes(1); expect(err).toHaveBeenCalledTimes(1); expect(err.mock.calls[0][0]).toBe('hit'); }); it('emit on an unknown event is a no-op', () => { expect(() => bus.emit('ghost', 1)).not.toThrow(); }); it('clear() drops every handler of every event', () => { bus.on('a', () => {}); bus.on('b', () => {}); bus.clear(); expect(bus.listenerCount('a')).toBe(0); expect(bus.listenerCount('b')).toBe(0); }); it('supports off for a non-existent handler without error', () => { const spy = jest.fn(); bus.off('hit', spy); expect(bus.listenerCount('hit')).toBe(0); }); it('handles a once-handler unsubscribing itself during emit', () => { const calls: number[] = []; bus.once('tick', (n) => calls.push(n)); bus.on('tick', (n) => calls.push(n * 10)); bus.emit('tick', 1); bus.emit('tick', 2); expect(calls).toEqual([1, 10, 20]); }); });