From bce2d5098cfe05a4fadad1b742042ebb4e6b84cb Mon Sep 17 00:00:00 2001 From: jero Date: Thu, 17 Oct 2019 23:37:54 +0300 Subject: [PATCH] feat(alienstore): add useAlienModule hook import dynamically a Redux module and inject its reducers improves #43 --- .../config/alienStore/alienStore.test.tsx | 33 ++++++++++++++++++- .../store/config/alienStore/alienStore.tsx | 24 +++++++++++++- src/app/store/config/alienStore/index.tsx | 1 + 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/app/store/config/alienStore/alienStore.test.tsx b/src/app/store/config/alienStore/alienStore.test.tsx index 1735b0e1..e32208ed 100644 --- a/src/app/store/config/alienStore/alienStore.test.tsx +++ b/src/app/store/config/alienStore/alienStore.test.tsx @@ -1,11 +1,13 @@ /* eslint-disable @typescript-eslint/ban-ts-ignore, import/no-named-as-default-member */ import React, { ReactElement } from 'react'; -import { createStore as createReduxStore } from 'redux'; +import { renderHook, act, RenderHookResult } from '@testing-library/react-hooks'; +import { createStore as createReduxStore, AnyAction } from 'redux'; import alienStore, { createStore, reloadStore, injectReducers, withStoreModule, + useAlienModule, } from './alienStore'; describe('Dyno Store', () => { @@ -14,6 +16,7 @@ describe('Dyno Store', () => { expect(alienStore).toHaveProperty('reloadStore'); expect(alienStore).toHaveProperty('injectReducers'); expect(alienStore).toHaveProperty('withStoreModule'); + expect(alienStore).toHaveProperty('useAlienModule'); }); it('should create and return a Redux store', () => { @@ -81,4 +84,32 @@ describe('Dyno Store', () => { }); }); }); + + describe('test "useAlienModule"', () => { + const alienModuleMock = { + actions: { + dummyAction: (): AnyAction => ({ + type: 'DUMMY_ACTION', + payload: { + name: 'Джеро', + }, + }), + }, + }; + + type AlienModuleType = Promise<{ default: typeof alienModuleMock }>; + + const importAlienModule = (): AlienModuleType => Promise.resolve({ default: alienModuleMock }); + it('should render "null" at first', async () => { + const store = createStore(); + const mockDispatch = jest.spyOn(store, 'dispatch'); + let hookRenderer = {} as RenderHookResult<{}, AlienModuleType>; + await act(async () => { + hookRenderer = renderHook(() => useAlienModule(importAlienModule)); + }); + expect(mockDispatch).toHaveBeenCalledTimes(1); + expect(mockDispatch).toHaveBeenCalledWith({ type: '@@ALIEN_STORE/RELOAD' }); + expect(hookRenderer.result.current).toEqual({ default: alienModuleMock }); + }); + }); }); diff --git a/src/app/store/config/alienStore/alienStore.tsx b/src/app/store/config/alienStore/alienStore.tsx index 214280bd..398bd1dd 100644 --- a/src/app/store/config/alienStore/alienStore.tsx +++ b/src/app/store/config/alienStore/alienStore.tsx @@ -1,4 +1,4 @@ -import { ComponentType } from 'react'; +import { ComponentType, useEffect, useState } from 'react'; import { createStore as createReduxStore, combineReducers, @@ -47,9 +47,31 @@ export async function withStoreModule

( } } +type UseAlienModuleImportType

= () => Promise<{ default: P } | P>; + +export function useAlienModule

(moduleStore: UseAlienModuleImportType

): P | null { + const [alienModule, setAlienModule] = useState

(null); + + useEffect(() => { + (async (): Promise => { + try { + const module = await moduleStore(); + injectReducers(module.reducers); + setAlienModule(module); + } catch (err) { + throw new Error(`useDyno error: ${err}`); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return alienModule; +} + export default { createStore, reloadStore, injectReducers, withStoreModule, + useAlienModule, }; diff --git a/src/app/store/config/alienStore/index.tsx b/src/app/store/config/alienStore/index.tsx index 07893608..8b1f7026 100644 --- a/src/app/store/config/alienStore/index.tsx +++ b/src/app/store/config/alienStore/index.tsx @@ -2,5 +2,6 @@ export { createStore } from './alienStore'; export { reloadStore } from './alienStore'; export { injectReducers } from './alienStore'; export { withStoreModule } from './alienStore'; +export { useAlienModule } from './alienStore'; export { default } from './alienStore';