I'm using Redux toolkit in a React.js app, and I extracted my logic as below:
Store.tsx
const history = createHashHistory();
const middleware = [
...getDefaultMiddleware().concat(routerMiddleware(history)),
];
const Store = configureStore({
reducer: {
router: connectRouter(history) as Reducer<any, any>,
/* my reducers */
}, middleware
});
MySlice.tsx
import {createSlice} from '@reduxjs/toolkit';
const initialState = {
/* content of my state */
};
const mySlice = createSlice(
{
name: "myState",
initialState,
reducers: {
myAction: (state: MyState) => {
// Whatever here...
}
},
extraReducers: builder => {
/* My extra reducers */
}
});
export const MySlice = mySlice;
And then I have my function:
MySuperFunc.tsx
export const superFunc = () => {
/* content of my function */
const {myAction} = MySlice.actions;
Store.dispatch(myAction({my: 'payload'}));
};
I would like to unit test it with Jest. I want to mock the content of my Store/MySlice because the configureStore
& createSlice
doing extra logics and seems to require some configuration.
I'm a little lost from React.js best practices & documentation regarding mock
, setMock
and spyOn
.
superFunc.spec.ts
const dispatchMockFn = jest.fn();
// Sol: 1
jest.mock('<< path >>/Store', () => ({dispatch: dispatchMockFn )});
// Sol: 2
jest.setMock('<< path >>/Store', {dispatch: dispatchMockFn});
// Sol: 3
jest.spyOn(Store, 'dispatch');
describe('superFunc', () => {
it('should call store', () => {
superFunc();
return expect(dispatchMockFn).toHaveBeenCalledWith(/* results of myAction({my: 'payload'}) */);
});
});
The problem I faced some error by code executed in the Store:
Seems to be normal because I used "Store" which is not exporting only an object, we have some extra code inside (createHistory etc.).
I searched a solution to mock entirely a module, that's why I try setMock/mock, it change a little bit the error but know it complaining regarding MySlice
(extraReducers) saying that my promises.fulfilled/rejected are not defined etc.
But I don't want to go deep inside the Store/Slice config, I just want to mock the file content.
Any idea/recommendation?
CodePudding user response:
I found the solution:
The jest.mock
factory must be adapted from your export (export default VS. export const = {...})
Example 1: MySuperFunc.tsx (with export default)
export default ({superFunc: () => 'hello world'});
Unit test:
import superFunc from './MySuperFunc';
jest.mock('./MySuperFunc', () => ({superFunc: jest.fn()});
it('should return toto', () => {
(MySuperFunc.superFunc as any).mockReturnValue('toto');
return expect(MySuperFunc.superFunc).toHaveBeenCalledWith('toto');
});
But, in the example 2 if you change your export by:
// MySuperFunc.tsx
export const MyVariable = {superFunc: () => 'hello world'});
Your jest.mock
must be adapted as:
jest.mock('./MySuperFunc', () => ({MyVariable: {superFunc: jest.fn()}});
So when I re-take my question, I have 2 choices:
- I can change my export in my slice file by using an
export default
- Or I adapt my
jest.mock
including{MySlice: {actions: {myAction: () => '...'}}}
My apologies, this topic is clearly not related to "redux toolkit" but more on how you deals with your export content from your typescript files.