Files
mediacms/frontend/tests/utils/helpers/exportStore.test.ts

97 lines
4.1 KiB
TypeScript

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();
});
});
});