UNPKG

pocak

Version:

State machine

142 lines (120 loc) 3.91 kB
const stateMachine = require("./index.js"); const Turnstil = { 0: "Locked", 1: "Unlocked", Locked: 0, Unlocked: 1 }; const coin = (current, states) => () => { if (Array.isArray(states)) { if (current === states[0]) { return states[1]; } } else if (current === states.Locked) { return states.Unlocked; } return current; }; const push = (current, states) => () => { if (Array.isArray(states)) { if (current === states[1]) { return states[0]; } } else if (current === states.Unlocked) { return states.Locked; } return current; }; const transitions = [coin, push]; describe("StateMachine", () => { it("should move to the correct state", () => { const [state, coin, push] = stateMachine(Turnstil, transitions); expect(state()).toBe(Turnstil.Locked); coin(); expect(state()).toBe(Turnstil.Unlocked); push(); push(); expect(state()).toBe(Turnstil.Locked); coin(); expect(state()).toBe(Turnstil.Unlocked); }); it("should be able to subscribe to state changes", () => { const cb = jest.fn(id => id); const [state, coin] = stateMachine(Turnstil, transitions); state.subscribe(cb); coin(200); expect(cb.mock.calls.length).toBe(1); coin(100); coin(100); expect(cb.mock.calls.length).toBe(3); cb.mockClear(); cb.mockReset(); const [state2, coin2] = stateMachine(["Locked", "Unlocked"], transitions); state2.subscribe(cb); coin2(200); expect(cb.mock.calls.length).toBe(1); coin2(100); coin2(100); expect(cb.mock.calls.length).toBe(3); cb.mockClear(); cb.mockReset(); }); it("should unsubscribe from state changes", () => { const cb = jest.fn(id => id); const [state, coin] = stateMachine(Turnstil, transitions); const unsubscribe = state.subscribe(cb); unsubscribe(); coin(100); coin(100); coin(100); coin(100); expect(cb.mock.calls.length).toBe(0); }); it("should tell the current state", () => { const [state] = stateMachine(Turnstil); expect(state()).toBe(Turnstil.Locked); const [state2] = stateMachine(["FirstState"]); expect(state2()).toBe("FirstState"); }); it("should move to other state when appropriate action is called", () => { const [state, coin] = stateMachine(Turnstil, transitions); const _state = coin(); expect(state()).toBe(Turnstil.Unlocked); expect(_state).toBe(Turnstil.Unlocked); const [state2, coin2] = stateMachine(["Locked", "Unlocked"], transitions); const _state2 = coin2(); expect(state2()).toBe("Unlocked"); expect(_state2).toBe("Unlocked"); }); it("should not move to other state when unappropriate action is called", () => { const [state, coin, push] = stateMachine(Turnstil, transitions); push(); expect(state()).toBe(Turnstil.Locked); }); it("should let the state to be define", () => { const [state] = stateMachine(Turnstil, transitions, Turnstil.Unlocked); expect(state()).toBe(Turnstil.Unlocked); const [state2] = stateMachine(["Locked", "Unlocked"], transitions, 1); expect(state2()).toBe("Unlocked"); }); it("should pass arguments to transition functions", () => { const myTransitionFn = jest.fn(id => id); const [state, myTransition] = stateMachine(Turnstil, [ () => myTransitionFn ]); myTransition("1", 2, 3.2); expect(myTransitionFn.mock.calls.length).toBe(1); expect(myTransitionFn).toHaveBeenCalledWith("1", 2, 3.2); myTransitionFn.mockClear(); myTransitionFn.mockReset(); const [state2, myTransition2] = stateMachine( ["Locked", "Unlocked"], [() => myTransitionFn] ); myTransition2("1", 2, 3.2); expect(myTransitionFn.mock.calls.length).toBe(1); expect(myTransitionFn).toHaveBeenCalledWith("1", 2, 3.2); myTransitionFn.mockClear(); myTransitionFn.mockReset(); }); });