How to test with Jest whether action created by action creator (and not passed as prop) fires?

Viewed 656

I try to test whether a given action is really fired in a component. It could be easy if the callback with action was delivered as a prop, but it's not clear for me how to do it in my case. Here is the component:

export const Modal = (props: appendProps): JSX.Element => {
    const { items, activeScope } = props;
    const primary = items[0] === activeScope;
    const { closeInput, appendItem } = useDispatchAction();
{...}
    <Button
      variant="contained"
      size="large"
      className="modal-content__button"
      color="secondary"
      onClick={() => {
           closeInput();
      }}
      >
       Zamknij
   </Button>

useDispatchAction is below:

import { useDispatch } from 'react-redux';
import { bindActionCreators } from 'redux';
import { actionCreators } from '../redux';

const useDispatchAction = () => {
    const dispatch = useDispatch();
    return bindActionCreators(actionCreators, dispatch);
};

export default useDispatchAction;

And test itself below

describe('Test button actions', () => {
    const closeInput = jest.fn();
    jest.mock('../../src/hooks/useDispatchAction', () => ({closeInput}));

    beforeEach(() => {
        render(<Modal />);
    });
    afterEach(() => cleanup());
    test('component fires closeInput', () => {
        const closeButton = screen.getByRole('button', { name: 'Zamknij' });
        expect(closeButton).toBeInTheDocument();
        userEvent.click(closeButton);
        expect(closeInput).toBeCalled();
    });
});

but this keep telling me that function has been called 0 times and not 1 at least

2 Answers

When you jest.mock, you get a function that returns undefined by default. So, if useDispatchAction returns undefined, you can't go const { closeInput, appendItem } = useDispatchAction();, because you cannot destructure from undefined.

However, you can supply a second argument to jest.mock:

const closeInput = jest.fn()
jest.mock('../../src/hooks/useDispatchAction', () => ({ closeInput }))

Now you've mocked useDispatchAction to return something that looks more like your original function, except that the action returns something you can assert was called.

You can test it like this:

expect(closeInput).toHaveBeenCalled()

I think this should work, but I haven't tested this particular code.

What finally works is:

const actions = {
    closeInput: jest.fn(),
    appendItem: jest.fn(),
};

jest.mock('../../src/hooks/useDispatchAction', () => () => actions);

describe('Given Modal component', () => {
    describe('when "Zamknij" button is clicked', () => {
        it('should call closeInput function', async () => {
            actions.closeInput.mockClear();

            const { findByText } = render(<Modal />);
            const closeButton = await findByText('Zamknij');

            fireEvent.click(closeButton);

            expect(actions.closeInput).toHaveBeenCalled();
        });
    });
});

Related