import EventEmitter from 'events'; import { exportStore } from '../../../src/static/js/utils/helpers'; // The dispatcher is an external module dependency used by exportStore; mock it to observe registrations jest.mock('../../../src/static/js/utils/dispatcher', () => ({ dispatcher: { register: jest.fn(), }, })); import { dispatcher } from '../../../src/static/js/utils/dispatcher'; /** * Behaviors covered: * 1. Binds the provided handler method to store instance context. * 2. Registers the bound callback exactly once with the dispatcher. * 3. Returns the same store instance that was provided. * 4. Invoking the registered callback forwards payload to the handler with correct this. * 5. Type-safety assumption: only function keys are accepted as handler (runtime sanity via mock class). */ describe('utils/helpers', () => { describe('exportStore', () => { class TestStore extends (EventEmitter as { new (): EventEmitter }) { public calls: unknown[] = []; public handler(payload: unknown) { // Assert `this` is the store instance when called via bound function this.calls.push({ self: this, payload }); } public otherHandler(payload: unknown) { this.calls.push({ self: this, payload, type: 'other' }); } } beforeEach(() => { jest.clearAllMocks(); }); test('Returns the same store instance and registers exactly once', () => { const store = new TestStore(); const returned = exportStore(store as unknown as EventEmitter, 'handler' as any); expect(returned).toBe(store); expect(dispatcher.register).toHaveBeenCalledTimes(1); expect(typeof (dispatcher.register as jest.Mock).mock.calls[0][0]).toBe('function'); }); test('Binds the handler to the store instance context', () => { const store = new TestStore(); exportStore(store as unknown as EventEmitter, 'handler' as any); const registered = (dispatcher.register as jest.Mock).mock.calls[0][0] as (p: unknown) => void; const payload = { a: 1 }; registered(payload); expect(store.calls).toHaveLength(1); const { self, payload: received } = store.calls[0] as any; expect(self).toBe(store); expect(received).toBe(payload); }); test('Forwards any payload through the registered callback to the handler', () => { const store = new TestStore(); exportStore(store as unknown as EventEmitter, 'otherHandler' as any); const registered = (dispatcher.register as jest.Mock).mock.calls[0][0] as (p: unknown) => void; registered(null); registered(42); registered({ x: 'y' }); expect(store.calls.map((c: any) => c.payload)).toEqual([null, 42, { x: 'y' }]); }); test('Supports different handler keys of the same store', () => { const store = new TestStore(); exportStore(store as unknown as EventEmitter, 'handler' as any); exportStore(store as unknown as EventEmitter, 'otherHandler' as any); expect(dispatcher.register).toHaveBeenCalledTimes(2); const cb1 = (dispatcher.register as jest.Mock).mock.calls[0][0] as (p: unknown) => void; const cb2 = (dispatcher.register as jest.Mock).mock.calls[1][0] as (p: unknown) => void; cb1('a'); cb2('b'); expect(store.calls).toHaveLength(2); expect(store.calls[0]).toMatchObject({ payload: 'a' }); expect(store.calls[1]).toMatchObject({ payload: 'b', type: 'other' }); }); test('Runtime guard scenario: non-existing handler results in TypeError on bind access', () => { const store = new TestStore(); // @ts-expect-error intentionally passing wrong key to simulate runtime misuse expect(() => exportStore(store as unknown as EventEmitter, 'notAHandler')).toThrow(); }); }); });