How to test RTK Query with react testing library?
Asked Answered
A

4

9

I'm trying to work with RTK Query, but can't find a good example of how to write unit tests with react testing library for a component that uses requests with RTK Query.

For example, we have a component that gets a list of something from server. How do mock data for requests? I found a solution to use mswjs for mocking API for tests.

But even with it, I have a problem: I need to add await new Promise((r) => setTimeout(r, 1000)); before I'll check that something from the collection exists.
Maybe, somebody knows how to test components with RTK Query?

Accepter answered 3/6, 2022 at 16:7 Comment(2)
small updates - await new Promise((r) => setTimeout(r, 1000)); don't needed because of waitForElementToBeRemoved to await remove loader. But maybe somebody has examples of unit testing components with RTK QueryAccepter
Please provide enough code so others can better understand or reproduce the problem.Giovannagiovanni
V
18

You can take a look at the tests of RTK Query itself.

Some things:

  • use msw to mock an api
  • wrap your component in a real Redux store with your api (storeRef.wrapper in the example)
  • use something to wait for UI changes like
      await waitFor(() =>
        expect(screen.getByTestId('isFetching').textContent).toBe('false')
      )
Vernitavernoleninsk answered 3/6, 2022 at 17:15 Comment(0)
S
4

An alternative I have found is mocking the rtk query hooks themselves. Then you can set anything you want for the data object.

jest.mock('pathToHook', () => ({
  __esModule: true,
  default: () => () => { data: 'whatever you want' },
}))
Swane answered 21/6, 2022 at 12:40 Comment(1)
but what pathToHook would look like if we're talking about a default hook generated by RTK?Efthim
H
4

You should be able to do something like this.

import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useGetData } from './api'; // RTK Query API

import MyComponent from './MyComponent';

jest.mock('./useGetData');

describe('MyComponent', () => {
  beforeEach(() => {
    useGetData.mockClear();
  });

  it('should render data after API request', async () => {
    const mockData = {
      id: 1,
      name: 'John Doe',
      email: '[email protected]'
    };
    useGetData.mockReturnValueOnce({
      data: mockData,
      isLoading: false,
      isSuccess: true,
      isError: false,
      error: null,
    });

    render(<MyComponent />);

    // Check that loading state is not displayed
    expect(screen.queryByText('Loading...')).toBeNull();

    // Check that data is displayed correctly
    expect(screen.getByText('Name: John Doe')).toBeInTheDocument();
    expect(screen.getByText('Email: [email protected]')).toBeInTheDocument();
  });
});

In this example, we are testing that MyComponent correctly displays data after a successful useGetData hook call. We simulate the useGetData hook by mocking it using jest.mock and setting up a mock return value using useGetData.mockReturnValueOnce. Then, we render the component and verify that the loading state is not displayed and that the data is correctly displayed using expect statements. It's worth noting that we don't need to wait for an API request to complete, as useGetData already returns the data we wish to test.

Heliotherapy answered 7/3, 2023 at 10:50 Comment(4)
Thanks a lot for your answer. You saved a lot of my time.Vallonia
const hookMocked = jest.fn(); jest.mock('path-to-the-module-you-want-to-mock', () => ({ hookThatYouWantToMock: () => hookMocked(), })); Then you can use mockClear() inside beforeEach() and mockReturnValueOnce() inside the tests :)Sherard
What about mocking a mutation or a lazy query how could you do it ?Manger
how to mock the response using typescript ? i'm getting >Property 'refetch' is missing in type ... @HeliotherapySouthwestwardly
M
0

The easiest way is to use "jest-fetch-mock" (npm i -D jest-fetch-mock)

After set it in your jest setup file (jest.setup.ts)

import fetchMock from 'jest-fetch-mock'

fetchMock.enableMocks()

And use in your test file by this way:

import fetch from 'jest-fetch-mock'

it('render hints if data exists', async () => {
    fetch.mockResponse(JSON.stringify(['test']))
    
    const { getByText, getByPlaceholderText, store } = renderWithProviders(<SearchBar />)
})

fetch.mockResponse(JSON.stringify(['test'])) // will return ['test'] in every request result (even in rtk query query hook), you can pass your own data you need.

Maomaoism answered 8/3 at 11:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.