React testing-library unable to re render modal in between tests

Viewed 2119

I have a modal component that I am rendering for multiple tests like so:

const result = render(<MyModal {...myTestProps} />);
const modalComponent = screen.getByTestId('modal-client-id');

In one of my tests I dismiss the modal:

   it("Closes modal when cancel button is clicked", async(done) => {
       const result = render(<MyModal {...myTestProps} />);
       const modalComponent = screen.getByTestId('modal-client-id');
       const cancelButton = screen.getByTestId('modal-cancel-button');
       await act(async () => {
           new Promise((resolve, reject) => {
               fireEvent.click(cancelButton);
               done();
           });
       });
       expect(modalComponent).not.toBeInDocument();
   });

But on subsequent tests:

   it("Closes modal when successful", async(done) => {
       const result = render(<MyModal {...myTestProps} />);
       const modalComponent = screen.getByTestId('modal-client-id');
       const okButton = screen.getByTestId('modal-ok-button');
       await act(async () => {
           new Promise((resolve, reject) => {
               fireEvent.click(okButton);
               done();
           });
       });
       expect(modalComponent).not.toBeInDocument();
   });

Getting by testId fails. The only thing rendered in the document is an empty

//Cancel test
<DocumentFragment>
    <div />
    <div>
      ...Modal elements
    </div>
</DocumentFragment>

//Ok button
<DocumentFragment>
    <div />
</DocumentFragment>

I have tried adding a [cleanup][1], as well as clearing/reinitializing document, document.body, and document.innerhtml in afterEach but all to no effect. The tests always run successfully when with the other commented out. The component it self is defined with React hooks, and I do not see any global side effects coming out of the modal component. Is there a way to reset the dom to alway re render the modal in subsequent tests?

1 Answers

My case was that I was using act and promises incorrectly. I followed Act warnings and tips and refactored the act like so:

   it("Closes modal when successful", async(done) => {
       const result = render(<MyModal {...myTestProps} />);
       const modalComponent = screen.getByTestId('modal-client-id');
       const okButton = screen.getByTestId('modal-ok-button');
       fireEvent.click(okButton);
       await waitForElementToBeRemoved(screen.getByTestId('modal-client-id');
       expect(modalComponent).not.toBeInDocument();
       done();
   });

Since I wasn't resolving the promise and incorrectly calling done() the rendering was causing side effects in my tests. fireEvent also does not need an external wrap with act as it already performs the action in an act.

Related