Test modal component within another component

4.1k Views Asked by At

I'm trying to test a component that should open its modal. Modal is a part of this component, but it's rendered with createPortal(). I first check if modal exist in the document and after button click if it appeared but test fails.

Component:

const [openModal, setOpenModal] = useState(false);

function Component() {
  return (
    <div>
      <button onClick={() => setOpenModal(true)}>Open Modal</button>
      <Modal open={openModal}/>
    </div>
  )
}

Modal:

const Modal = ({ open, children }) => {
  return createPortal(
    <div style={{display: open ? "block" : "none"}} data-testid="modal">
      {children}
    </div>,
    document.getElementById("modals")
  );
};

Test:

test("component that opens modal", async () => {
  render(<Component />);
  const button = screen.getByText("Open Modal");
  const modal = screen.queryByTestId("modal");
  expect(modal).not.toBeInTheDocument();
  fireEvent.click(button);
  await waitFor(() => expect(modal).toBeInTheDocument()); // Fails
});

I tried to test it with await waitFor(() => expect(modal).toBeInTheDocument()) and also with standard expect(modal).toBeInTheDocument()). I also tried to render modal without portal, but still had no effect on the test. Could you please explain how it should be tested?

2

There are 2 best solutions below

1
On

This kind of behavior is probably generating a new render, try using act

Some useful links: https://github.com/threepointone/react-act-examples/blob/master/sync.md

https://testing-library.com/docs/preact-testing-library/api/#act

1
On

After fireEvent try this and it will pass:

await waitFor(() => expect(modal));

This will pass if modal id is present in the view.