test with ts

This commit is contained in:
Yanick Champoux 2021-10-16 11:41:04 -04:00
parent 69a8781b4b
commit c5a9a7397a
3 changed files with 134 additions and 136 deletions

View File

@ -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);
} }

View File

@ -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();
}); });

View File

@ -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');
}); });