This article addresses how to mock useDispatch
in component test code. Moreover, it suggests a solution to the situation where action
ends up being an anonymous function.
[Function (anonymous)]
How to test a component with useDispatch
Let’s say you want to test a component where an action will be dispatched by click event.
mock setup
jest.mock('react-redux');
const useDispatchMock = useDispatch as jest.Mock;
const mockNotificationClear = jest.fn();
useDispatchMock.mockImplementation(() => {
return jest.fn().mockImplementation((action) => {
switch (action.type) {
case 'notification/clear':
mockNotificationClear();
break;
default:
break;
}
});
});
test
it('notification clears', () => {
renderComponent(); // render a component to test
act(() => {
fireEvent.click(screen.getByTestId('notification-clear'));
});
expect(mockNotificationClear).toBeCalled();
});
How to handle action that references ‘anonymous function’
problem
I encountered a situation where action.type
is undefined when dispatch is called. So, I used console.log
to inspect what action
references.
[Function (anonymous)]
Because of this, I cannot identify which action has been called!
solution
mock setup
jest.mock('react-redux');
const useDispatchMock = useDispatch as jest.Mock;
const mockNotificationClear = jest.fn();
const mockDispatch = jest.fn(); // default to this if action.type cannot be identified
useDispatchMock.mockImplementation(() => {
return jest.fn().mockImplementation((action) => {
switch (action.type) {
case 'notification/clear':
mockNotificationClear();
break;
default:
mockDispatch(action(useDispatchMock).arg);
break;
}
});
});
- Test if
dispatch
is called even though we wouldn’t know which action is called. - Pass the arguments that has been passed to the anonymous action so that we can test if the correct arguments are passed.
action().arg
allows access to what arguments has been passed. - Pass
useDispatchMock
toaction()
. Unless so, if there is another dispatch to run, it wouldn’t be called.
TypeError: dispatch is not a function
test
it('updates a post', () => {
renderComponent(); // render a component to test
const postTitle = screen.getByTestId('post-title');
const postBody = screen.getByTestId('post-body');
fireEvent.change(postTitle, { target: { value: 'test' }});
fireEvent.change(postBody, { target: { value: 'test' }});
act(() => {
fireEvent.click(screen.getByTestId('update-post'));
});
expect(mockDispatch).toBeCalledWith({ title: 'test', body: 'test' });
});
Thanks for reading.
Hope you enjoyed the article. If you have any question or opinion to share, feel free to write some comments.
Facebook Comments