ga-pubsub
Version:
It establishes data communication within and between the application or systems using event-driven architecture
185 lines (123 loc) • 4.86 kB
JavaScript
const EventManager = require('./ga-pubsub');
describe('GA-PubSub (Multi-Tenant Enhanced EventManager)', () => {
let bus;
beforeEach(() => {
// isolate each test fully
EventManager.resetAll?.();
bus = EventManager.getEventingManagerInstance('test-tenant');
});
test('should subscribe to and publish an event', async () => {
const callback = jest.fn();
bus.subscribe('exampleEvent', callback);
await bus.publish('exampleEvent', { key: 'value' });
expect(callback).toHaveBeenCalledWith({ key: 'value' });
});
test('should handle multiple subscribers', async () => {
const cb1 = jest.fn();
const cb2 = jest.fn();
bus.subscribe('multiEvent', cb1);
bus.subscribe('multiEvent', cb2);
await bus.publish('multiEvent', 'data');
expect(cb1).toHaveBeenCalledWith('data');
expect(cb2).toHaveBeenCalledWith('data');
});
test('should not leak events across tenants', async () => {
const busA = EventManager.getEventingManagerInstance('A');
const busB = EventManager.getEventingManagerInstance('B');
const cbA = jest.fn();
const cbB = jest.fn();
busA.subscribe('event', cbA);
busB.subscribe('event', cbB);
await busA.publish('event', 'A-data');
expect(cbA).toHaveBeenCalledWith('A-data');
expect(cbB).not.toHaveBeenCalled();
});
test('should handle synchronous subscribers', async () => {
const cb = jest.fn();
bus.subscribe('syncEvent', cb);
await bus.publish('syncEvent', 'sync-data');
expect(cb).toHaveBeenCalledWith('sync-data');
});
test('should handle async subscribers safely', async () => {
const asyncCb = jest.fn(async (data) => {
return new Promise((resolve) => {
setTimeout(() => resolve(`processed-${data}`), 20);
});
});
bus.subscribe('asyncEvent', asyncCb);
await bus.publish('asyncEvent', 'data');
expect(asyncCb).toHaveBeenCalledWith('data');
});
test('should isolate errors between subscribers', async () => {
const good = jest.fn();
const bad = jest.fn(() => {
throw new Error('failure');
});
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
bus.subscribe('errorEvent', bad);
bus.subscribe('errorEvent', good);
await bus.publish('errorEvent', 'data');
expect(good).toHaveBeenCalledWith('data');
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
test('should unsubscribe a subscriber correctly', async () => {
const cb = jest.fn();
const { eventName, id } = bus.subscribe('removeEvent', cb);
bus.unsubscribe(eventName, id);
await bus.publish(eventName, 'data');
expect(cb).not.toHaveBeenCalled();
});
test('should support subscribeOnce behavior', async () => {
const cb = jest.fn();
bus.subscribeOnce('onceEvent', cb);
await bus.publish('onceEvent', 'first');
await bus.publish('onceEvent', 'second');
expect(cb).toHaveBeenCalledTimes(1);
expect(cb).toHaveBeenCalledWith('first');
});
test('should support wildcard events', async () => {
const cb = jest.fn();
bus.subscribe('user:*', cb);
await bus.publish('user:created', { id: 1 });
await bus.publish('user:deleted', { id: 2 });
expect(cb).toHaveBeenCalledTimes(2);
});
test('should return correct subscriber count', () => {
bus.subscribe('countEvent', jest.fn());
bus.subscribe('countEvent', jest.fn());
expect(bus.getSubscriberCount('countEvent')).toBe(2);
});
test('should return list of active events', () => {
bus.subscribe('a', jest.fn());
bus.subscribe('b', jest.fn());
const events = bus.getEvents();
expect(events).toContain('a');
expect(events).toContain('b');
});
test('should unsubscribeEvent remove all listeners', async () => {
const cb1 = jest.fn();
const cb2 = jest.fn();
bus.subscribe('bulkEvent', cb1);
bus.subscribe('bulkEvent', cb2);
bus.unsubscribeEvent('bulkEvent');
await bus.publish('bulkEvent', 'data');
expect(cb1).not.toHaveBeenCalled();
expect(cb2).not.toHaveBeenCalled();
});
test('should unsubscribeAll clear everything safely', async () => {
const cb = jest.fn();
bus.subscribe('x', cb);
bus.subscribe('y', cb);
bus.unsubscribeAll();
await bus.publish('x', 'data');
await bus.publish('y', 'data');
expect(cb).not.toHaveBeenCalled();
});
test('should respect replay opt-out', () => {
const cb = jest.fn();
bus.publish('replayEvent', 'first');
bus.subscribe('replayEvent', cb, { replay: false });
expect(cb).not.toHaveBeenCalledWith('first');
});
});