Mock Dispatch Function Is Not Called
I am writing a test for async action creator but encountered a problem where it states "Expected mock function to have been called" with:
[{"type": "GET_LOGIN_SUCCESS", "value": true}]
But it was not called.
I am not sure where exactly the problem is. If anyone could help that will be greatly appreciated.
Here's my actions.js
import { GET_LOGIN_SUCCESS } from './constants'
export const getLoginInfo = () => {
return (dispatch, getState, axiosInstance) => {
return axiosInstance.get('/api/isLogin.json')
.then((res) => {
dispatch({
type: GET_LOGIN_SUCCESS,
value: res.data.data.login
})
console.log('finishing dispatch')
})
}
}
actions.test.js
import { getLoginInfo } from './actions'
import { GET_LOGIN_SUCCESS } from './constants'
describe('async actions', () => {
it('dispatches GET_LOGIN_SUCCESS when getting login finishes', () => {
const axiosInstance = {
get: jest.fn(() => Promise.resolve({ data: { data: {login : true }}}))
}
const dispatch = jest.fn()
getLoginInfo()(dispatch, null, axiosInstance)
expect(dispatch).toHaveBeenCalledWith({
type: GET_LOGIN_SUCCESS,
value: true
})
})
})
Answer
The problem is that jest can't know that there are async task involved. So in your case you create a mock that returns a promise, and dispatch is called when the promise is resolved. As JavaScript is single threaded, it first evaluate the code in the test and all async tasks are done afterwards. So you need to make jest aware of the promise by using async/await
:
describe('async actions', () => {
it('dispatches GET_LOGIN_SUCCESS when getting login finishes', async() => {
const p = Promise.resolve({ data: { data: {login : true }}}))
const axiosInstance = {
get: jest.fn(() => p
}
const dispatch = jest.fn()
getLoginInfo()(dispatch, null, axiosInstance)
await p // even it sounds not very logically you need to wait here
expect(dispatch).toHaveBeenCalledWith({
type: GET_LOGIN_SUCCESS,
value: true
})
})
As @brian-lives-outdoors points out, getLoginInfo
returns the promise as well so you could also just wait for the result of the call:
it('dispatches GET_LOGIN_SUCCESS when getting login finishes', async() => {
const axiosInstance = {
get: jest.fn(() => Promise.resolve({ data: { data: {login : true }}}))
}
const dispatch = jest.fn()
await getLoginInfo()(dispatch, null, axiosInstance)
expect(dispatch).toHaveBeenCalledWith({
type: GET_LOGIN_SUCCESS,
value: true
})
})
There is a epic article that describes the whole topic
Related Questions
- → Import statement and Babel
- → should I choose reactjs+f7 or f7+vue.js?
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → .tsx webpack compile fails: Unexpected token <
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → React Native with visual studio 2015 IDE
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM
- → How do I determine if a new ReactJS session and/or Browser session has started?
- → Alt @decorators in React-Native
- → How to dynamically add class to parent div of focused input field?