Wai Yan Hein
Wai Yan Hein

Reputation: 14791

Jest + React Testing Library: waitFor is not working

I am writing unit tests for my React JS application using Jest and React testing library. I am trying to test the async functions. But it is not working.

This is my test

import React from 'react';
import "regenerator-runtime/runtime"
import {render, waitFor, fireEvent, screen} from '@testing-library/react';
import {DonorSelect} from "../../src/components";
import MockAdapter from "axios-mock-adapter";
import Axios from 'axios';
import vars from "../configVars";
import {searchUsersResponse} from "../mock/apiResponse";
import { act } from "react-dom/test-utils"

test ("DonorSelect Component", async () => {
   let selectedUser = null;
   let users = [ ];
   let inputValue=""

    //mock the users api endpoint
    let mock = new MockAdapter(Axios);
    mock.onGet(`${vars.baseApEndpoint}/users?keyword=client`)
        .reply(200, searchUsersResponse)

    await act(async() => await render(
        <DonorSelect
            id={"user_select"}
            onSelect={(user, displayText) => {
                selectedUser = { ...user }
            }}
            onInputChange={(textFieldValue) => {
                inputValue = textFieldValue;
            }}
            onUsersFetched={(userItems) => {
                users = [ ...userItems ]
            }}
            onChange={(name, value) => {

            }}
            label={"Search User"}
            placeholder={"Please, select a user."}
            name={"user"}
            value={selectedUser!=null? selectedUser.id:""}
            inputValue={inputValue}
        />
    ))

    //assert that input is rendered
    expect(screen.getByTestId("user_select_input")).toBeTruthy()
    fireEvent.change(screen.getByTestId("user_select_input"), {
        target: { value: "client" }
    })
    fireEvent.focus(screen.getByTestId("user_select_input"))

    await waitFor(() => {
        //assert that if the label is rendered
        expect(screen.getByTestId("user_select_label")).toBeTruthy()
        // assert that input is rendered
        expect(screen.getByTestId("user_select_user_item_0")).toBeTruthy()
    })
})

As you can see in the test what is not working is the last expect()

expect(screen.getByTestId("user_select_user_item_0")).toBeTruthy()

It is always failing. What that component is doing is that, when the input value changes and focus on the input, it will make the api request and render the items. The component is working as expected. I have fully tested it. But it is just not working in the test. What is wrong with my code and how can I fix it?

Upvotes: 5

Views: 14763

Answers (2)

Ezequiel De Simone
Ezequiel De Simone

Reputation: 330

Based on the information here: Testing: waitFor is not a function #8855 link

The Solution that works for me is update the library to new version:

This module is distributed via npm which is bundled with node and should be installed as one of your project's devDependencies:

npm install --save-dev @testing-library/react

or

for installation via yarn

yarn add --dev @testing-library/react

This library has peerDependencies listings for react and react-dom.

React Testing Library versions 13+ require React v18. If your project uses an older version of React, be sure to install version 12:

npm install --save-dev @testing-library/react@12


yarn add --dev @testing-library/react@12

For more information

Upvotes: -2

Domino987
Domino987

Reputation: 8774

The default waitFor timeout time is 1000ms.

If you are calling a real endpoint without mocking (mocking is recommended, for example using msw), this might take more than 1 second to execute.

This will result in the timeout being exceeded and the waitFor throws an error.

IF you do not want to mock the endpoint, intercept it and return a test value, which should be under 1 sec, you could also extend the timeout time ti wait for the real api call to be executed and resolved:

await waitFor(() => {
        //assert that if the label is rendered
        expect(screen.getByTestId("user_select_label")).toBeTruthy()
        // assert that input is rendered
        expect(screen.getByTestId("user_select_user_item_0")).toBeTruthy()
    }
,{timeout: 4000}) // this will now wait 4 secs for the execution, but you should see what works for you.

Upvotes: 4

Related Questions