test with ts
This commit is contained in:
parent
69a8781b4b
commit
c5a9a7397a
@ -1,6 +1,6 @@
|
|||||||
import { map, mapValues, merge } from 'lodash';
|
import { map, mapValues, merge } from 'lodash';
|
||||||
|
|
||||||
export function buildSelectors(localSelectors, splatSelector, subduxes) {
|
export function buildSelectors(localSelectors, splatSelector = {}, subduxes ={}) {
|
||||||
const subSelectors = map(subduxes, ({ selectors }, slice) => {
|
const subSelectors = map(subduxes, ({ selectors }, slice) => {
|
||||||
if (!selectors) return {};
|
if (!selectors) return {};
|
||||||
if (slice === '*') return {};
|
if (slice === '*') return {};
|
||||||
@ -9,11 +9,12 @@ export function buildSelectors(localSelectors, splatSelector, subduxes) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let splat = {};
|
let splat = {};
|
||||||
if (splatSelector) {
|
|
||||||
splat[splatSelector[0]] =
|
for ( const name in splatSelector ) {
|
||||||
|
splat[name] =
|
||||||
(state) =>
|
(state) =>
|
||||||
(...args) => {
|
(...args) => {
|
||||||
const value = splatSelector[1](state)(...args);
|
const value = splatSelector[name](state)(...args);
|
||||||
|
|
||||||
const res = () => value;
|
const res = () => value;
|
||||||
return merge(
|
return merge(
|
||||||
@ -24,7 +25,7 @@ export function buildSelectors(localSelectors, splatSelector, subduxes) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return merge({}, ...subSelectors, localSelectors, splat);
|
return merge({}, ...subSelectors, localSelectors, splat);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { test } from 'tap';
|
import { Updux } from '.';
|
||||||
|
import { action } from './actions';
|
||||||
|
|
||||||
import { Updux } from './Updux.js';
|
test('basic selectors', () => {
|
||||||
import { action } from './actions.js';
|
|
||||||
|
|
||||||
test('basic selectors', async (t) => {
|
|
||||||
const updux = new Updux({
|
const updux = new Updux({
|
||||||
subduxes: {
|
subduxes: {
|
||||||
bogeys: new Updux({
|
bogeys: new Updux({
|
||||||
@ -24,11 +22,11 @@ test('basic selectors', async (t) => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
t.same(updux.selectors.bogeys(state), { foo: 1, bar: 2 });
|
expect(updux.selectors.bogeys(state)).toMatchObject({ foo: 1, bar: 2 });
|
||||||
t.equal(updux.selectors.bogey(state)('foo'), 1);
|
expect(updux.selectors.bogey(state)('foo')).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('available in the middleware', async (t) => {
|
test('available in the middleware', () => {
|
||||||
const doIt = action('doIt');
|
const doIt = action('doIt');
|
||||||
|
|
||||||
const updux = new Updux({
|
const updux = new Updux({
|
||||||
@ -60,10 +58,10 @@ test('available in the middleware', async (t) => {
|
|||||||
const store = updux.createStore();
|
const store = updux.createStore();
|
||||||
store.dispatch(updux.actions.doIt());
|
store.dispatch(updux.actions.doIt());
|
||||||
|
|
||||||
t.match(store.getState(), { payload: 'foo' });
|
expect(store.getState()).toMatchObject({ payload: 'foo' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('selector typescript', async (t) => {
|
test('selector typescript', () => {
|
||||||
const bar = new Updux({
|
const bar = new Updux({
|
||||||
initial: { baz: 1 },
|
initial: { baz: 1 },
|
||||||
selectors: {
|
selectors: {
|
||||||
@ -73,40 +71,38 @@ test('selector typescript', async (t) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
t.same(bar.selectors.getBaz(bar.initial), 1);
|
expect(bar.selectors.getBaz(bar.initial)).toEqual(1);
|
||||||
t.same(bar.selectors.getMultBaz({ baz: 3 })(2), 6);
|
expect(bar.selectors.getMultBaz({ baz: 3 })(2)).toEqual(6);
|
||||||
|
|
||||||
test('subduxes', async (t) => {
|
// subduxes
|
||||||
const foo = new Updux({
|
const foo = new Updux({
|
||||||
subduxes: { bar },
|
subduxes: { bar },
|
||||||
selectors: {
|
selectors: {
|
||||||
getRoot: () => 'root',
|
getRoot: () => 'root',
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
|
||||||
t.same(foo.selectors.getBaz(foo.initial), 1);
|
|
||||||
t.same(foo.selectors.getMultBaz({ bar: { baz: 3 } })(2), 6);
|
|
||||||
|
|
||||||
t.ok(foo.selectors.getRoot);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('no root selector', async (t) => {
|
expect(foo.selectors.getBaz(foo.initial)).toEqual(1);
|
||||||
const foo = new Updux({
|
expect(foo.selectors.getMultBaz({ bar: { baz: 3 } })(2)).toEqual(6);
|
||||||
subduxes: {
|
|
||||||
quux: new Updux({}),
|
|
||||||
bar: new Updux({
|
|
||||||
selectors: {
|
|
||||||
getBaz: () => 'baz',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
t.ok(foo.selectors.getBaz);
|
expect(foo.selectors.getRoot).toBeTruthy();
|
||||||
|
|
||||||
|
/// no root selector
|
||||||
|
const foo3 = new Updux({
|
||||||
|
subduxes: {
|
||||||
|
quux: new Updux({}),
|
||||||
|
bar: new Updux({
|
||||||
|
selectors: {
|
||||||
|
getBaz: () => 'baz',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(foo3.selectors.getBaz).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('selector in mw', async (t) => {
|
test('selector in mw', () => {
|
||||||
const myDux = new Updux({
|
const myDux = new Updux({
|
||||||
initial: { stuff: 12 },
|
initial: { stuff: 12 },
|
||||||
subduxes: {
|
subduxes: {
|
||||||
@ -124,16 +120,16 @@ test('selector in mw', async (t) => {
|
|||||||
|
|
||||||
myDux.addEffect('*', ({ selectors, getState }) => () => () => {
|
myDux.addEffect('*', ({ selectors, getState }) => () => () => {
|
||||||
['getStuff', 'getBar'].forEach((selector) =>
|
['getStuff', 'getBar'].forEach((selector) =>
|
||||||
t.type(selectors[selector], 'function')
|
expect(typeof selectors[selector]).toEqual('function')
|
||||||
);
|
);
|
||||||
|
|
||||||
t.equal(getState.getStuff(), 12);
|
expect(getState.getStuff()).toEqual(12);
|
||||||
t.equal(getState.getBar(), 'meh');
|
expect(getState.getBar()).toEqual('meh');
|
||||||
|
|
||||||
ranEffect = true;
|
ranEffect = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
myDux.createStore().dispatch({ type: 'foo' });
|
myDux.createStore().dispatch({ type: 'foo' });
|
||||||
|
|
||||||
t.ok(ranEffect);
|
expect(ranEffect).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { test } from 'tap';
|
import { difference, omit } from 'lodash';
|
||||||
import sinon from 'sinon';
|
|
||||||
import { difference, omit } from 'lodash-es';
|
|
||||||
|
|
||||||
import { Updux } from './Updux.js';
|
import { Updux } from './Updux';
|
||||||
|
|
||||||
test('initial', async (t) => {
|
test('initial', () => {
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
initial: {},
|
initial: {},
|
||||||
subduxes: {
|
subduxes: {
|
||||||
@ -14,10 +12,10 @@ test('initial', async (t) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
t.same(dux.initial, {});
|
expect(dux.initial).toMatchObject({});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('actions', async (t) => {
|
test('actions', () => {
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
initial: {},
|
initial: {},
|
||||||
subduxes: {
|
subduxes: {
|
||||||
@ -28,10 +26,10 @@ test('actions', async (t) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
t.type(dux.actions.foo, 'function');
|
expect(typeof dux.actions.foo).toBe('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('selectors', async (t) => {
|
test('selectors', () => {
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
initial: {},
|
initial: {},
|
||||||
subduxes: {
|
subduxes: {
|
||||||
@ -44,30 +42,28 @@ test('selectors', async (t) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
t.same(dux.selectors, {});
|
expect(dux.selectors).toMatchObject({});
|
||||||
|
|
||||||
const getInner = (state) => (index) => state[index];
|
const getInner = (state) => (index) => state[index];
|
||||||
dux.setSplatSelector('getInner', getInner);
|
dux.setMappedSelector('getInner', getInner);
|
||||||
|
|
||||||
t.type(dux.selectors.getInner, 'function');
|
expect(typeof dux.selectors.getInner).toBe('function');
|
||||||
|
|
||||||
t.same(
|
expect(
|
||||||
dux.selectors.getInner({
|
dux.selectors.getInner({
|
||||||
one: { a: 1 },
|
one: { a: 1 },
|
||||||
two: { a: 2 },
|
two: { a: 2 },
|
||||||
})('one')(),
|
})('one')()
|
||||||
{ a: 1 }
|
).toMatchObject({ a: 1 });
|
||||||
);
|
|
||||||
|
|
||||||
t.same(
|
expect(
|
||||||
dux.selectors
|
dux.selectors
|
||||||
.getInner({
|
.getInner({
|
||||||
one: { a: 1 },
|
one: { a: 1 },
|
||||||
two: { a: 2 },
|
two: { a: 2 },
|
||||||
})('one')
|
})('one')
|
||||||
.getA(),
|
.getA()
|
||||||
1
|
).toBe(1);
|
||||||
);
|
|
||||||
|
|
||||||
// and now with the store
|
// and now with the store
|
||||||
const store = dux.createStore({
|
const store = dux.createStore({
|
||||||
@ -75,12 +71,12 @@ test('selectors', async (t) => {
|
|||||||
two: { a: 2 },
|
two: { a: 2 },
|
||||||
});
|
});
|
||||||
|
|
||||||
t.same(store.getState.getInner('two')(), { a: 2 });
|
expect(store.getState.getInner('two')()).toMatchObject({ a: 2 });
|
||||||
t.same(store.getState.getInner('two').getA(), 2);
|
expect(store.getState.getInner('two').getA()).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('splat middleware', async (t) => {
|
test('splat middleware', () => {
|
||||||
const snitch = sinon.fake(() => true);
|
const snitch = jest.fn(() => true);
|
||||||
|
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
initial: {},
|
initial: {},
|
||||||
@ -101,11 +97,11 @@ test('splat middleware', async (t) => {
|
|||||||
const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } });
|
const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } });
|
||||||
store.dispatch.foo();
|
store.dispatch.foo();
|
||||||
|
|
||||||
t.notOk(snitch.called);
|
expect(snitch).not.toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('splat subscriptions', async (t) => {
|
test('splat subscriptions', () => {
|
||||||
const snitch = sinon.fake(() => true);
|
const snitch = jest.fn(() => true);
|
||||||
|
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
initial: {},
|
initial: {},
|
||||||
@ -129,20 +125,21 @@ test('splat subscriptions', async (t) => {
|
|||||||
const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } });
|
const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } });
|
||||||
store.dispatch({ type: 'noop' });
|
store.dispatch({ type: 'noop' });
|
||||||
|
|
||||||
t.notOk(snitch.called);
|
expect(snitch).not.toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('splat subscriptions, more', async (t) => {
|
test('splat subscriptions, more', () => {
|
||||||
const snitch = sinon.fake(() => true);
|
const snitch = jest.fn(() => true);
|
||||||
|
|
||||||
const inner = new Updux({
|
const inner = new Updux({
|
||||||
initial: { a: 1 },
|
initial: { a: 1 },
|
||||||
actions: { foo: null, incAll: null },
|
actions: { foo: null, incAll: null },
|
||||||
mutations: {
|
mutations: {
|
||||||
foo: (id) => (state) => state.a === id ? { ...state, b: 1 } : state,
|
foo: (id) => (state) =>
|
||||||
|
state.a === id ? { ...state, b: 1 } : state,
|
||||||
incAll: () => (state) => ({ ...state, a: state.a + 1 }),
|
incAll: () => (state) => ({ ...state, a: state.a + 1 }),
|
||||||
},
|
},
|
||||||
subscriptions: [() => snitch],
|
reactions: [() => snitch],
|
||||||
});
|
});
|
||||||
|
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
@ -155,7 +152,7 @@ test('splat subscriptions, more', async (t) => {
|
|||||||
delete: (id) => (state) => omit(state, id),
|
delete: (id) => (state) => omit(state, id),
|
||||||
newEntry: (name) => (state) => ({ ...state, [name]: { a: 10 } }),
|
newEntry: (name) => (state) => ({ ...state, [name]: { a: 10 } }),
|
||||||
},
|
},
|
||||||
splatReaction: 'whatev',
|
mappedReaction: true,
|
||||||
subduxes: {
|
subduxes: {
|
||||||
'*': inner,
|
'*': inner,
|
||||||
},
|
},
|
||||||
@ -164,72 +161,76 @@ test('splat subscriptions, more', async (t) => {
|
|||||||
const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } });
|
const store = dux.createStore({ one: { a: 1 }, two: { a: 2 } });
|
||||||
store.dispatch({ type: 'noop' });
|
store.dispatch({ type: 'noop' });
|
||||||
|
|
||||||
t.equal(snitch.callCount, 2);
|
expect(snitch).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
t.same(snitch.firstCall.args[0], { a: 1 });
|
expect(snitch).toHaveBeenCalledWith(
|
||||||
t.same(snitch.secondCall.args[0], { a: 2 });
|
{ a: 1 },
|
||||||
|
undefined,
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
expect(snitch).toHaveBeenCalledWith(
|
||||||
|
{ a: 2 },
|
||||||
|
undefined,
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
|
||||||
snitch.resetHistory();
|
snitch.mockReset();
|
||||||
|
|
||||||
store.dispatch.foo(2);
|
store.dispatch.foo(2);
|
||||||
|
|
||||||
t.equal(snitch.callCount, 1);
|
expect(snitch).toHaveBeenCalledWith(
|
||||||
|
{ a: 2, b: 1 },
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
|
||||||
t.same(snitch.firstCall.args[0], { a: 2, b: 1 });
|
snitch.mockReset();
|
||||||
|
|
||||||
snitch.resetHistory();
|
|
||||||
store.dispatch.delete('one');
|
store.dispatch.delete('one');
|
||||||
|
|
||||||
t.same(store.getState(), {
|
expect(store.getState()).toMatchObject({
|
||||||
two: { a: 2, b: 1 },
|
two: { a: 2, b: 1 },
|
||||||
});
|
});
|
||||||
|
|
||||||
t.equal(snitch.callCount, 1);
|
expect(snitch).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
t.ok(
|
expect(snitch).toHaveBeenCalledWith(
|
||||||
snitch.calledWithMatch(
|
undefined,
|
||||||
undefined,
|
{ a: 1 },
|
||||||
{ a: 1 },
|
expect.anything()
|
||||||
sinon.match.typeOf('function')
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await t.test('only one subscriber left', async (t) => {
|
// only one subscriber left
|
||||||
snitch.resetHistory();
|
snitch.mockReset();
|
||||||
store.dispatch.incAll();
|
|
||||||
|
|
||||||
t.equal(snitch.callCount, 1);
|
store.dispatch.incAll();
|
||||||
|
|
||||||
t.ok(
|
expect(snitch).toHaveBeenCalledTimes(1);
|
||||||
snitch.calledWithMatch(
|
|
||||||
{ a: 3, b: 1 },
|
|
||||||
{ a: 2, b: 1 },
|
|
||||||
sinon.match.typeOf('function')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await t.test('new entry gets subscribed', async (t) => {
|
expect(snitch).toHaveBeenCalledWith(
|
||||||
snitch.resetHistory();
|
{ a: 3, b: 1 },
|
||||||
store.dispatch.newEntry('newbie');
|
{ a: 2, b: 1 },
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
|
||||||
t.equal(snitch.callCount, 1);
|
// new entry gets subscribed
|
||||||
|
snitch.mockReset();
|
||||||
|
store.dispatch.newEntry('newbie');
|
||||||
|
|
||||||
t.ok(
|
expect(snitch).toHaveBeenCalledTimes(1);
|
||||||
snitch.calledWithMatch(
|
|
||||||
{ a: 10 },
|
expect(snitch).toHaveBeenCalledWith(
|
||||||
undefined,
|
{ a: 10 },
|
||||||
sinon.match.typeOf('function')
|
undefined,
|
||||||
)
|
expect.anything()
|
||||||
);
|
);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('many levels down', { only: false }, async (t) => {
|
test('many levels down', () => {
|
||||||
const snitch = sinon.fake(() => true);
|
const snitch = jest.fn(() => true);
|
||||||
|
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
splatReaction: 'potato',
|
mappedReaction: true,
|
||||||
actions: { remove: null },
|
actions: { remove: null },
|
||||||
mutations: {
|
mutations: {
|
||||||
remove: () => (state) => ({}),
|
remove: () => (state) => ({}),
|
||||||
@ -245,7 +246,7 @@ test('many levels down', { only: false }, async (t) => {
|
|||||||
mutations: {
|
mutations: {
|
||||||
add: () => (x) => x + 1,
|
add: () => (x) => x + 1,
|
||||||
},
|
},
|
||||||
subscriptions: [
|
reactions: [
|
||||||
(store) => (state) => snitch(state, store),
|
(store) => (state) => snitch(state, store),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -257,23 +258,23 @@ test('many levels down', { only: false }, async (t) => {
|
|||||||
const store = dux.createStore({ one: { a: 1 } });
|
const store = dux.createStore({ one: { a: 1 } });
|
||||||
store.dispatch({ type: 'foo' });
|
store.dispatch({ type: 'foo' });
|
||||||
|
|
||||||
t.ok(snitch.calledOnce);
|
expect(snitch).toHaveBeenCalled();
|
||||||
t.same(snitch.firstCall.firstArg, 1);
|
expect(snitch).toHaveBeenCalledWith(1, expect.anything());
|
||||||
|
|
||||||
snitch.resetHistory();
|
snitch.mockReset();
|
||||||
|
|
||||||
store.dispatch.remove();
|
store.dispatch.remove();
|
||||||
|
|
||||||
t.ok(snitch.calledOnce);
|
expect(snitch).toBeCalled();
|
||||||
t.same(snitch.firstCall.firstArg, undefined);
|
expect(snitch).toHaveBeenCalledWith(undefined, expect.anything());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('inherit info via the store', async (t) => {
|
test('inherit info via the store', () => {
|
||||||
const snitch = sinon.fake(() => true);
|
const snitch = jest.fn(() => true);
|
||||||
const splatSnitch = sinon.fake(() => true);
|
const splatSnitch = jest.fn(() => true);
|
||||||
|
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
splatReaction: (store, key) => {
|
mappedReaction: (store, key) => {
|
||||||
store.itemId = key;
|
store.itemId = key;
|
||||||
|
|
||||||
splatSnitch();
|
splatSnitch();
|
||||||
@ -290,7 +291,7 @@ test('inherit info via the store', async (t) => {
|
|||||||
mutations: {
|
mutations: {
|
||||||
add: () => (x) => x + 1,
|
add: () => (x) => x + 1,
|
||||||
},
|
},
|
||||||
subscriptions: [
|
reactions: [
|
||||||
(store) => (state) => snitch(state, store.itemId),
|
(store) => (state) => snitch(state, store.itemId),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -306,9 +307,9 @@ test('inherit info via the store', async (t) => {
|
|||||||
|
|
||||||
store.dispatch({ type: 'noop' });
|
store.dispatch({ type: 'noop' });
|
||||||
|
|
||||||
t.ok(splatSnitch.calledTwice);
|
expect(splatSnitch).toBeCalledTimes(2);
|
||||||
|
|
||||||
t.ok(snitch.calledTwice);
|
expect(snitch).toBeCalledTimes(2);
|
||||||
t.ok(snitch.calledWithMatch(1, 'one'));
|
expect(snitch).toHaveBeenCalledWith(1, 'one');
|
||||||
t.ok(snitch.calledWithMatch(2, 'two'));
|
expect(snitch).toHaveBeenCalledWith(2, 'two');
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user