Search code examples
reactjsjestjsreact-testing-library

The element(s) given to waitForElementToBeRemoved are already removed


Testing Code

test("popover responses to hover", async () => {
  render(<SummaryForm />);

  //popover appears upon mouseover of checkbox label
  const termsAndConditions = screen.getByText(/terms and conditions/i);
  userEvent.hover(termsAndConditions);

  userEvent.unhover(termsAndConditions);
  let nullPopoverAgain;
  await waitForElementToBeRemoved(() => {
    nullPopoverAgain = screen.queryByText(
      /no ice cream will actually be delivered/i
    );
  });

  expect(nullPopoverAgain).not.toBeInTheDocument();
});

Summary Form Code

import React, { useState } from "react";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
import OverlayTrigger from "react-bootstrap/OverlayTrigger";
import Popover from "react-bootstrap/Popover";

export default function SummaryForm() {
  const [tcChecked, setTcChecked] = useState(false);

  const popover = (
    <Popover id="popover-basic">
      <Popover.Body>No ice cream will actually be delivered</Popover.Body>
    </Popover>
  );

  const checkboxLabel = (
    <span>
      I agree to
      <OverlayTrigger placement="right" overlay={popover}>
        <span style={{ color: "blue" }}> Terms and Conditions</span>
      </OverlayTrigger>
    </span>
  );

  return (
    <Form>
      <Form.Group controlId="terms-and-conditions">
        <Form.Check
          type="checkbox"
          checked={tcChecked}
          onChange={(e) => setTcChecked(e.target.checked)}
          label={checkboxLabel}
        />
      </Form.Group>
      <Button variant="primary" type="submit" disabled={!tcChecked}>
        Confirm order
      </Button>
    </Form>
  );
}

Getting error

● popover responses to hover

    The element(s) given to waitForElementToBeRemoved are already removed. waitForElementToBeRemoved requires that the element(s) exist(s) before waiting for removal.

      49 |   userEvent.unhover(termsAndConditions);
      50 |   let nullPopoverAgain;
    > 51 |   await waitForElementToBeRemoved(() => {
         |                                  ^
      52 |     nullPopoverAgain = screen.queryByText(
      53 |       /no ice cream will actually be delivered/i
      54 |     );

I move userEvent.unhover(termsAndConditions); after waitForElementToBeRemoved but it throws the same error despite that. I also commented the code of unhover despite of that getting the same error that the given element had already been removed. Without un hovering, it should not go from the dom. How is this possible?


Solution

  • You should pass the element that you want to wait for its removal directly to the waitForElementToBeRemoved function, instead of wrapping it in a callback.

    test("popover responses to hover", async () => {
      render(<SummaryForm />);
    
      //popover appears upon mouseover of checkbox label
      const termsAndConditions = screen.getByText(/terms and conditions/i);
      userEvent.hover(termsAndConditions);
    
      userEvent.unhover(termsAndConditions);
      await waitForElementToBeRemoved(
        screen.queryByText(/no ice cream will actually be delivered/i)
      );
    
      expect(
        screen.queryByText(/no ice cream will actually be delivered/i)
      ).not.toBeInTheDocument();
    });