元素已从文档中删除,但 jest 仍能找到它

Element is removed from document, but jest still finds it

我已经围绕 react-toastify 构建了一个包装器,这样我就可以在多个地方调用它。

这是包装器的代码:

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);

现在,我正在测试我的 dismissNotification 函数。

我写了这个测试用例:

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();
  });
});

但最后一个测试用例总是失败,表示存在带有文本 Test Notification 的 dom 节点。

实际错误:

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

您似乎使用 waitForElementToBeRemoved 不正确。根据 the documentation,“第一个参数必须是一个元素、元素数组,或者 returns 一个元素或元素数组的回调。”

此外,您似乎遇到了一些超时问题。似乎动画导致元素在 DOM 中停留的时间比您预期的要长。您可以执行两个快速测试来确认这是一个问题。

首先,检查浏览器中的 DOM。当您关闭通知时,您可以看到该元素并没有立即被删除。

其次,尝试设置 custom transition 这样我们就可以调整持续时间。当您将 collapseDuration 设置为 5000 之类的内容时,吐司需要很长时间才能消失,并且测试失败。当你将collapseDuration设置为0时,toast立即消失,测试通过。

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

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

所以我认为您需要修复您使用 waitForElementToBeRemoved 的方式并应用自定义 timeout。试试这个代码:

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