Home > Blockchain >  Jest mock redux toolkit actions/store files
Jest mock redux toolkit actions/store files

Time:09-27

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: enter image description here

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.

  • Related