import { describe, it, expect, vi } from 'vitest'; import { dispatchMiddleware, handlerMiddleware, flowful, hasHandler, addHandler, removeHandler, dispatch, DispatchMiddleware, ActionHandlerMiddleware, Flowful, createHandler, actionCreator, addDispatchMiddleware, removeDispatchMiddleware, addHandlerMiddleware, removeHandlerMiddleware, ActionHandlerMiddlewareCallback, DispatchMiddlewareCallback, } from '../src/index'; describe('singleton', () => { describe('exports', () => { it('should export dispatchMiddleware as an instance of DispatchMiddleware', () => { expect(dispatchMiddleware).toBeInstanceOf(DispatchMiddleware); }); it('should export handlerMiddleware as an instance of ActionHandlerMiddleware', () => { expect(handlerMiddleware).toBeInstanceOf(ActionHandlerMiddleware); }); it('should export flowful as an instance of Flowful', () => { expect(flowful).toBeInstanceOf(Flowful); // We can infer it uses the middlewares based on the constructor call in singleton.ts }); }); describe('handler management functions', () => { it('should correctly add a handler', () => { let handlerCalled = false; const Test = actionCreator('TEST_ACTION'); const testHandler = createHandler({ inputs: [Test], run: () => { handlerCalled = true; }, }); expect(hasHandler(testHandler)).toBe(false); addHandler(testHandler); expect(hasHandler(testHandler)).toBe(true); }); it('should correctly check if a handler exists', () => { let handlerCalled = false; const Test = actionCreator('TEST_ACTION'); const testHandler = createHandler({ inputs: [Test], run: () => { handlerCalled = true; }, }); expect(hasHandler(testHandler)).toBe(false); addHandler(testHandler); expect(hasHandler(testHandler)).toBe(true); removeHandler(testHandler); expect(hasHandler(testHandler)).toBe(false); }); it('should correctly remove a handler', () => { let handlerCalled = false; const Test = actionCreator('TEST_ACTION'); const testHandler = createHandler({ inputs: [Test], run: () => { handlerCalled = true; }, }); addHandler(testHandler); expect(hasHandler(testHandler)).toBe(true); removeHandler(testHandler); expect(hasHandler(testHandler)).toBe(false); }); }); describe('dispatch function', () => { it('should dispatch a single action to an added handler', () => { let handlerCalled = false; const Test = actionCreator('TEST_ACTION'); const testHandler = createHandler({ inputs: [Test], run: () => { handlerCalled = true; }, }); addHandler(testHandler); expect(handlerCalled).toBe(false); dispatch(Test()); expect(handlerCalled).toBe(true); }); it('should dispatch multiple actions', () => { const ActionA = actionCreator('ACTION_A'); const ActionB = actionCreator('ACTION_B'); let receivedPayloadA: number | undefined; let receivedPayloadB: string | undefined; const multiHandler = createHandler({ inputs: [ActionA, ActionB], run: (actionMap) => { receivedPayloadA = actionMap.get(ActionA)?.payload; receivedPayloadB = actionMap.get(ActionB)?.payload; }, }); addHandler(multiHandler); dispatch(ActionA(123), ActionB('test')); expect(receivedPayloadA).toBe(123); expect(receivedPayloadB).toBe('test'); removeHandler(multiHandler); // Cleanup }); it('should not call handler if it was removed', () => { const Test = actionCreator('TEST_ACTION'); const callback = vi.fn(); const handler = createHandler({ inputs: [Test], run: () => { callback(); }, }); addHandler(handler); removeHandler(handler); dispatch(Test()); expect(callback).not.toHaveBeenCalled(); }); }); describe('middleware management functions', () => { it('should add, call and remove dispatch middleware', () => { const mockfn = vi.fn(); const callback: DispatchMiddlewareCallback = (next) => (actionMap) => { mockfn(); return next(actionMap); }; const added = addDispatchMiddleware(callback); expect(added).toBe(true); const Test = actionCreator('TEST_DISPATCH_MW'); dispatch(Test()); expect(mockfn).toHaveBeenCalledTimes(1); const removed = removeDispatchMiddleware(callback); expect(removed).toBe(true); dispatch(Test()); expect(mockfn).toHaveBeenCalledTimes(1); }); it('should add, call and remove handler middleware', () => { const mockfn = vi.fn(); const callback: ActionHandlerMiddlewareCallback = (next) => (actionMap, handler) => { mockfn(); return next(actionMap, handler); }; const added = addHandlerMiddleware(callback); expect(added).toBe(true); const Test = actionCreator('TEST_HANDLER_MW'); addHandler( createHandler({ inputs: [Test], run: vi.fn(), }) ); dispatch(Test()); expect(mockfn).toHaveBeenCalled(); const removed = removeHandlerMiddleware(callback); expect(removed).toBe(true); dispatch(Test()); expect(mockfn).toHaveBeenCalledTimes(1); // Should not be called again }); }); });