import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { useState } from "react"; import { ErrorBoundary } from "./ErrorBoundary"; /** A child that throws on demand. Toggle `boom` to control whether it crashes. */ function Boom({ boom, label = "kaboom" }: { boom: boolean; label?: string }) { if (boom) throw new Error(label); return
child ok
; } // React logs caught render errors to console.error; silence it so the suite output // stays readable while still exercising the real error path. let errorSpy: ReturnType; beforeEach(() => { errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); }); afterEach(() => { errorSpy.mockRestore(); }); test("renders children when nothing throws", () => { render( , ); expect(screen.getByText("child ok")).toBeInTheDocument(); }); test("renders the default fallback when a child throws", () => { render( , ); expect(screen.queryByText("child ok")).not.toBeInTheDocument(); // Default fallback names the labelled surface. expect(screen.getByText(/couldn't be displayed/i)).toBeInTheDocument(); expect(screen.getByText(/step/i)).toBeInTheDocument(); }); test("uses a custom fallback render prop with the error", () => { render(

custom: {err.message}

}>
, ); expect(screen.getByText("custom: explode")).toBeInTheDocument(); }); test("calls onError when a child throws", () => { const onError = vi.fn(); render( , ); expect(onError).toHaveBeenCalledTimes(1); expect(onError.mock.calls[0][0]).toBeInstanceOf(Error); expect((onError.mock.calls[0][0] as Error).message).toBe("reported"); }); test("recovers when resetKeys change to non-crashing content", async () => { function Harness() { const [boom, setBoom] = useState(true); return ( <> ); } render(); // Starts crashed → fallback visible. expect(screen.getByText(/couldn't be displayed/i)).toBeInTheDocument(); // Flip the data (and thus resetKeys); the boundary clears and re-renders children. await userEvent.click(screen.getByRole("button", { name: "fix" })); expect(screen.getByText("child ok")).toBeInTheDocument(); expect(screen.queryByText(/couldn't be displayed/i)).not.toBeInTheDocument(); }); test("Try again resets the boundary", async () => { let boom = true; function Flaky() { if (boom) throw new Error("transient"); return
recovered
; } render( , ); expect(screen.getByText(/couldn't be displayed/i)).toBeInTheDocument(); // Simulate the underlying condition clearing, then retry. boom = false; await userEvent.click(screen.getByRole("button", { name: /try again/i })); expect(screen.getByText("recovered")).toBeInTheDocument(); });