Izabayo Blaise
Izabayo Blaise

Reputation: 95

How to mock a function and expect it to be called?

I am new to react-testing-library and I have been trying to test one function for a long time. for example, I want to check if when a button is clicked a given function is called and it's throwing errors. so any help would be highly appreciated and if possible share with me any helpful resources.

signin.js

export default class SignIn extends Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    handleClose = (event, reason) => { };
    validate = () => { };
    change = (e) => { };
    onSubmit = (e) => { };

    render() {
        return (<div>...</div>);
    }
}

Full: https://github.com/blaise82/react-testing-library-try/blob/master/src/views/SignIn.js

this is my test

it('should submit form', async () => {
    const { getByLabelText, getByText, container, debug } = render(<SignIn />);
    const change = jest.fn();
    const onSubmit = jest.fn();
    const email = getByLabelText('email');
    const password = getByLabelText('password');
    const submit = getByLabelText('submit');

    userEvent.type(email, '[email protected]');
    expect(email.value).toBe('[email protected]');
    expect(password.value).toBe('');
    expect(change).toHaveBeenCalled();

    console.log(password)
    await userEvent.click(submit);
    expect(onSubmit).toHaveBeenCalled();

});

Full: https://github.com/blaise82/react-testing-library-try/blob/master/src/test/signin.test.js

results

>    Expected number of calls: >= 1
>     Received number of calls:    0

please let know what I am doing wrong.

Full code on GitHub: https://github.com/blaise82/react-testing-library-try

Upvotes: 8

Views: 53068

Answers (2)

dhananzen
dhananzen

Reputation: 264

You can test a function by mocking all that is coming from outside of the component (aka dependencies) like - a prop callback, an external library api etc.

Before starting, let's go through what all functions are in the component. Going through the component, I can list them as below:

  1. Event handlers on elements [like handleClose, onSubmit, change in the component]
  2. Functions internal to the component which do not interact with the state/functions outside the component [validate]
  3. prop functions/library apis being called [axios.post]

Let's discuss them one by one --

  • Event handlers &
  • Functions internal to component not interacting with state/functions outside of the component

==> Event handlers that are attached to elements can safely be expected to get called. You don't need to test them if they are called. Rather, what you should test is the after-effect of them being called. Also the functions like validate

Let's take example of the change function that you are trying to test. This function after being called sets the state and the state gets reflected into the form elements. We can assert values of the form elements with a helper like this.

  • prop functions/library apis being called [axios.post]

==> These functions can be mocked and tested for the number of calls/parameters they are called with. https://jestjs.io/docs/en/mock-functions.html#mocking-modules

In addition to the snippet of mocking jest as given in the link above, in your case -

axios.post.toHaveBeenCalledWith(expectedParms);

Also you can make it return results/errors you want and test respective component behaviour.

Hope you find this helpful. Cheers!

Upvotes: 13

mindlis
mindlis

Reputation: 1677

I think this is because you are not actually passing in your mocked functions to the component. You're just instantiating two constants that happen to have the name of the functions you're trying to watch, but are not actually being used anywhere in your component.

It sounds like you want to spy on your component's internal functions to see that they've been called.

Here's something of an example (not tested) based on a post (linked below) that might help you.

describe('spying on "onSubmit" method', () => {
  it('should call onSubmit when the button is clicked', () => {
    const wrapper = shallow(<SignIn />); 
    const instance = wrapper.instance();

    jest.spyOn(instance, 'onSubmit');

    wrapper.find('button').simulate('click');
    expect(instance.onSubmit).toHaveBeenCalled();
  });
});

Post: https://bambielli.com/til/2018-03-04-directly-test-react-component-methods/#spying-on-incrementcounter

Upvotes: 2

Related Questions