mirror of
https://github.com/prymitive/karma
synced 2026-05-15 04:06:41 +00:00
126 lines
4.1 KiB
TypeScript
126 lines
4.1 KiB
TypeScript
import { act } from "react";
|
|
|
|
import { render, screen } from "@testing-library/react";
|
|
|
|
import { ErrorBoundary } from "./ErrorBoundary";
|
|
|
|
let consoleSpy: jest.SpyInstance;
|
|
|
|
beforeEach(() => {
|
|
jest.useFakeTimers();
|
|
consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {});
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllTimers();
|
|
jest.useRealTimers();
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
const FailingComponent = () => {
|
|
throw new Error("Error thrown from problem child");
|
|
};
|
|
|
|
const renderFailingComponent = () => {
|
|
return render(
|
|
<ErrorBoundary>
|
|
<FailingComponent></FailingComponent>
|
|
</ErrorBoundary>,
|
|
);
|
|
};
|
|
|
|
describe("<ErrorBoundary />", () => {
|
|
it("matches snapshot", () => {
|
|
const { asFragment } = renderFailingComponent();
|
|
expect(asFragment()).toMatchSnapshot();
|
|
expect(consoleSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("componentDidCatch should catch an error from FailingComponent", () => {
|
|
jest.spyOn(ErrorBoundary.prototype, "componentDidCatch");
|
|
renderFailingComponent();
|
|
expect(ErrorBoundary.prototype.componentDidCatch).toHaveBeenCalled();
|
|
});
|
|
|
|
it("sets up timer to reload after 60s", () => {
|
|
// Verifies that a timer is set up for auto-reload after error
|
|
renderFailingComponent();
|
|
expect(jest.getTimerCount()).toBe(1);
|
|
expect(consoleSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("renders error message when component fails", () => {
|
|
renderFailingComponent();
|
|
expect(
|
|
screen.getByText("Error: Error thrown from problem child"),
|
|
).toBeInTheDocument();
|
|
expect(consoleSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("decrements reload countdown each second", () => {
|
|
// Verifies the reloadApp method decrements the countdown timer
|
|
renderFailingComponent();
|
|
expect(screen.getByText(/auto refresh in 60s/)).toBeInTheDocument();
|
|
|
|
act(() => {
|
|
jest.advanceTimersByTime(1000);
|
|
});
|
|
expect(screen.getByText(/auto refresh in 59s/)).toBeInTheDocument();
|
|
|
|
act(() => {
|
|
jest.advanceTimersByTime(1000);
|
|
});
|
|
});
|
|
|
|
it("reloadApp decrements countdown when more than one second is left", () => {
|
|
// Verifies that reloadApp uses functional setState to decrement reloadSeconds
|
|
const boundary = new ErrorBoundary({ children: <span /> });
|
|
const setStateSpy = jest.spyOn(boundary, "setState");
|
|
boundary.state = { cachedError: null, reloadSeconds: 2 };
|
|
|
|
boundary.reloadApp();
|
|
|
|
expect(setStateSpy).toHaveBeenCalledTimes(1);
|
|
const updater = setStateSpy.mock.calls[0][0] as unknown as (prev: {
|
|
reloadSeconds: number;
|
|
}) => { reloadSeconds: number };
|
|
expect(updater({ reloadSeconds: 2 })).toEqual({ reloadSeconds: 1 });
|
|
});
|
|
|
|
it("reloadApp does not decrement when countdown reaches 1 or less", () => {
|
|
// Verifies that reloadApp calls window.location.reload when reloadSeconds <= 1 (line 65)
|
|
const boundary = new ErrorBoundary({ children: <span /> });
|
|
const setStateSpy = jest.spyOn(boundary, "setState");
|
|
boundary.state = { cachedError: null, reloadSeconds: 1 };
|
|
|
|
boundary.reloadApp();
|
|
|
|
expect(setStateSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("componentDidCatch does not set error if already cached", () => {
|
|
// Verifies that componentDidCatch skips setState when error is already cached (line 75)
|
|
const boundary = new ErrorBoundary({ children: <span /> });
|
|
const setStateSpy = jest.spyOn(boundary, "setState");
|
|
const error = new Error("Test error");
|
|
boundary.state = { cachedError: error, reloadSeconds: 60 };
|
|
|
|
boundary.componentDidCatch(error, { componentStack: "" });
|
|
|
|
expect(setStateSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("componentDidCatch does not set timer if already set", () => {
|
|
// Verifies that componentDidCatch skips setInterval when timer is already set (line 80)
|
|
const boundary = new ErrorBoundary({ children: <span /> });
|
|
const setIntervalSpy = jest.spyOn(global, "setInterval");
|
|
const error = new Error("Test error");
|
|
boundary.timer = 123 as unknown as ReturnType<typeof setInterval>;
|
|
|
|
boundary.componentDidCatch(error, { componentStack: "" });
|
|
|
|
expect(setIntervalSpy).not.toHaveBeenCalled();
|
|
setIntervalSpy.mockRestore();
|
|
});
|
|
});
|