In this tutorial, I’ll show you how to write the redux unit test for remote server called.
Prepare Sample Data
json-server --watch data.json
Mock Data
src/ducks/__tests__/feeds/mockData.js
export const mockData = { data: [ 1, 2, 3 ], links: { first: 'https://xxx.com/v1/moment/public/explore?page=1', last: 'https://xxx.com/v1/moment/public/explore?page=93', prev: null, next: 'https://xxx.com/v1/moment/public/explore?page=2' }, meta: { current_page: 1, from: 1, last_page: 93, path: 'https://xxx.com/v1/moment/public/explore', per_page: '1', to: 1, total: 93 }, status: 'success', message: null }
ActionCreator, Reducers
redux/ducks/moments.js
import axios from 'axios'; export const types = { FETCH_MOMENTS_REQUEST: 'FETCH_MOMENTS_REQUEST', FETCH_MOMENTS_SUCCESS: 'FETCH_MOMENTS_SUCCESS', FETCH_MOMENTS_FAILURE: 'FETCH_MOMENTS_FAILURE', } const DEFAULT_STATE = { data: [], error: null, loading: false, refreshing : false, page : 1, total : 0, } ** Action ** export const actions = { fetchMoments(page = 1) { return function(dispatch, getState) { dispatch({ type: types.FETCH_MOMENTS_REQUEST, payload: { page : page, loading: true, } }); return axios.get(`http://localhost:3000/data?page=${page}&per_page=20`) .then(function(response) { const { data } = response; const { meta, links } = data; dispatch({ type: types.FETCH_MOMENTS_SUCCESS, payload: { data: data.data, loading: false, total : meta.total, page: meta.current_page } }); }).catch(err => { dispatch({ type: types.FETCH_MOMENTS_FAILURE, payload: err.message, }); }); }; }, }; ** Reducer ** export function reducer(state = DEFAULT_STATE, action ) { switch(action.type) { case types.FETCH_MOMENTS_REQUEST: return { ...state, loading: true, refreshing: false, total : 0, }; case types.FETCH_MOMENTS_SUCCESS: return { ...state, loading: false, refreshing: false, data: action.payload, }; case types.FETCH_MOMENTS_FAILURE: return { ...state, loading: false, refreshing: false, error: action.payload, }; } }
Unit Test
Request Ajax Call Test
Execute yarn jest src/ducks/__tests__/moments/request.spec.js
import { types, actions } from '../../moments'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { mockData } from '../feeds/mockData'; // yarn jest src/ducks/__tests__/moments/request.spec.js describe('fetch moments when Refreshing', function() { var dispatch, mock, thunk; beforeEach(function() { dispatch = jest.fn(); thunk = actions.fetchMoments() mock = new MockAdapter(axios); }); // spy = dispatch function, this code will run => dispatch({ type: types.FETCH_FEED_REQUEST, }); // thunk = return function (dispatch, getState) ... it('should dispatch the REQUEST action when the action is dispatched', function() { const page = 1; const spy = jest.fn(); const thunk = actions.fetchMoments(page); thunk(spy); expect(spy.mock.calls[0][0]).toEqual({ type: types.FETCH_MOMENTS_REQUEST, payload : { page : 1, loading: true, } }); }); it('should have correct page 2 corresponds', function() { const page = 2; const spy = jest.fn(); const thunk = actions.fetchMoments(page); thunk(spy); return expect(spy.mock.calls[0][0]).toEqual({ type: types.FETCH_MOMENTS_REQUEST, payload : { page : 2, loading: true, } }); }); });
Success Ajax Call Test
Execute yarn jest src/ducks/__tests__/moments/success.spec.js
import { types, actions } from '../../moments'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { mockData } from '../feeds/mockData'; var Q = require('q'); var _ = require('lodash'); describe('fetch moments when Successful', function() { var dispatch, deferred, mock, thunk; beforeEach(function() { deferred = Q.defer(); dispatch = jest.fn(); thunk = actions.fetchMoments() mock = new MockAdapter(axios); }); it('should call the correct url', function() { spyOn(axios, 'get').and.returnValue(deferred.promise); actions.fetchMoments()(dispatch); expect(axios.get).toHaveBeenCalledWith('http://localhost:3000/data?page=1&per_page=20'); }); it('should not call the url', function() { spyOn(axios, 'get').and.returnValue(deferred.promise); actions.fetchMoments()(dispatch); expect(axios.get).not.toHaveBeenCalledWith('http://google.com/data'); }); it('should dispatch the SUCCESS action when the data is fetch successfully', () => { mock.onGet('http://localhost:3000/data?page=1&per_page=20').reply(200, mockData ); thunk(dispatch).then( function() { expect(dispatch.mock.calls[1][0].type).toEqual( types.FETCH_MOMENTS_SUCCESS ); }); }); it('should contains the correct payload from the response', () => { mock.onGet('http://localhost:3000/data?page=1&per_page=20').reply(200, mockData ); thunk(dispatch).then( function() { expect(dispatch.mock.calls[1][0].payload).toEqual({ data: [ 1, 2, 3, ], loading: false, total: 93, page: 1 }); }); }); });
Failure Ajax Call Test
Execute yarn jest src/ducks/__tests__/moments/failure.spec.js
import { types, actions } from '../../moments'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { mockData } from '../feeds/mockData'; var Q = require('q'); var _ = require('lodash'); describe('fetch moments when Successful', function() { var dispatch, deferred, mock, thunk; beforeEach(function() { deferred = Q.defer(); dispatch = jest.fn(); thunk = actions.fetchMoments() mock = new MockAdapter(axios); }); it('should dispatch the FAILURE action when the data is not available', function() { mock.onGet('http://localhost:3000/data?page=1&per_page=20').reply(404); thunk(dispatch).then( function() { return expect(dispatch.mock.calls[1][0]).toEqual({ type: types.FETCH_MOMENTS_FAILURE, payload: 'Request failed with status code 404', }); }); }); });
Redux Unit Test