import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { ErrorBoundary } from "./ErrorBoundary.component";
const ThrowError = ({ shouldThrow }: { shouldThrow: boolean }) => {
if (shouldThrow) {
throw new Error("Test error");
}
return
No error
;
};
describe("ErrorBoundary", () => {
// Suppress console.error for these tests
const originalError = console.error;
beforeEach(() => {
console.error = vi.fn();
});
afterEach(() => {
console.error = originalError;
});
it("renders children when there is no error", () => {
render(
Error occurred}>
);
expect(screen.getByText("No error")).toBeInTheDocument();
});
it("renders fallback when there is an error", () => {
render(
Error occurred}>
);
expect(screen.getByText("Error occurred")).toBeInTheDocument();
});
it("calls onError when an error occurs", () => {
const onError = vi.fn();
render(
Error occurred} onError={onError}>
);
expect(onError).toHaveBeenCalledWith(
expect.any(Error),
expect.objectContaining({
componentStack: expect.any(String),
})
);
});
it("renders function fallback with error and reset", () => {
const fallback = vi.fn((error, reset) => (
Function fallback
));
render(
);
expect(screen.getByText("Function fallback")).toBeInTheDocument();
expect(fallback).toHaveBeenCalledWith(
expect.any(Error),
expect.any(Function)
);
});
it("resets when resetKeys change", () => {
const onReset = vi.fn();
const { rerender } = render(
Error occurred}
resetKeys={[1]}
onReset={onReset}
>
);
expect(screen.getByText("Error occurred")).toBeInTheDocument();
rerender(
Error occurred}
resetKeys={[2]}
onReset={onReset}
>
);
expect(screen.getByText("No error")).toBeInTheDocument();
expect(onReset).toHaveBeenCalled();
});
it("calls onReset when reset function is called", () => {
const onReset = vi.fn();
render(
(
)}
onReset={onReset}
>
);
const resetButton = screen.getByText("Reset");
fireEvent.click(resetButton);
expect(onReset).toHaveBeenCalled();
});
it("actually resets the error boundary when reset is called", () => {
const TestComponent = () => {
const [shouldThrow, setShouldThrow] = React.useState(true);
return (
(
Error: {error.message}
)}
>
);
};
render();
// Should show error initially
expect(screen.getByText("Error: Test error")).toBeInTheDocument();
// Click reset
fireEvent.click(screen.getByText("Reset and Fix"));
// Should now show the working component
expect(screen.getByText("No error")).toBeInTheDocument();
});
it("handles resetKeys array changes correctly", () => {
const onReset = vi.fn();
const { rerender } = render(
Error occurred}
resetKeys={["key1", "key2"]}
onReset={onReset}
>
);
expect(screen.getByText("Error occurred")).toBeInTheDocument();
// Change one key in the array
rerender(
Error occurred}
resetKeys={["key1", "key3"]}
onReset={onReset}
>
);
expect(screen.getByText("No error")).toBeInTheDocument();
expect(onReset).toHaveBeenCalled();
});
it("handles empty resetKeys properly", () => {
const onReset = vi.fn();
const { rerender } = render(
Error occurred}
resetKeys={[]}
onReset={onReset}
>
);
expect(screen.getByText("Error occurred")).toBeInTheDocument();
// Change from empty to populated
rerender(
Error occurred}
resetKeys={["key1"]}
onReset={onReset}
>
);
expect(screen.getByText("No error")).toBeInTheDocument();
expect(onReset).toHaveBeenCalled();
});
it("does not reset when resetKeys array is the same", () => {
const onReset = vi.fn();
const { rerender } = render(
Error occurred}
resetKeys={["key1", "key2"]}
onReset={onReset}
>
);
expect(screen.getByText("Error occurred")).toBeInTheDocument();
// Rerender with same keys
rerender(
Error occurred}
resetKeys={["key1", "key2"]}
onReset={onReset}
>
);
expect(screen.getByText("Error occurred")).toBeInTheDocument();
expect(onReset).not.toHaveBeenCalled();
});
});