209 lines
No EOL
6.3 KiB
TypeScript
209 lines
No EOL
6.3 KiB
TypeScript
import { beforeEach, describe, expect, it, mock } from 'bun:test';
|
|
import { SimpleEventBus } from '../src/simple-event-bus';
|
|
import type { EventHandler, EventSubscription, EventBusMessage } from '../src/types';
|
|
|
|
describe('EventBus', () => {
|
|
let eventBus: SimpleEventBus;
|
|
|
|
beforeEach(() => {
|
|
eventBus = new SimpleEventBus();
|
|
});
|
|
|
|
describe('subscribe', () => {
|
|
it('should subscribe to events', () => {
|
|
const handler: EventHandler = mock(async () => {});
|
|
|
|
const subscription = eventBus.subscribe('test-event', handler);
|
|
|
|
expect(subscription).toBeDefined();
|
|
expect(subscription.channel).toBe('test-event');
|
|
expect(subscription.handler).toBe(handler);
|
|
});
|
|
|
|
it('should allow multiple subscribers to same event', () => {
|
|
const handler1 = mock(async () => {});
|
|
const handler2 = mock(async () => {});
|
|
|
|
const sub1 = eventBus.subscribe('event', handler1);
|
|
const sub2 = eventBus.subscribe('event', handler2);
|
|
|
|
expect(sub1.handler).toBe(handler1);
|
|
expect(sub2.handler).toBe(handler2);
|
|
});
|
|
|
|
it('should support pattern subscriptions', () => {
|
|
const handler = mock(async () => {});
|
|
|
|
const subscription = eventBus.subscribe('user.*', handler);
|
|
|
|
expect(subscription.channel).toBe('user.*');
|
|
});
|
|
});
|
|
|
|
describe('unsubscribe', () => {
|
|
it('should unsubscribe by subscription object', () => {
|
|
const handler = mock(async () => {});
|
|
const subscription = eventBus.subscribe('event', handler);
|
|
|
|
const result = eventBus.unsubscribe(subscription);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should unsubscribe by id', () => {
|
|
const handler = mock(async () => {});
|
|
eventBus.subscribe('event', handler);
|
|
|
|
// We'll use the subscription object method since we don't expose IDs
|
|
const result = eventBus.unsubscribe('sub-1');
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should return false for non-existent subscription', () => {
|
|
const result = eventBus.unsubscribe('non-existent');
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('publish', () => {
|
|
it('should publish events to subscribers', async () => {
|
|
const handler = mock(async (message: EventBusMessage) => {});
|
|
eventBus.subscribe('event', handler);
|
|
|
|
await eventBus.publish('event', { data: 'test' });
|
|
|
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
const message = handler.mock.calls[0][0];
|
|
expect(message.type).toBe('event');
|
|
expect(message.data).toEqual({ data: 'test' });
|
|
});
|
|
|
|
it('should publish to multiple subscribers', async () => {
|
|
const handler1 = mock(async () => {});
|
|
const handler2 = mock(async () => {});
|
|
eventBus.subscribe('event', handler1);
|
|
eventBus.subscribe('event', handler2);
|
|
|
|
await eventBus.publish('event', { data: 'test' });
|
|
|
|
expect(handler1).toHaveBeenCalledTimes(1);
|
|
expect(handler2).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should match pattern subscriptions', async () => {
|
|
const handler = mock(async () => {});
|
|
eventBus.subscribe('user.*', handler);
|
|
|
|
await eventBus.publish('user.created', { userId: '123' });
|
|
await eventBus.publish('user.updated', { userId: '123' });
|
|
await eventBus.publish('order.created', { orderId: '456' });
|
|
|
|
expect(handler).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it('should handle errors in handlers gracefully', async () => {
|
|
const errorHandler = mock(async () => {
|
|
throw new Error('Handler error');
|
|
});
|
|
const successHandler = mock(async () => {});
|
|
|
|
eventBus.subscribe('event', errorHandler);
|
|
eventBus.subscribe('event', successHandler);
|
|
|
|
await eventBus.publish('event', { data: 'test' });
|
|
|
|
expect(errorHandler).toHaveBeenCalledTimes(1);
|
|
expect(successHandler).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe('publishSync', () => {
|
|
it('should publish synchronously', () => {
|
|
const handler = mock((message: EventBusMessage) => {});
|
|
eventBus.subscribe('event', handler);
|
|
|
|
eventBus.publishSync('event', { data: 'test' });
|
|
|
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
const message = handler.mock.calls[0][0];
|
|
expect(message.type).toBe('event');
|
|
expect(message.data).toEqual({ data: 'test' });
|
|
});
|
|
});
|
|
|
|
describe('once', () => {
|
|
it('should subscribe for single event', async () => {
|
|
const handler = mock(async () => {});
|
|
eventBus.once('event', handler);
|
|
|
|
await eventBus.publish('event', { data: 'first' });
|
|
await eventBus.publish('event', { data: 'second' });
|
|
|
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe('off', () => {
|
|
it('should remove all handlers for event', async () => {
|
|
const handler1 = mock(async () => {});
|
|
const handler2 = mock(async () => {});
|
|
eventBus.subscribe('event', handler1);
|
|
eventBus.subscribe('event', handler2);
|
|
|
|
eventBus.off('event');
|
|
|
|
await eventBus.publish('event', { data: 'test' });
|
|
|
|
expect(handler1).not.toHaveBeenCalled();
|
|
expect(handler2).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should remove specific handler', async () => {
|
|
const handler1 = mock(async () => {});
|
|
const handler2 = mock(async () => {});
|
|
eventBus.subscribe('event', handler1);
|
|
eventBus.subscribe('event', handler2);
|
|
|
|
eventBus.off('event', handler1);
|
|
|
|
await eventBus.publish('event', { data: 'test' });
|
|
|
|
expect(handler1).not.toHaveBeenCalled();
|
|
expect(handler2).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe('hasSubscribers', () => {
|
|
it('should check for subscribers', () => {
|
|
expect(eventBus.hasSubscribers('event')).toBe(false);
|
|
|
|
const handler = mock(async () => {});
|
|
eventBus.subscribe('event', handler);
|
|
|
|
expect(eventBus.hasSubscribers('event')).toBe(true);
|
|
|
|
eventBus.off('event');
|
|
|
|
expect(eventBus.hasSubscribers('event')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('clear', () => {
|
|
it('should clear all subscriptions', async () => {
|
|
const handler1 = mock(async () => {});
|
|
const handler2 = mock(async () => {});
|
|
eventBus.subscribe('event1', handler1);
|
|
eventBus.subscribe('event2', handler2);
|
|
|
|
eventBus.clear();
|
|
|
|
await eventBus.publish('event1', {});
|
|
await eventBus.publish('event2', {});
|
|
|
|
expect(handler1).not.toHaveBeenCalled();
|
|
expect(handler2).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
}); |