Unit testable components pt.4: Testing the Redux data flow
Testing actions within actions
Testing redux is verbose. Sometimes it is even difficult. But it doesn't matter where you do it. It will always be challenging. The difference is that the DOM is irrelevant for my approach to testing.
I use redux-mock-store to test my actions. No need for enzyme. One less moving part to deal with. That is the whole point of this testing style. Here is what a sample test would look like
The action process
const processHomeMount = () =>
async (dispatch, getState) => {
try {
const type = getState().home.topSearches.focusedDateRange
const { endDate, startDate } = createPresentDateRange({ daysAgo: 100 })
await Promise.all([
dispatch(fetchPopularSearches({ type, limit: TOP_SEARCH_ENTRY_COUNT })),
dispatch(fetchNews({ startDate, endDate }))
])
} catch (error) {
return new Error(error)
}
}
Imports
// middleware to be passed into mocked store
import thunk from 'redux-thunk'
// action testing npm package
import configureStore from 'redux-mock-store'
import {
getPopularSearches,
getNews,
} from "Api/ApiCalls/HomeApi/HomeApi"
Mocks
// mock the functions so I can use returnValueOnce
jest.mock('Api/ApiCalls/HomeApi/HomeApi')
// api call return value mock
getPopularSearches.returnValueOnce(popularSearchesPayload)
getNews.returnValueOnce(newsPayload)
// setting up my mock store that dispatches actions and keeps track of emitted actions
const initialState = {}
const middleware = [thunk]
const mockStore = configureStore(middleware)(initialState)
Assertion
const processHomeMountExpectedActions = [
{
news: [{
content: `Welcome to my app!`,
createdAt: '2018-12-06T07:47:51.119Z',
id: 2,
title: 'sample news entry!',
version: null
}],
type: 'SET_NEWS'
},
{
type: 'SET_FOCUSED_TOP_SEARCH',
focusedDateRange: 'week',
},
{
type: 'SET_TOP_SEARCH_ENTRIES',
entries: [{name: 'the office'}]
},
]
describe('processHomeMount', () => {
beforeEach(() => {
// remove all actions from mockStore before each assertion in test file
mockStore.clearActions()
})
it('dispatches expected objects', () => {
mockStore.dispatch(processHomeMount())
const emittedActions = mockStore.getActions() // array of all actions run
expect(emittedActions).toEqual(processHomeMountExpectedActions)
})
})
All done
There you have it. Test Redux and React components in their own respective environments. Use
enzyme
to test components and
redux-mock-store
for your business logic. Not both at once.
Comments
Post a Comment