diff --git a/src/app/common/components/ErrorBoundary/ErrorBoundary.spec.tsx b/src/app/common/components/ErrorBoundary/ErrorBoundary.spec.tsx new file mode 100644 index 000000000..85cf87e09 --- /dev/null +++ b/src/app/common/components/ErrorBoundary/ErrorBoundary.spec.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import ErrorBoundary from './ErrorBoundary'; + +const ProblemChild = () => { + throw new Error('Error thrown from problem child'); +}; + +describe('ErrorBoundary', () => { + test('renders children without error', () => { + render( + Fallback}> +
Child Component
+
+ ); + + expect(screen.getByText('Child Component')).toBeInTheDocument(); + }); + + test('renders fallback UI on error', () => { + render( + Fallback}> + + + ); + + expect(screen.getByText('Fallback')).toBeInTheDocument(); + }); + + test('sets hasError state to true on error', () => { + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + render( + Fallback}> + + + ); + + expect(screen.getByText('Fallback')).toBeInTheDocument(); + expect(consoleErrorSpy).toHaveBeenCalled(); + + consoleErrorSpy.mockRestore(); + }); +}); \ No newline at end of file diff --git a/src/app/common/components/ErrorBoundary/ErrorBoundary.ts b/src/app/common/components/ErrorBoundary/ErrorBoundary.ts new file mode 100644 index 000000000..20cbccc58 --- /dev/null +++ b/src/app/common/components/ErrorBoundary/ErrorBoundary.ts @@ -0,0 +1,35 @@ +import { ReactNode, Component, ErrorInfo } from "react"; + +interface Props { + children: ReactNode; + fallback: ReactNode; +} + +interface State { + hasError: boolean; +} + +class ErrorBoundary extends Component { + public state: State = { + hasError: false + }; + + public static getDerivedStateFromError(_: Error): State { + return { hasError: true }; + } + + public componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error('ErrorBoundary caught an error: ', error, errorInfo); + this.setState({ hasError: true }); + } + + public render() { + if (this.state.hasError) { + return this.props.fallback; + } + + return this.props.children; + } +} + +export default ErrorBoundary; \ No newline at end of file diff --git a/src/features/AdminPage/CategoriesPage/CategoriesPage.component.tsx b/src/features/AdminPage/CategoriesPage/CategoriesPage.component.tsx index 8dcae18dc..dd008d123 100644 --- a/src/features/AdminPage/CategoriesPage/CategoriesPage.component.tsx +++ b/src/features/AdminPage/CategoriesPage/CategoriesPage.component.tsx @@ -97,7 +97,7 @@ const CategoriesMainPage: React.FC = observer(() => { modalStore.setConfirmationModal('confirmation'); } }, - 'Ви впевнені, що хочете видалити чю новину?', + 'Ви впевнені, що хочете видалити цю новину?', ); }} /> diff --git a/src/features/MainPage/MainPage.component.tsx b/src/features/MainPage/MainPage.component.tsx index 66aee263c..ce928388d 100644 --- a/src/features/MainPage/MainPage.component.tsx +++ b/src/features/MainPage/MainPage.component.tsx @@ -9,6 +9,7 @@ import StaticBanner from './StaticBanners/StaticBanner.component'; import StreetcodeSliderComponent from './StreetcodeSlider/StreetcodeSlider.component'; import TeamComponent from './TeamSlider/TeamComponent.component'; import TopCarouselComponent from './TopCarousel/TopCarousel.component'; +import ErrorBoundary from '@/app/common/components/ErrorBoundary/ErrorBoundary'; const mainPageContent = () => ( <> @@ -28,7 +29,9 @@ const mainPageContent = () => ( - + }> + +