Home > Blockchain >  How to test Input with React Testing Library?
How to test Input with React Testing Library?

Time:06-18

I am trying to test an input value of Search component via React Testing Library.

Search component receives two props: handleChange and input value: title.

My goal is to write the test so that initially the input value is empty and when user types something, test can validate that listening to event value was correct, but it always gets the initial value.

I'm trying to clear the input before typing but it doesn't work.

Error is:

 Expected the element to have value:
                       // indicates as empty string which I expect
                    
    Received:
      test            // it is still the default value: `test`, UserEvent.clear didn't clear

Here are the two test first checking if input initially was empty, which works fine and 2nd to listen to the input.

import { fireEvent, screen, waitFor } from "@testing-library/react";
import Search from "../Search";
import { render } from "../../../test-utils/test-utils";
import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";

const mockedOnChange = jest.fn();

describe("input should be filled with title", () => {
  test("input should be empty initially", async () => {
    render(<Search title="" onChangeHadler={mockedOnChange} />);
    const input = screen.getByRole("textbox", { name: /search/i });
    expect(input).toHaveValue("");
  });
   // renderComponent wrapps the `Search` component
  const renderComponent = (searchInputValue: string) => {
    const view = render(
      <Search title={searchInputValue} onChangeHadler={mockedOnChange} />
    );
    return view;
  };

  test("input should update by typed text", async () => {
    renderComponent("test");
    const input = await screen.findByRole("textbox", { name: /search/i });
    await waitFor(() => expect(input).toHaveValue("test"));
    userEvent.clear(input);
    expect(input).toHaveValue(""); // error appears here indicating that value was not cleared

    // userEvent.type(input, "su"); 
    // await waitFor(() => expect(input).toHaveValue("su"));
  });
});

CodePudding user response:

Your tested component is a controlled component : it receives (props) its value from the parent component, with a function reference which notifies the parent that the user changed the input value. Typically this function will update the parent state, which is passed down to the child component, and used as the input value.

In your test you only render the child component, and you mock the callback function. So you cannot expect the input value to change when triggering user interactions in your test. You can only test that the title props is used as value for the input, and that the callback function (which is mocked in your test) is correctly called when you trigger user interactions. But you cannot test a "full scenario" without rendering the parent component.

test("input value is the title props", async () => {
    renderComponent("test");
    const input = await screen.findByRole("textbox", { name: /search/i });
    await waitFor(() => expect(input).toHaveValue("test"));
});

test("callback function is called on user interactions", async () => {
    renderComponent("test");
    const input = await screen.findByRole("textbox", { name: /search/i });
    userEvent.type(input, "new value");
    expect(mockedOnChange).toHaveBeenCalledWith("new value");
});
  • Related