diff --git a/src/components/common/ErrorBoundary.test.tsx b/src/components/common/ErrorBoundary.test.tsx
new file mode 100644
index 0000000..6d409de
--- /dev/null
+++ b/src/components/common/ErrorBoundary.test.tsx
@@ -0,0 +1,71 @@
+import { render, screen, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+import React from 'react'
+import { ErrorBoundary } from './ErrorBoundary'
+
+function ProblemChild({ shouldThrow }: { shouldThrow?: boolean }) {
+ if (shouldThrow) {
+ throw new Error('Test render crash')
+ }
+ return
Healthy content
+}
+
+describe('ErrorBoundary', () => {
+ let consoleErrorSpy: any
+
+ beforeEach(() => {
+ consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
+ })
+
+ afterEach(() => {
+ consoleErrorSpy.mockRestore()
+ })
+
+ it('renders children when there is no error', () => {
+ render(
+
+
+
+ )
+ expect(screen.getByText('Healthy content')).toBeInTheDocument()
+ })
+
+ it('catches render error, logs via console.error, and renders default fallback UI', () => {
+ render(
+
+
+
+ )
+
+ expect(screen.getByText('Something went wrong')).toBeInTheDocument()
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ '[ErrorBoundary] Caught render error:',
+ expect.any(Error),
+ expect.any(String)
+ )
+ })
+
+ it('calls optional onError callback when an error is caught', () => {
+ const onError = vi.fn()
+ render(
+
+
+
+ )
+
+ expect(onError).toHaveBeenCalledTimes(1)
+ expect(onError).toHaveBeenCalledWith(
+ expect.objectContaining({ message: 'Test render crash' }),
+ expect.objectContaining({ componentStack: expect.any(String) })
+ )
+ })
+
+ it('renders custom fallback when provided', () => {
+ render(
+ Custom Error Screen}>
+
+
+ )
+ expect(screen.getByText('Custom Error Screen')).toBeInTheDocument()
+ })
+})
diff --git a/src/components/common/ErrorBoundary.tsx b/src/components/common/ErrorBoundary.tsx
index d32f2b7..0d5dfb0 100644
--- a/src/components/common/ErrorBoundary.tsx
+++ b/src/components/common/ErrorBoundary.tsx
@@ -1,11 +1,46 @@
-import React,{Component,type ReactNode}from 'react'
-interface P{children:ReactNode;fallback?:ReactNode}
-interface St{hasError:boolean;error?:Error}
-export class ErrorBoundary extends Component{
- state:St={hasError:false}
- static getDerivedStateFromError(e:Error):St{return{hasError:true,error:e}}
- render(){
- if(this.state.hasError)return this.props.fallback??(
Something went wrong
)
+import React, { Component, type ReactNode, type ErrorInfo } from 'react'
+
+interface ErrorBoundaryProps {
+ children: ReactNode
+ fallback?: ReactNode
+ onError?: (error: Error, info: ErrorInfo) => void
+}
+
+interface ErrorBoundaryState {
+ hasError: boolean
+ error?: Error
+}
+
+export class ErrorBoundary extends Component {
+ state: ErrorBoundaryState = { hasError: false }
+
+ static getDerivedStateFromError(e: Error): ErrorBoundaryState {
+ return { hasError: true, error: e }
+ }
+
+ componentDidCatch(error: Error, info: ErrorInfo) {
+ console.error('[ErrorBoundary] Caught render error:', error, info.componentStack)
+ if (this.props.onError) {
+ this.props.onError(error, info)
+ }
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+ this.props.fallback ?? (
+
+
Something went wrong
+
+
+ )
+ )
+ }
return this.props.children
}
}