ciz30
ciz30

Reputation: 453

React-testing-library mock function not called

i'm trying to test my component:

in my componet when i click to button i call some function and pass there some id.

my test:

it("should call function on submit click", async () => {
  const wrapper = render(<Component />);
   const id = "1";
  const handleSubmit = jest.fn();
  const SubmitBtn = wrapper.getByTestId("submit-btn");
  fireEvent.click(SubmitBtn);
  await waitFor(() => wrapper);
  expect(handleSubmit).toHaveBeenCalled();
});

here i tried:

expect(handleSubmit).toHaveBeenCalled();
expect(handleSubmit).toHaveBeenCalledWith(id);
expect(handleSubmit).toBeCalled();
expect(handleSubmit).toBeCalledWith(id)

tried everything but it's not works..

 expect(jest.fn()).toBeCalled()
    Expected number of calls: >= 1
    Received number of calls:    0

Upvotes: 0

Views: 7024

Answers (1)

Florian Motteau
Florian Motteau

Reputation: 3714

Your mock cannot be called this, because you declare it after having rendered your component. I assume you have a handleSubmit function in your component that gets called on submit click, but when you call :

const handleSubmit = jest.fn();

...the component is already renderer and there is no way you can mock its handleSubmit function.

What I suggest :

Do not try to spy on handleSubmit function, test like a real user

You should not try to test internal component logic, but test what a real user would see : a loading spinner, a confirmation message...This is what promotes RTL, because it will give you confidence in your test, decouple your test from internal implementation (which is a good thing when it comes to React components unit testing), and force you as a developper to think about user first when writing code (thinking how you will test your code using RTL forces you to think about user experience).

In your test you could do this :

// in component
const handleSubmit = () => {
  // do things

  // say that this boolean controls a message display
  setSubmittedMessageDisplay(true);
}

In test

it('should call function on submit click', async () => {
  const wrapper = render(<Component />);
  const submitBtn = wrapper.getByTestId('submit-btn');

  fireEvent.click(submitBtn);
  expect(wrapper.getByText('form submitted - controlled by submittedMessageDisplay')).toBeTruthy();
});

Pass the form submit handler down from parent component, mock it

This implies to lift things up to the parent component :

// in parent
const handleSubmit = () => {...}
<ChildWithForm onSubmit={handleSubmit} />

// in child
<Form onSubmit={props.onSubmit}>...</Form>

Then in your test you can do this :

test('submits form correctly', () => {
  const mockedHandler = jest.fn();
  const wrapper = render(<Child onSubmit={mockedHandler} />);

  const submitBtn = wrapper.getByTestId('submit-btn');
  fireEvent.click(submitBtn);

  expect(mockedHandler).toHaveBeenCalled();
});

Upvotes: 1

Related Questions