Testing API Reduction Actions

What is the best way to test this feature.

export function receivingItems() { return (dispatch, getState) => { axios.get('/api/items') .then(function(response) { dispatch(receivedItems(response.data)); }); }; } 

I currently have

 describe('Items Action Creator', () => { it('should create a receiving items function', () => { expect(receivingItems()).to.be.a.function; }); }); 
+6
source share
3 answers

From Redux "Writing Tests" Recipe:

For asynchronous action creators using Redux Thunk or other middleware, it's best to mock Redux's test repository completely. You can still use applyMiddleware() with the mock repository as shown below (you can find the following code in redux-mock-store ). You can also use nock to mock HTTP requests.

 function fetchTodosRequest() { return { type: FETCH_TODOS_REQUEST } } function fetchTodosSuccess(body) { return { type: FETCH_TODOS_SUCCESS, body } } function fetchTodosFailure(ex) { return { type: FETCH_TODOS_FAILURE, ex } } export function fetchTodos() { return dispatch => { dispatch(fetchTodosRequest()) return fetch('http://example.com/todos') .then(res => res.json()) .then(json => dispatch(fetchTodosSuccess(json.body))) .catch(ex => dispatch(fetchTodosFailure(ex))) } } 

can be verified as follows:

 import expect from 'expect' import { applyMiddleware } from 'redux' import thunk from 'redux-thunk' import * as actions from '../../actions/counter' import * as types from '../../constants/ActionTypes' import nock from 'nock' const middlewares = [ thunk ] /** * Creates a mock of Redux store with middleware. */ function mockStore(getState, expectedActions, done) { if (!Array.isArray(expectedActions)) { throw new Error('expectedActions should be an array of expected actions.') } if (typeof done !== 'undefined' && typeof done !== 'function') { throw new Error('done should either be undefined or function.') } function mockStoreWithoutMiddleware() { return { getState() { return typeof getState === 'function' ? getState() : getState }, dispatch(action) { const expectedAction = expectedActions.shift() try { expect(action).toEqual(expectedAction) if (done && !expectedActions.length) { done() } return action } catch (e) { done(e) } } } } const mockStoreWithMiddleware = applyMiddleware( ...middlewares )(mockStoreWithoutMiddleware) return mockStoreWithMiddleware() } describe('async actions', () => { afterEach(() => { nock.cleanAll() }) it('creates FETCH_TODOS_SUCCESS when fetching todos has been done', (done) => { nock('http://example.com/') .get('/todos') .reply(200, { todos: ['do something'] }) const expectedActions = [ { type: types.FETCH_TODOS_REQUEST }, { type: types.FETCH_TODOS_SUCCESS, body: { todos: ['do something'] } } ] const store = mockStore({ todos: [] }, expectedActions, done) store.dispatch(actions.fetchTodos()) }) }) 
+11
source

I would use the axios stub (e.g. using mock-require ) and write a test that actually calls receivingItems()(dispatch, getState) and ensures that dispatch is called with the correct data.

+2
source

I decided it another way: introducing axioms in dependence on action. I prefer this approach with respect to rewriting dependencies.

So, I used the same approach to test the components related to reduction. When I export actions, I export two versions: one with (for use for components) and one without (for testing) binding bindings.

Here's what the actions.js file looks like:

 import axios from 'axios' export const loadDataRequest = () => { return { type: 'LOAD_DATA_REQUEST' } } export const loadDataError = () => { return { type: 'LOAD_DATA_ERROR' } } export const loadDataSuccess = (data) =>{ return { type: 'LOAD_DATA_SUCCESS', data } } export const loadData = (axios) => { return dispatch => { dispatch(loadDataRequest()) axios .get('http://httpbin.org/ip') .then(({data})=> dispatch(loadDataSuccess(data))) .catch(()=> dispatch(loadDataError())) } } export default { loadData: loadData.bind(null, axios) } 

Then testing with jest (actions.test.js):

 import { loadData } from './actions' describe('testing loadData', ()=>{ test('loadData with success', (done)=>{ const get = jest.fn() const data = { mydata: { test: 1 } } get.mockReturnValue(Promise.resolve({data})) let callNumber = 0 const dispatch = jest.fn(params =>{ if (callNumber===0){ expect(params).toEqual({ type: 'LOAD_DATA_REQUEST' }) } if (callNumber===1){ expect(params).toEqual({ type: 'LOAD_DATA_SUCCESS', data: data }) done() } callNumber++ }) const axiosMock = { get } loadData(axiosMock)(dispatch) }) }) 

When using actions inside a component, I import everything:

import Actions from './actions'

And send:

Actions.loadData() // this is the version with axios binded.

+1
source

All Articles