Vytautas Butkus
Vytautas Butkus

Reputation: 5535

How to mock and test redux-thunk actions?

I can't find a way how to properly test async redux actions that are using other actions inside it's body:

import {postRequest} from './http'

export function saveAnswer (id, answer) {
  return (dispatch) => {
    dispatch({type: SAVE_ANSWER})

    return dispatch(postRequest(ANSWERS_ENDPOINT, {id, answer}))
  }
}

I want to stub postRequest so that it's logic is not executed.

I have setup for spec:

import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import * as ACTIONS from '../answers'
import * as HTTP_ACTIONS from '../http'

const mockStore = configureMockStore([thunk])
const store = mockStore({})


describe('saveAnswer()', () => {
  it('test', () => {
    sinon.stub(HTTP_ACTIONS, 'postRequest').returns(Promise.resolve({}))

    store.dispatch(ACTIONS.saveAnswer(ID, ANSWER))
  })
})

When I run spec I get this error: Error: Actions must be plain objects. Use custom middleware for async actions.

I don't understand what am I doing wrong but it has to do something with stubbing postRequest action.

How can I properly stub that action?

Upvotes: 0

Views: 952

Answers (1)

Bartek Fryzowicz
Bartek Fryzowicz

Reputation: 6674

If you use redux-thunk argument of dispatch must be a function or plain object. In your case postRequest returns Promise object which is not plain object (nor function;). As a result you call dispatch with promise object as argument. So please make sure that you call dispatch with argument which is either function or plain action object (with type property).

You can rewrite your code like this (assuming that postRequest returns promise) and then error should disappear:

import {postRequest} from './http'

export function saveAnswer (id, answer) {
  return (dispatch) => {
    dispatch({type: SAVE_ANSWER})
    postRequest(ANSWERS_ENDPOINT, {id, answer})
      .then((response) => dispatch({
         type: ANSWER_SAVED,
         data: response
      }));
  };
}

Answer update after comment:

So since postRequest doesn't return Promise object but function the problem is in how you're stubbing it. Please try this (stub should also return function instead of Promise object):

const mockFuntion = () => Promise.resolve({}); // here can also  be an spy function if needed
sinon.stub(HTTP_ACTIONS, 'postRequest').returns(mockFuntion);

Upvotes: 1

Related Questions