Skip to content

Commit

Permalink
feat(alienstore): add removeReducers method
Browse files Browse the repository at this point in the history
removes a reducer by given key that should match on the state in order to get removed, otherwise it
should not remove it and therefore the reducerMap continue intact

improves #43
  • Loading branch information
aneurysmjs committed Nov 4, 2019
1 parent e924018 commit 8fae08c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 6 deletions.
68 changes: 65 additions & 3 deletions src/app/store/config/alienStore/alienStore.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import alienStore, {
getReducerMap,
injectReducers,
reloadStore,
removeReducers,
useAlienModule,
withStoreModule,
} from './alienStore';
Expand All @@ -19,6 +20,7 @@ describe('alienStore', () => {
expect(alienStore).toHaveProperty('getReducerMap');
expect(alienStore).toHaveProperty('injectReducers');
expect(alienStore).toHaveProperty('reloadStore');
expect(alienStore).toHaveProperty('removeReducers');
expect(alienStore).toHaveProperty('useAlienModule');
expect(alienStore).toHaveProperty('withStoreModule');
});
Expand Down Expand Up @@ -82,13 +84,14 @@ describe('alienStore', () => {
it('should return the current reducers also when they are given', () => {
const initialReducers = {
reducer1: (): string => 'reducer1 value',
reducer2: (): string => 'reducer1 value',
reducer2: (): string => 'reducer2 value',
};
createStore(initialReducers);
const currentReducers = getReducerMap();
expect(Object.keys(currentReducers)).toEqual(Object.keys(initialReducers));
});
});

describe('injectReducers', () => {
it('should add reducer and reload the store', () => {
const store = createStore(undefined);
Expand All @@ -109,7 +112,66 @@ describe('alienStore', () => {
});
});

describe('test "withStoreModule"', () => {
describe('removeReducers', () => {
it('should remove reducers byt given key and reload the store', () => {
const initialReducers = {
reducer1: (): string => 'reducer1 value',
reducer2: (): string => 'reducer2 value',
reducer3: (): string => 'reducer3 value',
reducer4: (): string => 'reducer4 value',
};
const store = createStore(initialReducers);
const mockDispatch = jest.spyOn(store, 'dispatch');

const currentReducers = getReducerMap();

expect(Object.keys(currentReducers)).toHaveLength(4);

removeReducers('reducer1');
const current3Reducers = getReducerMap();
expect(Object.keys(current3Reducers)).toHaveLength(3);

removeReducers('reducer2');
const current2Reducers = getReducerMap();
expect(Object.keys(current2Reducers)).toHaveLength(2);

removeReducers('reducer3');
const current1Reducers = getReducerMap();
expect(Object.keys(current1Reducers)).toHaveLength(1);

expect(mockDispatch).toHaveBeenCalledTimes(3);
expect(mockDispatch).toHaveBeenCalledWith({ type: '@@ALIEN_STORE/RELOAD' });
});

it('should not remove a reducer if it does not exist', () => {
const initialReducers = {
reducer1: (): string => 'reducer1 value',
reducer2: (): string => 'reducer2 value',
};
const store = createStore(initialReducers);
const mockDispatch = jest.spyOn(store, 'dispatch');

const currentReducers = getReducerMap();

expect(Object.keys(currentReducers)).toHaveLength(2);

removeReducers('reducerWithNotValidName');
const reducerMap = getReducerMap();
expect(Object.keys(reducerMap)).toHaveLength(2);
expect(Object.keys(reducerMap)).toEqual(Object.keys(currentReducers));
expect(mockDispatch).not.toHaveBeenCalled();
});

it('should throw if all reducers has been deleted', () => {
createStore(undefined);

expect(() => {
removeReducers('defaultState');
}).toThrowError('alienStore: the reducerMap cannot be empty, otherwise Redux will complaint');
});
});

describe('withStoreModule', () => {
it('should add reducer and reload the store', async () => {
const Example = (): ReactElement => <div>some component</div>;
const component = Promise.resolve({ default: Example });
Expand Down Expand Up @@ -155,7 +217,7 @@ describe('alienStore', () => {
/**
* @link https://stackoverflow.com/questions/56085458/testing-custom-hook-with-react-hooks-testing-library-throws-an-error
*/
describe('test "useAlienModule"', () => {
describe('useAlienModule', () => {
const alienModuleMock = {
reducers: {
dummy: (state: { name: string }, action: AnyAction): typeof state => {
Expand Down
18 changes: 15 additions & 3 deletions src/app/store/config/alienStore/alienStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,20 @@ export const injectReducers = (newReducers: ReducerMap): void => {

reducerMap = { ...reducerMap, ...newReducers };

// console.log('reducerMap', reducerMap);
reloadStore();
};

export const removeReducers = (key: string): void => {
// if the reducer doens't exist, just skip
if (key && !reducerMap[key]) {
return;
}

delete reducerMap[key];

if (Object.keys(reducerMap).length === 0) {
throw new Error('alienStore: the reducerMap cannot be empty, otherwise Redux will complaint');
}

reloadStore();
};
Expand Down Expand Up @@ -89,8 +102,6 @@ export function useAlienModule<P>(moduleStore: UseAlienModuleImportType<P>): P |
injectReducers(reducerToInject);
setAlienModule(module);
} catch (err) {
// throw new Error(`useAlienModule error: ${err}`);
// throw Error(`useAlienModule error: ${err}`);
setAlienModule(err);
}
})();
Expand All @@ -105,6 +116,7 @@ export default {
getReducerMap,
injectReducers,
reloadStore,
removeReducers,
useAlienModule,
withStoreModule,
};

0 comments on commit 8fae08c

Please sign in to comment.