I am using new Redux toolkit. New Redux-toolkit much efficient than old redux. I have create multiple reducers and actions by using new Redux-toolkit. I destructor the redux-toolkit setup little bit. I am using Enzyme and Jest for unit test. My redux counter intialState is 1. From my testing, inside it
scope I first take the intialState then after simulate('click') increase button, I got result 2, which I expected. When I try to test my decrease button inside the it
scope it takes the result from increase's it
scope. If I put intialState 1 inside the decrease button's it
scope, it gives me failed test because it expected 2. I think I need to create mockStore for this counter.test
. Since the redux-toolkit's syntax are new to me, I don't how to create the mockstore inside counter.test
test suite.
Ps. There is also other react component where it fetch data, todolist. I also want to do unit test
those components. if anyone help me to test those components I will be really glad. I am newbie in unit testing ????.
I uploaded my code to Codesandbox.
Below I am explaining how i did the setup and passing to React's component.
This is counter reducer
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
"name": `counter`,
"initialState": 1 as number,
"reducers": {
"increment": (state) => state + 1,
"decrement": (state) => state - 1
}
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
This is combineReducers
import { combineReducers } from 'redux';
import counter from 'store/reducer/counter';
import todo from 'store/reducer/todo/todo';
import fetchUser from 'store/reducer/fetch';
import fetching from 'store/reducer/createAsyncAxios';
const rootReducer = combineReducers({
counter, //This is my counter Reducer
todo,
fetchUser,
fetching
});
export type IRootState = ReturnType<typeof rootReducer>;
export default rootReducer;
This is my store file
import { configureStore, Action, getDefaultMiddleware } from '@reduxjs/toolkit';
import { ThunkAction } from "redux-thunk";
import rootReducer, { IRootState } from 'store/combineReducer';
const store = configureStore({
"reducer": rootReducer,
"middleware": [...getDefaultMiddleware()]
});
export type AppThunk = ThunkAction<void, IRootState, null, Action<string>>
export default store;
Ps. I destructor the rootfile. first I created a root file where I imported store then I connected to App
. I did it because I can direct import rootfile to test suite
import React from 'react';
import { Provider } from 'react-redux';
import store from 'store/store';
import { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
body {
background-color: #282c34;
color: white;
font-family: "Lucida Console", Courier, monospace;
}
`;
interface IProps {
children: JSX.Element[] | JSX.Element;
}
export default ({ children }: IProps) => {
return (
<Provider store={store}>
<GlobalStyle />
{children}
</Provider>
);
};
This is how connected my rootfile to App
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import Root from './root';
ReactDOM.render(
<Root>
<App />
</Root>
,
document.getElementById(`root`)
);
This is my counter component
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from 'store/reducer/counter/index';
import { IRootState } from 'store/combineReducer';
import styled from 'styled-components';
const Button = styled.button`
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
`;
const Text = styled.h1`
color: blue;
`;
export default () => {
const counter = useSelector((state: IRootState) => state.counter);
const dispatch = useDispatch();
return (
<div >
<Text>{counter}</Text>
<Button data-test="increment" onClick={() => dispatch(increment())}>
Increment counter
</Button>
<br></br>
<br></br>
<Button data-test="decrement" onClick={() => dispatch(decrement())}>
Decrement counter
</Button>
</div>
);
};
This is my counter
test suite
import React from 'react';
import { mount } from "enzyme"; // mount is full dom renderning function with children
import Counter from 'components/counter';
import Root from "root/index";
let wrapped;
beforeEach(() => {
// I need to create mock store in here. I don't know how to do that.
wrapped = mount(
<Root >
<Counter />
</Root>
);
// console.log(wrapped.debug());
});
afterEach(() => {
wrapped.unmount(); // it cleans the mount after test.
});
describe(`This is counter component`, () => {
it(``, () => {
expect(wrapped.find(`h1`).text()).toEqual(`1`);
});
it(`after click it will increase the value`, () => {
expect(wrapped.find(`h1`).text()).toEqual(`1`);
wrapped.find(`button`).at(0).find(`[data-test="increment"]`).simulate(`click`);
expect(wrapped.find(`h1`).text()).toEqual(`2`);
});
it(`after click it will decrease the value`, () => {
expect(wrapped.find(`h1`).text()).toEqual(`1`); // Test failed: because it Received: "2"
wrapped.find(`button`).at(1).find(`[data-test="decrement"]`).simulate(`click`);
expect(wrapped.find(`h1`).text()).toEqual(`2`); //
});
});
redux-mock-store
? – k-wasilewski