Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matcher error: received value must be a mock or spy function

I'm writing tests (with Jest and React Testing Library) for a form React component. I have a method that runs on form submit:

const onSubmit = (data) => {
  // ...
  setIsPopupActive(true);
  // ...
};

and useEffect that runs after isPopupActive change, so also on submit:

useEffect(() => {
  if (isPopupActive) {
    setTimeout(() => {
      setIsPopupActive(false);
    }, 3000);
  }
}, [isPopupActive]);

In the test, I want to check, whether the popup disappears after 3 seconds. So here's my test:

it('Closes popup after 3 seconds', async () => {
    const nameInput = screen.getByPlaceholderText('Imię');
    const emailInput = screen.getByPlaceholderText('Email');
    const messageInput = screen.getByPlaceholderText('Wiadomość');
    const submitButton = screen.getByText('Wyślij');

    jest.useFakeTimers();

    fireEvent.change(nameInput, { target: { value: 'Test name' } });
    fireEvent.change(emailInput, { target: { value: '[email protected]' } });
    fireEvent.change(messageInput, { target: { value: 'Test message' } });
    fireEvent.click(submitButton);

    const popup = await waitFor(() =>
      screen.getByText(/Wiadomość została wysłana/)
    );

    await waitFor(() => {
      expect(popup).not.toBeInTheDocument(); // this passes

      expect(setTimeout).toHaveBeenCalledTimes(1);
      expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 3000);
    });
  });

However, I'm getting the error:

expect(received).toHaveBeenCalledTimes(expected)

Matcher error: received value must be a mock or spy function

Received has type:  function
Received has value: [Function setTimeout]

What am I doing wrong?

like image 711
Velrin Black Avatar asked Jun 17 '21 09:06

Velrin Black


People also ask

How do you mock a function?

There are two ways to mock functions: Either by creating a mock function to use in test code, or writing a manual mock to override a module dependency.

How do you use spyOn function in jest?

To spy on an exported function in jest, you need to import all named exports and provide that object to the jest. spyOn function. That would look like this: import * as moduleApi from '@module/api'; // Somewhere in your test case or test suite jest.

How do you mock an import jest?

To mock an imported function with Jest we use the jest. mock() function. jest. mock() is called with one required argument - the import path of the module we're mocking.

Can We spy on a mock function from inside a test?

We can't spy on a function on its own: Now we can spy on whether our mock function was called from inside our test. What if we want to mock everything in the file, but use the actual implementation for one or two of the functions?

What are mocks and spies in Python?

Mock functions, also known as spies, are special functions that allow us to track how a particular function is called by external code. Instead of just testing the output of the function, we can gain additional information about how a function was used.

What is a mock function in greetworld?

The act of passing a mock function to greetWorld allows us to spy on how it uses the function. We expect to have the function to be called one time with the 'world' string as the first argument. How Does It Work?

What is a mock function in Python?

Mock functions, also known as spies, are special functions that allow us to track how a particular function is called by external code. Instead of just testing the output of the function, we can gain additional information about how a function was used. By using mock functions, we can know the following:


1 Answers

Jest 27 has breaking changes for fakeTimers. It seems Jest contributors doesn't update documentation on time. This comment on Github issues confirms it. Moreover, here related PR.

Well, you can solve your problem by two ways.

  1. Configure Jest to use legacy fake timers. In jest.config.js you can add line (but it not works for me):
module.exports = {
 // many of lines omited
 timers: 'legacy'
};
  1. Configure legacy fake timers for individually test suite, or even test:
jest.useFakeTimers('legacy');
describe('My awesome logic', () => {
// blah blah blah
});

It's preferably to use new syntax based on @sinonjs/fake-timers. But I can't find working example for Jest, so I'll update this answer as soon as possible.

like image 149
EvgeniyRRU Avatar answered Sep 19 '22 12:09

EvgeniyRRU