Redux Unit Test

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

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.