import { difference, omit } from 'lodash-es'; import { Updux } from './Updux'; test('initial', () => { const dux = new Updux({ initial: {}, subduxes: { '*': { initial: { a: 1 }, }, }, }); expect(dux.initial).toMatchObject({}); }); test('actions', () => { const dux = new Updux({ initial: {}, subduxes: { '*': { initial: { a: 1 }, actions: { foo: null }, }, }, }); expect(typeof dux.actions.foo).toBe('function'); }); test('selectors', () => { const dux = new Updux({ initial: {}, subduxes: { '*': { initial: { a: 1 }, selectors: { getA: ({ a }) => a, }, }, }, }); expect(dux.selectors).toMatchObject({}); const getInner = (state) => (index) => state[index]; dux.setMappedSelector('getInner', getInner); expect(typeof dux.selectors.getInner).toBe('function'); expect( dux.selectors.getInner({ one: { a: 1 }, two: { a: 2 }, })('one')() ).toMatchObject({ a: 1 }); expect( dux.selectors .getInner({ one: { a: 1 }, two: { a: 2 }, })('one') .getA() ).toBe(1); // and now with the store const store = dux.createStore({ one: { a: 1 }, two: { a: 2 }, }); expect(store.getState.getInner('two')()).toMatchObject({ a: 2 }); expect(store.getState.getInner('two').getA()).toEqual(2); }); test('splat middleware', () => { const snitch = jest.fn(() => true); const dux = new Updux({ initial: {}, subduxes: { '*': { initial: { a: 1 }, actions: { foo: null }, effects: { foo: (api) => (next) => (action) => { snitch(); next(action); }, }, }, }, }); const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } }); store.dispatch.foo(); expect(snitch).not.toBeCalled(); }); test('splat subscriptions', () => { const snitch = jest.fn(() => true); const dux = new Updux({ initial: {}, subduxes: { '*': { initial: { a: 1 }, actions: { foo: null }, mutations: { foo: (id) => (state) => state.a === i ? { ...state, b: 1 } : state, }, subscriptions: [ (store) => (state, previous, unsub) => { snitch(state); }, ], }, }, }); const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } }); store.dispatch({ type: 'noop' }); expect(snitch).not.toBeCalled(); }); test('splat subscriptions, more', () => { const snitch = jest.fn(() => true); const inner = new Updux({ initial: { a: 1 }, actions: { foo: null, incAll: null }, mutations: { foo: (id) => (state) => state.a === id ? { ...state, b: 1 } : state, incAll: () => (state) => ({ ...state, a: state.a + 1 }), }, reactions: [() => snitch], }); const dux = new Updux({ initial: {}, actions: { delete: null, newEntry: null, }, mutations: { delete: (id) => (state) => omit(state, id), newEntry: (name) => (state) => ({ ...state, [name]: { a: 10 } }), }, mappedReaction: true, subduxes: { '*': inner, }, }); const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } }); store.dispatch({ type: 'noop' }); expect(snitch).toHaveBeenCalledTimes(2); expect(snitch).toHaveBeenCalledWith({ a: 1 }, undefined, expect.anything()); expect(snitch).toHaveBeenCalledWith({ a: 2 }, undefined, expect.anything()); snitch.mockReset(); store.dispatch.foo(2); expect(snitch).toHaveBeenCalledWith( { a: 2, b: 1 }, expect.anything(), expect.anything() ); snitch.mockReset(); store.dispatch.delete('one'); expect(store.getState()).toMatchObject({ two: { a: 2, b: 1 }, }); expect(snitch).toHaveBeenCalledTimes(1); expect(snitch).toHaveBeenCalledWith(undefined, { a: 1 }, expect.anything()); // only one subscriber left snitch.mockReset(); store.dispatch.incAll(); expect(snitch).toHaveBeenCalledTimes(1); expect(snitch).toHaveBeenCalledWith( { a: 3, b: 1 }, { a: 2, b: 1 }, expect.anything() ); // new entry gets subscribed snitch.mockReset(); store.dispatch.newEntry('newbie'); expect(snitch).toHaveBeenCalledTimes(1); expect(snitch).toHaveBeenCalledWith( { a: 10 }, undefined, expect.anything() ); }); test('many levels down', () => { const snitch = jest.fn(() => true); const dux = new Updux({ mappedReaction: true, actions: { remove: null }, mutations: { remove: () => (state) => ({}), }, subduxes: { '*': { subduxes: { a: { initial: 1, actions: { add: null, }, mutations: { add: () => (x) => x + 1, }, reactions: [(store) => (state) => snitch(state, store)], }, }, }, }, }); const store = dux.createStore({ one: { a: 1 } }); store.dispatch({ type: 'foo' }); expect(snitch).toHaveBeenCalled(); expect(snitch).toHaveBeenCalledWith(1, expect.anything()); snitch.mockReset(); store.dispatch.remove(); expect(snitch).toBeCalled(); expect(snitch).toHaveBeenCalledWith(undefined, expect.anything()); }); test('inherit info via the store', () => { const snitch = jest.fn(() => true); const splatSnitch = jest.fn(() => true); const dux = new Updux({ mappedReaction: (store, key) => { store.itemId = key; splatSnitch(); return { itemId: key }; }, subduxes: { '*': { subduxes: { a: { initial: 1, actions: { add: null, }, mutations: { add: () => (x) => x + 1, }, reactions: [ (store) => (state) => snitch(state, store.itemId), ], }, }, }, }, }); const store = dux.createStore({ one: { a: 1 }, two: { a: 2 }, }); store.dispatch({ type: 'noop' }); expect(splatSnitch).toBeCalledTimes(2); expect(snitch).toBeCalledTimes(2); expect(snitch).toHaveBeenCalledWith(1, 'one'); expect(snitch).toHaveBeenCalledWith(2, 'two'); });