2

I have the following thunk:

export const deleteUser = (id: number) => (dispatch: ThunkDispatch<{}, {}, AnyAction>) =>
    axiosInstance.delete(`users/${id}`)
        .then(() => dispatch(deleted(id)))

I have tested this thunk:

it('creates DELETED action when user is deleted', () => {
    const deleteId: number = 1
    axiosInstance.delete.mockResolvedValue({})
    const expectedActions = [ deleted(deleteId) ];
    const store = mockStore();
    return store.dispatch(deleteUser(deleteId)).then(() => {
        expect(store.getActions()).toEqual(expectedActions)
    });
});

Now I am testing a button that dispatches this thunk. I could copy the previous approach (comparing dispatched actions to expected dispatched actions) but that seems unnecessary as I've already tested the thunk. It would require doing more test setup also (e.g. mocking axios)

All I need to do is test that the button calls dispatch with this thunk. I tried

beforeEach(() => {
    store = mockStore({ users: userList })
    store.dispatch = jest.fn()
    render(<Provider store={store}><UserTable /></Provider>)
});

it('should dispatch delete thunk when the delete button is clicked', () =>
    fireEvent.click(screen.getByRole('button', {name: /delete user 1/i}))
    expect(store.dispatch).toHaveBeenCalledTimes(1)
    expect(store.dispatch).toHaveBeenCalledWith(deleteUser(1))
})

but expect(store.dispatch).toHaveBeenCalledWith(deleteUser(1)) fails as you can't compare anonymous functions.

Is there another way, or do I need to 'retest' the thunk in the component?

jd96
  • 535
  • 3
  • 12
  • 1
    Discussion from a couple years ago might be relevant to your issue: https://github.com/facebook/jest/issues/6390 – spb Jan 07 '21 at 15:32
  • Ah yes, that's not a bad idea - testing the string content of the 2 functions: ```expect(store.dispatch.mock.calls[0][0].toString()).toBe(deleteUser(1).toString())```. Does feel a bit hacky though. – jd96 Jan 08 '21 at 11:12

1 Answers1

0

After thinking about this a bit more it doesn't make that much sense to check if a thunk is dispatched here. I've gone for the approach of separating out the component I want to test from the connected component - see https://stackoverflow.com/a/35578985/11550924. This allows me to write a test like

const mockDeleteUser = jest.fn()
it('should call deleteUser when delete button is clicked', () => {
    render(<UserTable users={userList} deleteUser={mockDeleteUser} />)
    fireEvent.click(screen.getByRole('button', {name: /delete user 1/i}))
    expect(mockDeleteUser).toHaveBeenCalledTimes(1)
    expect(mockDeleteUser).toHaveBeenCalledWith(1)
})

i.e. instead of mocking the dispatch function and checking a the deleteUser thunk got there, I'm mocking deleteUser and checking it gets called. The connected component can then be tested in an E2E test.

jd96
  • 535
  • 3
  • 12