Answer the question
In order to leave comments, you need to log in
How to test asynchronous actions in Redux?
Hello, I started to study testing and chose the Jest library . I am using the React Redux libraries.
And I use redux-thunk to send asynchronous actions. I know how to test common actions. But I can't figure out how to test asynchronous requests.
Here is the test I wrote:
import {initialState} from 'reducers/commonReducer';
import * as actions from '../../../frontend/src/actions/authActions';
import {asyncConstant} from '../../../frontend/src/constant/asyncConstant';
import {commonConstant} from '../../../frontend/src/constant/commonConstant';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('async actions', () => {
it('should dispatch actions of ConstantA and ConstantB', () => {
const expectedActions = [
{type: `${commonConstant.REQUES_FOR_AUTH}${asyncConstant.BEGIN}`},
{type: `${commonConstant.REQUES_FOR_AUTH}${asyncConstant.FAILURE}`},
];
const store = mockStore({ initialState });
store.dispatch(actions.login('a', 's'));
expect(store.getActions()).toEqual(expectedActions);
});
});
import { Dispatch } from '../../../node_modules/redux';
import {asyncConstant} from '../constant/asyncConstant';
import {commonConstant} from '../constant/commonConstant';
import {authenticationRequest} from 'api/authApi';
export const login = (email: string, password: string): any => {
return (dispatch: Dispatch) => {
dispatch({type: `${commonConstant.REQUES_FOR_AUTH}${asyncConstant.BEGIN}`});
authenticationRequest(email, password)
.then((data: any) => {
if (data.auth) {
dispatch({type: `${commonConstant.REQUES_FOR_AUTH}${asyncConstant.SUCCESS}`});
} else {
dispatch({type: `${commonConstant.REQUES_FOR_AUTH}${asyncConstant.FAILURE}`, payload: {getServerDataError: true}});
}
})
.catch((error: any) => {
console.log(error);
dispatch({type: `${commonConstant.REQUES_FOR_AUTH}${asyncConstant.FAILURE}`, payload: {connectServerError: true}});
});
};
};
import axios, { AxiosPromise } from 'axios';
import {config} from '../config';
import {ServerRoters} from '../constant/serverRouters';
export function authenticationRequest(email: string, password: string): AxiosPromise {
return axios.post(`${config.apiPrefix}:${config.serverPort}/${ServerRoters.auth}`,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
email,
password,
})
.then((response: any) => {
if (response.status === 200 || 304) {
return response;
}
}).then((response: any) => {
if (response.data.auth) {
return {...response.data};
} else {
return {...response.data, auth: false };
}
});
}
import * as hash from 'object-hash';
import * as React from 'react';
export interface IAuthDispatch {
login: (email: string, password: string) => any;
}
export class Auth extends React.Component<IAuthDispatch> {
public state = {
emailValue: '',
passwordValue: '',
};
public onChangeInput = (e: React.FormEvent<HTMLInputElement>) => {
const state: any = {...this.state};
state[e.currentTarget.name] = e.currentTarget.name === 'passwordValue' ? hash(e.currentTarget.value) : e.currentTarget.value;
this.setState(state);
}
public onHandleSubmit = () => {
console.log(this.state);
this.props.login(this.state.emailValue, this.state.passwordValue);
}
public render() {
return (
<React.Fragment>
<form onSubmit={ (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); } }>
<input onChange={this.onChangeInput} type='text' name='emailValue' placeholder='user name' />
<input onChange={this.onChangeInput} type='password' name='passwordValue' placeholder='password' />
<input onClick={this.onHandleSubmit} type='submit' name='submit'/>
</form>
</React.Fragment>
);
}
}
export enum asyncConstant {
'BEGIN' = '_BEGIN',
'SUCCESS' = '_SUCCESS',
'FAILURE' = '_FAILURE',
}
export enum commonConstant {
'REQUES_FOR_AUTH' = 'REQUES_FOR_AUTH',
}
export enum ServerRoters {
auth = 'api/auth/login',
getRole = 'api/auth/role',
logout = 'api/auth/logout',
getTestListData = 'api/student/gettestlist',
getIssues = 'api/student/gettestissues',
}
import {connect} from 'react-redux';
import {Dispatch} from 'redux';
import * as actions from 'actions/authActions';
import {Auth, IAuthDispatch} from 'components/Auth';
const mapDispatchToProps = (dispatch: Dispatch): IAuthDispatch => ({
login: (email: string, password: string) => {
dispatch(actions.login(email, password));
},
});
export const ContainerAuth = connect(
mapDispatchToProps,
)(Auth);
Answer the question
In order to leave comments, you need to log in
Redux-thunk is well tested ( documentation ).
The bottom line is that you need to test the expectation: so many actions happened in the store, with such and such data and types (which is what you do for Request + Error), you do not have enough mock to request the server.
There is a text and video " Testing redux actions and reducers " with details if you don't like the documentation example.
An example of a login test from the second test task .
This is the biggest problem with redux-thunk. It is difficult to test, because you need to mock getStore and dispatch, as well as a request to the server. The only way out is to write your own implementation of store.
As an example: https://michalzalecki.com/testing-redux-thunk-like...
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question