简体   繁体   中英

Testing a Redux login Action

I'm hoping that I could ask for some help on how to test a Redux Action that involves a login API call. I've looked at some examples of testing an async Action, but I haven't wrapped my head around how to test the code below.

As a starting point, I would like to test that a) AUTH_USER is called if the .post request returns a 200 and b) localStorage` contains the token from the API call.

I've looked at using redux-mock-store , fetch-mock and isomorphic-fetch in order to mock the API calls to make sure I always receive the expected API response, but I have no idea where to start with the test.

Any help would be highly appreciated on a starting point for the tests! Even some help on just testing that 200 will return AUTH_USER would be appreciated!

Note: Elsewhere for other tests I'm using, redux-mock-store, enzyme, chai, expect, fetch-mock, isomorphic-fetch

import axios from 'axios';
import { browserHistory } from 'react-router';
import { API_URL } from 'config';
import {
  AUTH_USER
} from './types';

export function loginUser({ email, password }) {
  return function (dispatch) {
    axios.post(`${API_URL}/auth/login`, { email, password })
      .then((response) => {
        dispatch({ type: AUTH_USER });
        localStorage.setItem('token', response.data.token);
        browserHistory.push('/feature');
      })
      .catch(() => {
        dispatch(authError('Bad Login Info'));
      });
  };
}

Async Test Motivation

We want to ensure that a AUTHENTICATION_SUCCESS action is dispatched by our redux thunk middleware if the login is successful a AUTHENTICATION_FAILED action if the log in fails.

Remember we are not testing the Redux Thunk middleware, instead we are only testing our Thunk Action creator.

Testing a Redux Thunk action creator which queries an API

  1. Create a mock store for each unit test with redux-thunk middleware
  2. Use a mocking library such as nock to intercept http requests to test which actions are dispatched for a given type of request. Since we are testing a login request obvious cases here are http responses signalling login success and failure.
  3. Verify the correct action was dispatched to the store for a given http response.

Example

Tests

Here is an example of two tests for login success and failure using nock to mock the api call and the expect library for test assertions.

import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import nock from 'nock'
import expect from 'expect' // You can use any testing library

// modify these imports to suit your project
import * as actions from '../../actions/TodoActions' 
import * as types from '../../constants/ActionTypes'

import {
  AUTH_USER, AUTH_ERROR
} from './types';

const API_URL = 'www.api-example.com'
const middlewares = [ thunk ]
const mockStore = configureMockStore(middlewares)

describe('async actions', () => {
  afterEach(() => {
    nock.cleanAll()
  })

  it('creates AUTH_USER action when user is logged in', () => {
    nock(API_URL)
      .post(/auth/login)
      .reply(200, { data: 'Logged in successfully'] }})

    const expectedActions = [
      { type: AUTH_USER }
    ]
    const store = mockStore({ })

    return store.dispatch(actions.loginUser({'example@x.com','password'}))
      .then(() => { // return of async actions
        expect(store.getActions()).toEqual(expectedActions)
      })
  })

  it('creates AUTH_ERROR if user login fails', () => {
    nock(API_URL)
      .post(/auth/login)
      .reply(404, { data: {error: 404 }] }})

    const expectedActions = [
      { type: AUTH_ERROR }
    ]
    const store = mockStore({ })

    return store.dispatch(actions.loginUser({'example@x.com','password'}))
      .then(() => { // return of async actions
        expect(store.getActions()).toEqual(expectedActions)
      })
  })
})

Now to make the example work you need to add a return statement inside the function returned by your thunk action creator.

By eventually returning the promise given to us by axios.post we can add the .then call inside our test to make assertions about which actions have been dispatched after the promise has resolved.

Thunk action creator

import axios from 'axios';
import { browserHistory } from 'react-router';
import { API_URL } from 'config';
import {
  AUTH_USER
} from './types';

export function loginUser({ email, password }) {
  return function (dispatch) {
    return axios.post(`${API_URL}/auth/login`, { email, password })
      .then((response) => {
        dispatch({ type: AUTH_USER });
        localStorage.setItem('token', response.data.token);
        browserHistory.push('/feature');
      })
      .catch(() => {
        dispatch(authError('Bad Login Info'));
      });
  };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM