Skip to content

waitForElementToBeRemoved: TypeError: Cannot read property 'parentElement' of null #870

Closed
@AriPerkkio

Description

@AriPerkkio
  • Fresh project generated by create-react-app@4:
  • @testing-library/dom version: 5.11.4
  • Testing Framework and version:
    • jest@26.6.0
  • DOM Environment:
    • jest-environment-jsdom@26.6.2
    • jsdom@16.4.0

Relevant code or config:

Same code is available in codesandbox below. The real use case is a bit different but I was able to reproduce the issue with this example:

import React, { useReducer } from "react";
import Modal from "react-modal";
import userEvent from "@testing-library/user-event";
import {
    render,
    waitForElementToBeRemoved,
    screen,
} from "@testing-library/react";

beforeAll(() => {
    const root = document.createElement("div");
    root.id = "app-root";
    document.body.appendChild(root);
    Modal.setAppElement("#app-root");
});

function Component() {
    const [isOpen, toggle] = useReducer((s) => !s, false);

    return (
        <>
            <button onClick={toggle}>Open</button>

            <Modal isOpen={isOpen}>
                <button onClick={toggle}>Close</button>
                {isOpen && <div>Content</div>}
            </Modal>
        </>
    );
}

test("poc", async () => {
    render(<Component />);

    userEvent.click(screen.getByText("Open"));
    const content = await screen.findByText("Content");

    userEvent.click(screen.getByText("Close"));
    await waitForElementToBeRemoved(content);
});

What you did:

Queried element rendered inside react-modal. Closed the modal and waited for the content to disappear. The modal seems to do some direct DOM manipulation, https://github.com/reactjs/react-modal/blob/master/src/components/Modal.js.

What happened:

    TypeError: Cannot read property 'parentElement' of null

      37 | 
      38 |     userEvent.click(screen.getByText("Close"));
    > 39 |     await waitForElementToBeRemoved(content);
         |           ^
      40 | });
      41 | 

      at node_modules/@testing-library/dom/dist/wait-for-element-to-be-removed.js:30:21
          at Array.map (<anonymous>)
      at waitForElementToBeRemoved (node_modules/@testing-library/dom/dist/wait-for-element-to-be-removed.js:27:43)
      at Object.<anonymous> (src/App.test.js:39:11)

const getRemainingElements = elements.map(element => {
let parent = element.parentElement
while (parent.parentElement) parent = parent.parentElement
return () => (parent.contains(element) ? element : null)
})

Reproduction:

https://codesandbox.io/s/amazing-brook-7xssv?file=/src/App.test.js

Problem description:

react-modal is removing the parentElement of the queried element. The queried element is given to waitForElementToBeRemoved which crashes while accessing the parentElement.

I'm sure there are work-arounds which can be used to avoid the crash caused by this minimal example. This is still a valid bug in the waitForElementToBeRemoved utility.

Suggested solution:

waitForElementToBeRemoved should not crash if given element has no .parentElement available. It should resolve successfully once missing parentElement is detected.

Debug information:

    const getRemainingElements = elements.map(element => {
      let parent = element.parentElement;

      debugger
      // element.outerHTML -> '<div>Content</div>'
      // element.parentElement -> null

      while (parent.parentElement) parent = parent.parentElement;

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions