1
votes

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?

1
Please, provide stackoverflow.com/help/mcve . It's not confirmed that the component works as you expect. Considering that the test fails, it most likely isn't.Estus Flask
Hi, it is working as expected. I just included the code for the component. Please have a look. @EstusFlaskWai Yan Hein
The component is bulky, there are many points of failure, it needs to be refactored into several ones. Render function is an antipattern, it could be a separate component. It's hard to read, this decreases your chances that somebody will have enough time to debug it for you on SO. From what I see, the point of interest that affects failed assertion is (props.inputValue =="" || users.length< 1). It can be seen that you provided inputValue in tests. But it looks like users is empty. You should have been test for user-autocomplete-users-wrapper to make the test more specific.Estus Flask

1 Answers

0
votes

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.