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