React Testing Library and Vitest - element is visible before updating state

572 views Asked by At

As a newbie, I am trying to learn to write some tests.

I built a simple component with an input, and a button to display the text input after clicking on the button. The span is initially hidden, and it changes to visible after clicking on the button

This is the component

function Contact() {
  const [name, setName] = useState("");
  const [show, setShow] = useState(false);

  const handleSendContactRequest = (e) => {
    e.preventDefault();
    setShow(true);
  };

  return (
    <>
      <h1>Contact</h1>
      <span
        data-testid="message"
        style={{ visibility: show ? "visible" : "hidden" }}
      >
        {name} , check your inbox
      </span>
      <form action="">
        <input
          type="text"
          placeholder="name"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
        <button onClick={handleSendContactRequest}>Send contact request</button>
      </form>
    </>
  );
}

export default Contact;

I created a test to check that the span is initially hidden, that it passes, and a second to check the whole flow.

//this test passes. span is not visible
test("span should not be visiblet", () => {
  render(<Contact />);

  const span = screen.getByTestId("message");
  expect(span).not.toBeVisible();
});

test("should display name in the span after clicking the button", () => {
 render(<Contact />);

  const nameInput = screen.getByPlaceholderText("name");
  fireEvent.change(nameInput, { target: { value: "tom" } });

  const sendButton = screen.getByText("Send contact request");

  const hiddenSpan = screen.queryByText(
    "tom , check your account [email protected]"
  );
  expect(hiddenSpan).toBeNull(); // do not pass. spann is visible after fireEvent.change()

  fireEvent.click(sendButton);

  const spanElement = screen.getByText("tom , check your inbox");

  expect(spanElement).toBeVisible();


});

I am writting the test correctly? I do not understand why span has content after the fireEvent.change() when the previous test passed.

1

There are 1 answers

0
Rher On

I was checking for the wrong property. Since I just show and hide the element, methods like .findByText() .queryByText can still access to the value of the element, and methods like .toBeInTheDocument() or .toBe() will have access to the innerHTML and textContent of the element.

Just to check for .toBeVisible() seems to work fine. I modified the test :

test("should span be visible and contain a name value after clicking button", () => {
  render(<Contact />);
  const span = screen.getByTestId("message");
  expect(span).not.toBeVisible();
  const nameInput = screen.getByPlaceholderText("name");
  const nameInputValue = "Tom";
  const sendButton = screen.getByRole("button");

  fireEvent.change(nameInput, { target: { value: nameInputValue } });
  fireEvent.click(sendButton);


  expect(span).toBeVisible();
  
  expect(span.innerHTML).toBe(
    `${nameInputValue} , check your inbox`
  );
});

This test will pass, and if I comment out fireEvent.click(sendButton);, it won't.