This commit is contained in:
Yanick Champoux 2020-01-27 23:35:01 -05:00
parent 931377b584
commit 4c0d7b366f
3 changed files with 284 additions and 222 deletions

View File

@ -1,6 +1,6 @@
module.exports = { module.exports = {
"roots": [ "roots": [
"./src" "./dist"
], ],
"transform": { "transform": {
"^.+\\.ts$": "ts-jest", "^.+\\.ts$": "ts-jest",

View File

@ -1,7 +1,8 @@
import Updux, { actionCreator } from "."; import Updux, { actionCreator } from '.';
import u from "updeep"; import u from 'updeep';
import mwUpdux from './middleware_aux';
test("simple effect", () => { test('simple effect', () => {
const tracer = jest.fn(); const tracer = jest.fn();
const store = new Updux({ const store = new Updux({
@ -9,13 +10,13 @@ test("simple effect", () => {
foo: (api: any) => (next: any) => (action: any) => { foo: (api: any) => (next: any) => (action: any) => {
tracer(); tracer();
next(action); next(action);
} },
} },
}).createStore(); }).createStore();
expect(tracer).not.toHaveBeenCalled(); expect(tracer).not.toHaveBeenCalled();
store.dispatch({ type: "bar" }); store.dispatch({ type: 'bar' });
expect(tracer).not.toHaveBeenCalled(); expect(tracer).not.toHaveBeenCalled();
@ -24,7 +25,7 @@ test("simple effect", () => {
expect(tracer).toHaveBeenCalled(); expect(tracer).toHaveBeenCalled();
}); });
test("effect and sub-effect", () => { test('effect and sub-effect', () => {
const tracer = jest.fn(); const tracer = jest.fn();
const tracerEffect = (signature: string) => (api: any) => (next: any) => ( const tracerEffect = (signature: string) => (api: any) => (next: any) => (
@ -36,49 +37,81 @@ test("effect and sub-effect", () => {
const store = new Updux({ const store = new Updux({
effects: { effects: {
foo: tracerEffect("root") foo: tracerEffect('root'),
}, },
subduxes: { subduxes: {
zzz: { zzz: {
effects: { effects: {
foo: tracerEffect("child") foo: tracerEffect('child'),
} },
} },
} },
}).createStore(); }).createStore();
expect(tracer).not.toHaveBeenCalled(); expect(tracer).not.toHaveBeenCalled();
store.dispatch({ type: "bar" }); store.dispatch({ type: 'bar' });
expect(tracer).not.toHaveBeenCalled(); expect(tracer).not.toHaveBeenCalled();
store.dispatch.foo(); store.dispatch.foo();
expect(tracer).toHaveBeenNthCalledWith(1, "root"); expect(tracer).toHaveBeenNthCalledWith(1, 'root');
expect(tracer).toHaveBeenNthCalledWith(2, "child"); expect(tracer).toHaveBeenNthCalledWith(2, 'child');
}); });
test('"*" effect', () => { describe('"*" effect', () => {
test('from the constructor', () => {
const tracer = jest.fn(); const tracer = jest.fn();
const store = new Updux({ const store = new Updux({
effects: { effects: {
"*": api => next => action => { '*': api => next => action => {
tracer(); tracer();
next(action); next(action);
} },
} },
}).createStore(); }).createStore();
expect(tracer).not.toHaveBeenCalled(); expect(tracer).not.toHaveBeenCalled();
store.dispatch({ type: "bar" }); store.dispatch({ type: 'bar' });
expect(tracer).toHaveBeenCalled(); expect(tracer).toHaveBeenCalled();
}); });
test("async effect", async () => { test('from addEffect', () => {
const tracer = jest.fn();
const updux = new Updux({});
updux.addEffect('*', api => next => action => {
tracer();
next(action);
});
expect(tracer).not.toHaveBeenCalled();
updux.createStore().dispatch({ type: 'bar' });
expect(tracer).toHaveBeenCalled();
});
test('action can be modified', () => {
const mw = mwUpdux.middleware;
const next = jest.fn();
mw({dispatch:{}} as any)(next as any)({type: 'bar'});
expect(next).toHaveBeenCalled();
expect(next.mock.calls[0][0]).toMatchObject({meta: 'gotcha'});
});
});
test('async effect', async () => {
function timeout(ms: number) { function timeout(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms)); return new Promise(resolve => setTimeout(resolve, ms));
} }
@ -91,8 +124,8 @@ test("async effect", async () => {
next(action); next(action);
await timeout(1000); await timeout(1000);
tracer(); tracer();
} },
} },
}).createStore(); }).createStore();
expect(tracer).not.toHaveBeenCalled(); expect(tracer).not.toHaveBeenCalled();
@ -106,7 +139,7 @@ test("async effect", async () => {
expect(tracer).toHaveBeenCalled(); expect(tracer).toHaveBeenCalled();
}); });
test("getState is local", () => { test('getState is local', () => {
let childState; let childState;
let rootState; let rootState;
let rootFromChild; let rootFromChild;
@ -118,8 +151,8 @@ test("getState is local", () => {
childState = getState(); childState = getState();
rootFromChild = getRootState(); rootFromChild = getRootState();
next(action); next(action);
} },
} },
}); });
const root = new Updux({ const root = new Updux({
@ -129,8 +162,8 @@ test("getState is local", () => {
doIt: ({ getState }) => next => action => { doIt: ({ getState }) => next => action => {
rootState = getState(); rootState = getState();
next(action); next(action);
} },
} },
}); });
const store = root.createStore(); const store = root.createStore();
@ -141,78 +174,94 @@ test("getState is local", () => {
expect(childState).toEqual({ alpha: 12 }); expect(childState).toEqual({ alpha: 12 });
}); });
test("middleware as map", () => { test('middleware as map', () => {
let childState; let childState;
let rootState; let rootState;
let rootFromChild; let rootFromChild;
const doIt = actionCreator("doIt"); const doIt = actionCreator('doIt');
const child = new Updux({ const child = new Updux({
initial: "", initial: '',
effects: [ effects: [
[ [
doIt, doIt,
() => next => action => { () => next => action => {
next(u({ payload: (p: string) => p + "Child" }, action) as any); next(
} u(
] { payload: (p: string) => p + 'Child' },
] action
) as any
);
},
],
],
}); });
const root = new Updux({ const root = new Updux({
initial: { message: "" }, initial: { message: '' },
subduxes: { child }, subduxes: { child },
effects: [ effects: [
[ [
"^", '^',
() => next => action => { () => next => action => {
next(u({ payload: (p: string) => p + "Pre" }, action) as any); next(
} u({ payload: (p: string) => p + 'Pre' }, action) as any
);
},
], ],
[ [
doIt, doIt,
() => next => action => { () => next => action => {
next(u({ payload: (p: string) => p + "Root" }, action) as any); next(
} u({ payload: (p: string) => p + 'Root' }, action) as any
);
},
], ],
[ [
"*", '*',
() => next => action => { () => next => action => {
next(u({ payload: (p: string) => p + "After" }, action) as any); next(
} u(
{ payload: (p: string) => p + 'After' },
action
) as any
);
},
], ],
[ [
"$", '$',
() => next => action => { () => next => action => {
next(u({ payload: (p: string) => p + "End" }, action) as any); next(
} u({ payload: (p: string) => p + 'End' }, action) as any
] );
},
], ],
mutations: [[doIt, (message: any) => () => ({ message })]] ],
mutations: [[doIt, (message: any) => () => ({ message })]],
}); });
const store = root.createStore(); const store = root.createStore();
store.dispatch.doIt(""); store.dispatch.doIt('');
expect(store.getState()).toEqual({ message: "PreRootAfterChildEnd" }); expect(store.getState()).toEqual({ message: 'PreRootAfterChildEnd' });
}); });
test("generator", () => { test('generator', () => {
const updux = new Updux({ const updux = new Updux({
initial: 0, initial: 0,
mutations: [["doIt", payload => () => payload]], mutations: [['doIt', payload => () => payload]],
effects: [ effects: [
[ [
"doIt", 'doIt',
() => { () => {
let i = 0; let i = 0;
return () => (next: any) => (action: any) => return () => (next: any) => (action: any) =>
next({ ...action, payload: ++i }); next({ ...action, payload: ++i });
}, },
true true,
] ],
] ],
}); });
const store1 = updux.createStore(); const store1 = updux.createStore();

13
src/middleware_aux.ts Normal file
View File

@ -0,0 +1,13 @@
import Updux from '.';
const updux = new Updux({
subduxes: {
foo: { initial: "banana" }
}
});
updux.addEffect('*', api => next => action => {
next({...action, meta: "gotcha" });
});
export default updux;