useQuery: Cannot spy the useQuery property because it is not a function

Have a simple useQuery like this

  const {
    isLoading, isError, data,
  } = useQuery(['courses', { userId: someUserId }], fetchDataFromBackendServer);

in my unit test, i want the useQuery return info from very beginning (there's a reason i want to do that, but that's off the topic)

  describe.only('Title', () => {
    beforeEach(() => {
      jest.clearAllMocks();
      jest.spyOn(React, 'useQuery').mockResolvedValue({ isError: false, isLoading: false });
    }
    ...
  }

It gives me: Cannot spy the useQuery property because it is not a function; undefined given instead

Hot to fix this please ?


Solution 1:

First of all, React does not provide useQuery hook.

I suppose you are using react-query

The second, if you want to use jest.spyOn(obj, 'method'), you can't destruct the method from the obj. That means you should use it like ReactQuery.useQuery() in your component.

E.g.

import { render } from '@testing-library/react';
import React from 'react';
import * as ReactQuery from 'react-query';

describe('70660790', () => {
  test('should pass', () => {
    jest.spyOn(ReactQuery, 'useQuery').mockImplementation();
    function Test() {
      ReactQuery.useQuery('todos');
      return null;
    }
    render(<Test />);
    expect(ReactQuery.useQuery).toBeCalledWith('todos');
  });
});

Test result:

 PASS  examples/70660790/index.test.tsx (11.646 s)
  70660790
    ✓ should pass (18 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        13.036 s

See how react-query exports hooks in barrel file, we have to use namespace import.

The last, you should not mock useQuery hook the third-party package provides, and test the implementation detail. You should keep using the original useQuery hook and mock side effect function such as fetchDataFromBackendServer (I suppose it's an API call to the remote server). Then you can test what's the output of the component. See testing

Again, don't recommend mock useQuery. Mock Implementation is probably inconsistent with the original implementation, This will lead your test to build on the wrong mock Implementation. This causes your test case to pass, but the program is not correct at runtime.

And,test implementation details can also make test cases vulnerable. A small change in implementation details will cause the test case to fail and you will have to modify the test case.