diff --git a/src/app/store/config/alienStore/helpers/modules.ts b/src/app/store/config/alienStore/helpers/modules.ts index 7a2ba868..ed0e7b1f 100644 --- a/src/app/store/config/alienStore/helpers/modules.ts +++ b/src/app/store/config/alienStore/helpers/modules.ts @@ -1,6 +1,6 @@ import { AnyAction } from 'redux'; -import { reducer1 } from './reducers'; +import { reducer1, reducerA, reducerB } from './reducers'; export const reduxModule = { reducers: { @@ -27,3 +27,37 @@ export const reduxModuleNoReducers = { }), }, }; + +export const reduxModuleA = { + reducers: { + stateA: reducerA, + }, + actions: { + actionA: (): AnyAction => ({ + type: 'ACTION_A', + payload: { + name: 'Джеро', + }, + }), + }, + selectors: { + selectorA: ({ sliceA }) => sliceA, + }, +}; + +export const reduxModuleB = { + reducers: { + stateB: reducerB, + }, + actions: { + actionB: (): AnyAction => ({ + type: 'ACTION_B', + payload: { + name: 'Джеро', + }, + }), + }, + selectors: { + selectorB: ({ sliceA }) => sliceA, + }, +}; diff --git a/src/app/store/config/alienStore/helpers/reducers.ts b/src/app/store/config/alienStore/helpers/reducers.ts index 5dcc1e64..efb4a3f8 100644 --- a/src/app/store/config/alienStore/helpers/reducers.ts +++ b/src/app/store/config/alienStore/helpers/reducers.ts @@ -1,7 +1,7 @@ import { AnyAction } from 'redux'; export const initialReducer = { - state: (s = 'default state', action: AnyAction): string => { + someState: (s = 'default state', action: AnyAction): string => { if (action.type === 'INIT') { return 'init value'; } @@ -22,3 +22,17 @@ export const reducer2 = (s = 'reducer2 default state', action: AnyAction): strin } return s; }; + +export const reducerA = (s = 'reducerA default state', action: AnyAction): string => { + if (action.type === 'ACTION_A') { + return 'reducerA value'; + } + return s; +}; + +export const reducerB = (s = 'reducerB default state', action: AnyAction): string => { + if (action.type === 'ACTION_B') { + return 'reducerB value'; + } + return s; +}; diff --git a/src/app/store/config/alienStore/useAlien.test.tsx b/src/app/store/config/alienStore/useAlien.test.tsx index 9f57fb0f..c586cc54 100644 --- a/src/app/store/config/alienStore/useAlien.test.tsx +++ b/src/app/store/config/alienStore/useAlien.test.tsx @@ -6,7 +6,7 @@ import alien from './alien'; import useAlien from './useAlien'; -import { reduxModule, reduxModuleNoReducers } from './helpers/modules'; +import { reduxModule, reduxModuleNoReducers, reduxModuleA, reduxModuleB } from './helpers/modules'; import { withProvider, WrapperType } from './helpers/withProvider'; const WRONG_COMPONENT_PATH = './some/wrong/component/path'; @@ -25,14 +25,21 @@ beforeEach(() => { */ describe('useAlien', () => { type ReduxModuleType = Promise; + type ReduxModuleAType = Promise; + type ReduxModuleBType = Promise; - it('should render "null" at first and then resolve the module', async () => { - const alienModule = { - id: 'some-alien-module', - getModule: (): ReduxModuleType => Promise.resolve(reduxModule), + it('should render "null" at first and then resolve each module', async () => { + const alienModuleA = { + id: 'alien-module-a', + getModule: (): ReduxModuleAType => Promise.resolve(reduxModuleA), }; - const { result, waitForNextUpdate } = renderHook(() => useAlien([alienModule]), { + const alienModuleB = { + id: 'alien-module-b', + getModule: (): ReduxModuleBType => Promise.resolve(reduxModuleB), + }; + + const { result, waitForNextUpdate } = renderHook(() => useAlien([alienModuleA, alienModuleB]), { wrapper, }); @@ -43,12 +50,16 @@ describe('useAlien', () => { await waitForNextUpdate(); expect(store.getState()).toEqual({ - state1: 'reducer1 default state', + stateA: 'reducerA default state', + stateB: 'reducerB default state', }); expect(result.current).toHaveProperty('actions'); // @ts-ignore - 'actions' is always part of the result - expect(result.current.actions).toStrictEqual(reduxModule.actions); + expect(result.current.actions).toStrictEqual({ + ...reduxModuleA.actions, + ...reduxModuleB.actions, + }); }); it('should call cb when unmounting', async () => { diff --git a/src/app/store/config/alienStore/useAlien.tsx b/src/app/store/config/alienStore/useAlien.tsx index e1352321..ba0c9ac1 100644 --- a/src/app/store/config/alienStore/useAlien.tsx +++ b/src/app/store/config/alienStore/useAlien.tsx @@ -47,7 +47,7 @@ function useAlien( const { alienManager: { injectReducers, rootReducer }, } = store; - const [alien, setAlien] = useState(null); + const [alien, setAlien] = useState<[AlienResult] | null>(null); useEffect(() => { (async (): Promise => { @@ -59,21 +59,33 @@ function useAlien( const resolvedModules = await Promise.all(promises); - resolvedModules.forEach(alienModule => { - const { reducers, actions, selectors } = alienModule; - - if (check(reducers)) { - throw new Error('Redux Module has no reducers'); - } - // is safe here to iterate reducers's keys for reducer injection - Object.keys(reducers).forEach(key => { - injectReducers(key, reducers[key]); - }); - - store.replaceReducer(rootReducer); - - setAlien({ actions, selectors }); - }); + const result = resolvedModules.reduce( + (acc, { reducers, actions, selectors }: ReduxModule) => { + if (check(reducers)) { + throw new Error('Redux Module has no reducers'); + } + // is safe here to iterate reducers's keys for reducer injection + Object.keys(reducers).forEach(key => { + injectReducers(key, reducers[key]); + }); + + store.replaceReducer(rootReducer); + + return { + actions: { ...acc.actions, ...actions }, + // adds the "selectors" property if any exists + ...(selectors && { + selectors: { + ...acc.selectors, + ...selectors, + }, + }), + }; + }, + {}, + ); + + setAlien(result); } catch (err) { setAlien(err); }