import { describe, it, expect, beforeEach, afterEach, vi } from "vitest" import { render, screen, fireEvent } from "@testing-library/react" import { Button } from "antd" import { useState } from "react" import ChunkErrorBoundary from "@/components/common/ChunkErrorBoundary" import * as chunkUtils from "@/utils/chunkLoadError" // reload 函数 mock 掉(jsdom 不支持真实 window.location.reload) vi.mock("@/utils/chunkLoadError", async (importOriginal) => { const actual = await importOriginal() return { ...actual, reloadForChunkError: vi.fn(), goHomeRecover: vi.fn(), } }) const { reloadForChunkError, goHomeRecover } = vi.mocked(chunkUtils) /** 渲染时直接抛错的子组件 */ const Boom: React.FC<{ error: Error }> = ({ error }) => { throw error } /** 点击按钮后才抛 chunk 错误的子组件 */ const ChunkBoomButton: React.FC = () => { const [boom, setBoom] = useState(false) if (boom) { throw new TypeError("Failed to fetch dynamically imported module: /assets/x.js") } return } const renderBoundary = (ui: React.ReactNode) => render({ui}) beforeEach(() => { sessionStorage.clear() vi.clearAllMocks() // error boundary 捕获后 React 会打 error log,静默掉 vi.spyOn(console, "error").mockImplementation(() => {}) }) afterEach(() => { vi.restoreAllMocks() sessionStorage.clear() }) describe("ChunkErrorBoundary", () => { it("正常渲染 children", () => { renderBoundary(
hello-child
) expect(screen.getByText("hello-child")).toBeInTheDocument() }) it("首次捕获 chunk 错误 → 自动刷新(reloadForChunkError)并显示自动刷新提示", () => { renderBoundary() fireEvent.click(screen.getByText("boom")) expect(reloadForChunkError).toHaveBeenCalledTimes(1) expect(screen.getByText(/正在自动刷新/)).toBeInTheDocument() }) it("已刷新过仍失败 → 不再自动刷新,显示手动兜底按钮", () => { // 模拟"本会话已经自动刷新过一次" sessionStorage.setItem("chunk_error_reloaded_at", String(Date.now())) renderBoundary( , ) expect(reloadForChunkError).not.toHaveBeenCalled() expect(screen.getByText("系统已更新")).toBeInTheDocument() // 点击兜底按钮 → goHomeRecover(跳首页,不刷新当前 URL) fireEvent.click(screen.getByText("刷新并返回首页")) expect(goHomeRecover).toHaveBeenCalledTimes(1) }) it("非 chunk 错误 → 显示通用错误页,不触发 chunk 自动刷新", () => { renderBoundary() expect(reloadForChunkError).not.toHaveBeenCalled() expect(screen.getByText("页面出现异常")).toBeInTheDocument() }) })