import { render, screen } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { describe, expect, it, vi } from "vitest" import { StyleTemplateErrorBoundary, withStyleTemplateErrorBoundary } from "../style-template-error-boundary" // Component that throws an error const ThrowError = ({ shouldThrow }: { shouldThrow: boolean }) => { if (shouldThrow) { throw new Error("Test error message") } return
Normal content
} describe("StyleTemplateErrorBoundary", () => { // Suppress console.error for these tests const originalError = console.error beforeEach(() => { console.error = vi.fn() }) afterEach(() => { console.error = originalError }) it("should render children when there is no error", () => { render(
Test content
, ) expect(screen.getByText("Test content")).toBeInTheDocument() }) it("should render default error UI when error occurs", () => { render( , ) expect(screen.getByText("Ошибка загрузки шаблонов")).toBeInTheDocument() expect(screen.getByText("Test error message")).toBeInTheDocument() expect(screen.getByText("Попробовать снова")).toBeInTheDocument() }) it("should render custom fallback when provided", () => { const customFallback =
Custom error fallback
render( , ) expect(screen.getByText("Custom error fallback")).toBeInTheDocument() expect(screen.queryByText("Ошибка загрузки шаблонов")).not.toBeInTheDocument() }) it("should log error to console", () => { const consoleSpy = vi.spyOn(console, "error") render( , ) expect(consoleSpy).toHaveBeenCalledWith( "StyleTemplateErrorBoundary caught an error:", expect.any(Error), expect.any(Object), ) }) it("should handle retry button click", async () => { const user = userEvent.setup() let throwError = true const TestComponent = () => { if (throwError) { throw new Error("Test error") } return
Success after retry
} const { rerender } = render( , ) // Initially shows error expect(screen.getByText("Ошибка загрузки шаблонов")).toBeInTheDocument() // Set to not throw error anymore throwError = false // Click retry button const retryButton = screen.getByText("Попробовать снова") await user.click(retryButton) // Should reset error state and try to render children again rerender( , ) expect(screen.getByText("Success after retry")).toBeInTheDocument() expect(screen.queryByText("Ошибка загрузки шаблонов")).not.toBeInTheDocument() }) it("should show unknown error message when error has no message", () => { const ErrorWithoutMessage = () => { throw new Error() } render( , ) expect(screen.getByText("Произошла неизвестная ошибка")).toBeInTheDocument() }) it("should have proper styling for error UI", () => { render( , ) const errorContainer = screen.getByText("Ошибка загрузки шаблонов").parentElement?.parentElement expect(errorContainer).toBeDefined() const errorIcon = errorContainer?.querySelector(".h-12.w-12") expect(errorIcon).toBeInTheDocument() const retryButton = screen.getByText("Попробовать снова") expect(retryButton).toHaveClass("flex", "items-center", "gap-2", "rounded-md", "bg-red-600") }) it("should have refresh icon in retry button", () => { render( , ) const retryButton = screen.getByText("Попробовать снова") const refreshIcon = retryButton.querySelector(".h-4.w-4") expect(refreshIcon).toBeInTheDocument() }) }) describe("withStyleTemplateErrorBoundary HOC", () => { const originalError = console.error beforeEach(() => { console.error = vi.fn() }) afterEach(() => { console.error = originalError }) it("should wrap component with error boundary", () => { const TestComponent = () =>
Test component
const WrappedComponent = withStyleTemplateErrorBoundary(TestComponent) render() expect(screen.getByText("Test component")).toBeInTheDocument() }) it("should catch errors in wrapped component", () => { const ErrorComponent = () => { throw new Error("Component error") } const WrappedComponent = withStyleTemplateErrorBoundary(ErrorComponent) render() expect(screen.getByText("Component error")).toBeInTheDocument() expect(screen.getByText("Ошибка загрузки шаблонов")).toBeInTheDocument() }) it("should use custom fallback when provided", () => { const ErrorComponent = () => { throw new Error("Component error") } const customFallback =
Custom HOC fallback
const WrappedComponent = withStyleTemplateErrorBoundary(ErrorComponent, customFallback) render() expect(screen.getByText("Custom HOC fallback")).toBeInTheDocument() expect(screen.queryByText("Ошибка загрузки шаблонов")).not.toBeInTheDocument() }) it("should pass props to wrapped component", () => { interface TestProps { message: string count: number } const TestComponent = ({ message, count }: TestProps) => (
{message} - {count}
) const WrappedComponent = withStyleTemplateErrorBoundary(TestComponent) render() expect(screen.getByText("Hello - 42")).toBeInTheDocument() }) it("should handle component that throws on specific prop", () => { const ConditionalErrorComponent = ({ shouldError }: { shouldError: boolean }) => { if (shouldError) { throw new Error("Conditional error") } return
No error
} const WrappedComponent = withStyleTemplateErrorBoundary(ConditionalErrorComponent) const { rerender } = render() expect(screen.getByText("No error")).toBeInTheDocument() rerender() expect(screen.getByText("Conditional error")).toBeInTheDocument() }) })