updux/src/subscriptions.test.js

193 lines
4.7 KiB
JavaScript

import u from 'updeep';
import { Updux } from './Updux';
import { action } from './actions';
test('subscriptions', () => {
const inc = action('inc');
const set_copy = action('set_copy');
const dux = new Updux({
initial: {
x: 0,
copy: 0,
},
actions: {
inc,
set_copy,
},
mutations: {
inc: (payload) => u({ x: (x) => x + 1 }),
set_copy: (copy) => u({ copy }),
},
});
dux.addSubscription((store) => (state, previous, unsubscribe) => {
if (state.x > 2) return unsubscribe();
store.dispatch(set_copy(state.x));
});
const store = dux.createStore();
store.dispatch(inc());
expect(store.getState()).toMatchObject({ x: 1, copy: 1 });
store.dispatch(inc());
store.dispatch(inc());
expect(store.getState()).toMatchObject({ x: 3, copy: 2 });
});
test('subduxes subscriptions', () => {
const inc_top = action('inc_top');
const inc_bar = action('inc_bar');
const transform_bar = action('transform_bar');
const bar = new Updux({
initial: 'a',
actions: { inc_bar, transform_bar },
mutations: {
inc_bar: () => (state) => state + 'a',
transform_bar: (outcome) => () => outcome,
},
reactions: [
(store) => (state, previous, unsubscribe) => {
if (state.length <= 2) return;
unsubscribe();
store.dispatch(transform_bar('look at ' + state));
},
],
});
const dux = new Updux({
initial: {
count: 0,
},
subduxes: { bar },
actions: {
inc_top,
},
mutations: {
inc_top: () => u({ count: (count) => count + 1 }),
},
effects: {
'*': () => (next) => (action) => {
next(action);
},
},
reactions: [
(store) => {
return ({ count }, { count: previous } = {}) => {
if (count !== previous) {
previous = count;
store.dispatch.inc_bar();
}
};
},
],
});
const store = dux.createStore();
store.dispatch(inc_top());
store.dispatch(inc_top());
expect(store.getState()).toMatchObject({
count: 2,
bar: 'look at look at aaa',
});
store.dispatch(inc_top());
expect(store.getState()).toMatchObject({
count: 3,
bar: 'look at look at aaaa',
});
});
test('subscription within subduxes', () => {
let innerState = jest.fn(() => null);
let outerState = jest.fn(() => null);
const resetMocks = () => [innerState, outerState].map((f) => f.mockReset());
const inner = new Updux({
initial: 1,
actions: { inc: null },
mutations: {
inc: () => (state) => state + 1,
},
reactions: [
(store) => (state, previous, unsub) => {
if (!previous) return;
store.subscribe(innerState);
unsub();
},
],
});
const dux = new Updux({
initial: { x: 0 },
subduxes: { inner },
actions: {
incOuter: null,
},
mutations: {
incOuter: () => (state) => ({ ...state, x: state.x + 1 }),
},
reactions: [
(store) => (state, previous, unsub) => {
if (!previous) return;
store.subscribe(outerState);
unsub();
},
],
});
const store = dux.createStore();
store.dispatch({ type: 'noop' });
store.dispatch({ type: 'noop' });
expect(innerState).not.toHaveBeenCalled();
expect(outerState).not.toHaveBeenCalled();
store.dispatch.inc();
// not called yet
expect(innerState).not.toBeCalled();
expect(outerState).not.toBeCalled();
store.dispatch.inc();
expect(outerState).toBeCalledTimes(1);
expect(outerState).toHaveBeenCalledWith(
{ inner: 3, x: 0 },
undefined,
expect.anything()
);
expect(innerState).toHaveBeenCalled();
expect(innerState).toHaveBeenCalledWith(3, undefined, expect.anything());
resetMocks();
store.dispatch.inc();
expect(outerState).toBeCalled();
expect(outerState).toBeCalledWith(
{ inner: 4, x: 0 },
expect.anything(),
expect.anything()
);
expect(innerState).toBeCalledWith(4, 3, expect.anything());
// state of subdux doesnt change
resetMocks();
store.dispatch.incOuter();
expect(outerState).toBeCalled();
expect(innerState).not.toBeCalled();
});