Vishal
Vishal

Reputation: 6368

Element is removed from document, but jest still finds it

I have built a wrapper around react-toastify, so that I can call it at multiple places.

Here is the code for wrapper:

import { ReactText } from 'react';
import { toast } from 'react-toastify';

export const showNotification: (
  message: string,
  type?: 'info' | 'success' | 'warning' | 'error',
  timeOut?: number,
) => ReactText
  = (message, type = 'success', timeOut = 5000) => toast(
      message, { type, autoClose: timeOut },
    );

export const dismissNotification = (toastId: ReactText) => toast.dismiss(toastId);

Now, I am testing my dismissNotification function.

I have written this test case:

it('dismisses notification when called', async () => {
  render(<ToastContainer />);
  const notificationId = showNotification('Test Notification', 'success', 2000);
  await waitFor(() => {
    expect(screen.getByText('Test Notification')).toBeInTheDocument();
  });
  dismissNotification(notificationId);
  await waitForElementToBeRemoved(() => {
    expect(screen.queryByText('Test Notification')).not.toBeInTheDocument();
  });
});

But last test case always fails saying that a dom node with text Test Notification is present.

Actual Error:

dismisses notification when called

    expect(element).not.toBeInTheDocument()

    expected document not to contain element, found <div class="Toastify__toast-body" role="alert">Test Notification</div> instead

Upvotes: 2

Views: 4497

Answers (1)

srk
srk

Reputation: 1901

It looks like you are using waitForElementToBeRemoved incorrectly. According to the documentation, "the first argument must be an element, array of elements, or a callback which returns an element or array of elements."

In addition, it looks like you are facing some issue with the timeout. It seems the animation is causing the element to remain in the DOM for longer than you expect. You can perform two quick tests to confirm this is an issue.

First, inspect the DOM in your browser. When you dismiss the notification, you can see that the element is not removed right away.

Second, try setting a custom transition so we can play around with the duration. When you set the collapseDuration to something like 5000, the toast takes a long time to disappear, and the test fails. When you set the collapseDuration to 0, the toast disappears immediately, and the test passes.

const Zoom = cssTransition({
  enter: 'zoomIn',
  exit: 'zoomOut',
  collapseDuration: 0,
  //duration: 5000,
});

toast(message, {
  type,
  autoClose: timeOut,
  transition: Zoom,
});

So I think you need to both fix how you are using waitForElementToBeRemoved and also apply a custom timeout. Try this code:

await waitForElementToBeRemoved(screen.queryByText('Test Notification'), { timeout: 5000 });

Upvotes: 4

Related Questions