You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jest与React Testing Library测试react-toastify弹窗关闭功能遇阻

问题

我有一个含按钮的简单组件,点击按钮会打开react-toastify提供的弹窗(toast),该弹窗可通过自带的关闭按钮(X)关闭。我想要为该组件编写测试用例,验证点击关闭按钮后弹窗是否关闭,但目前无法完成这个测试。以下是我的代码:

MyComponent.js

import React, { useState } from "react";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

const MyComponent = () => {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const handleOpenModal = () => {
    if (!isModalOpen) {
      toast.success("This is modal content.", {
        autoClose: false,
        closeOnClick: false,
        onClose: () => setIsModalOpen(false), // Update state on close
      });
      setIsModalOpen(true);
    }
  };

  return (
    <div>
      <button onClick={handleOpenModal}>Open Modal</button>
    </div>
  );
};

export default MyComponent;

MyComponent.test.js

import React from "react";
import { render, fireEvent, waitFor, act } from "@testing-library/react";
import MyComponent from "./MyComponent";
import { ToastContainer } from "react-toastify";

// Test: Clicking close button closes modal
test("clicking close button closes modal", async () => {
  const { queryByText, getByRole } = render(
    <>
      <MyComponent />
      <ToastContainer />
    </>
  );

  const button = getByRole("button", { name: "Open Modal" });
  act(() => {
    fireEvent.click(button);
  });
  await waitFor(() => queryByText("This is modal content."));
  const closeButton = getByRole("button", { name: "close" });
  expect(closeButton).toBeInTheDocument();

  act(() => {
    fireEvent.click(closeButton);
  });

  expect(queryByText("This is modal content.")).toBeNull();
});

运行测试后出现问题,请问该如何修改测试代码使其正常运行?


解决方案

你的测试代码存在两个核心问题,修正后即可正常运行:

  • 关闭按钮定位错误:react-toastify默认关闭按钮的aria-label不是精确的"close",而是包含"close"的文本,需要用正则匹配来定位
  • 未等待关闭后的DOM更新:关闭toast是异步操作,直接断言会导致测试在DOM还未更新时执行,结果不准确

另外,React Testing Library v12+版本中,fireEvent和waitFor已经自动处理了act的逻辑,无需手动包裹。

修改后的测试代码如下:

import React from "react";
import { render, fireEvent, waitFor } from "@testing-library/react";
import MyComponent from "./MyComponent";
import { ToastContainer } from "react-toastify";

test("clicking close button closes modal", async () => {
  const { queryByText, getByRole } = render(
    <>
      <MyComponent />
      <ToastContainer />
    </>
  );

  // 触发打开toast的操作
  const openButton = getByRole("button", { name: "Open Modal" });
  fireEvent.click(openButton);
  
  // 等待toast内容渲染完成
  const toastContent = await waitFor(() => queryByText("This is modal content."));
  expect(toastContent).toBeInTheDocument();

  // 定位关闭按钮,用正则匹配aria-label中的close文本
  const closeButton = getByRole("button", { name: /close/i });
  expect(closeButton).toBeInTheDocument();

  // 点击关闭按钮
  fireEvent.click(closeButton);

  // 等待toast消失后断言
  await waitFor(() => {
    expect(queryByText("This is modal content.")).toBeNull();
  });
});

额外优化点:

  • 直接用await waitFor获取toast内容,简化代码逻辑
  • 正则匹配关闭按钮的名称,避免因语言或版本差异导致的定位失败
  • 将关闭后的断言放在waitFor中,确保DOM更新完成后再执行检查

内容的提问来源于stack exchange,提问作者random_coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:14:55