-
Start the development server
cd frontend npm run dev -
Open the app and navigate to any page
- App should load normally
-
Open browser DevTools (F12)
- Go to Console tab
-
Throw an error to test the boundary
throw new Error('Test error from console');
-
Expected Behavior:
- ✅ Error boundary catches the error
- ✅ Fallback UI appears with friendly message
- ✅ "Oops! Something Went Wrong" shown
- ✅ Error details visible in console
- ✅ "Error Details (Development Only)" section appears (in dev mode)
- ✅ "🔄 Reload Page" button is visible
-
Click "Reload Page" button
- ✅ Page reloads
- ✅ App returns to normal state
- ✅ Error is gone
With development error details:
-
Error boundary should show expanded details section
- Click "Error Details (Development Only)" to expand
- Shows JSON with: message, stack, componentStack, timestamp
- Helps with debugging
-
Console should show:
Error caught by ErrorBoundary: Error: Test error Error Info: { componentStack: "..." }
-
Build the app for production
cd frontend npm run build -
Serve from production build
npm run preview
-
Trigger error again from console
throw new Error('Test in production');
-
Expected Behavior:
- ✅ Fallback UI appears (same as before)
- ✅ "Error Details" section is NOT visible
- ✅ Only user-friendly message shown
- ✅ Error still logged to console
- ✅ Reload button still works
Create a temporary component that throws an error:
-
Create test component (in
frontend/src/pages/)// ErrorTest.jsx export default function ErrorTest() { throw new Error('Component initialization failed'); return <div>This won't render</div>; }
-
Add route to App.jsx temporarily
<Route path="/error-test" element={<ErrorTest />} />
-
Navigate to
/error-test- ✅ Error boundary catches it
- ✅ Shows friendly error message
- ✅ Shows which component failed in details
-
Remove test component and route
-
Create component with event handler error
function TestEventError() { const handleClick = () => { throw new Error('Event handler error'); }; return <button onClick={handleClick}>Throw Error</button>; }
-
Click the button
- ❌ Error boundary does NOT catch this
- ✅ Error appears in console only
- ✅ App continues working
- ✅ UI not affected
-
This is expected behavior - use try-catch inside event handlers
Note: API call errors in componentDidCatch won't be caught by the boundary, but this is expected.
-
Component with async API call
useEffect(() => { fetch('/api/invalid') .then(r => r.json()) .catch(e => { // Handle error here console.error('API error:', e); }); }, []);
-
This error won't trigger boundary - expected
-
Use try-catch or .catch() to handle - recommended pattern
Optional - requires backend endpoint
-
Check if
/api/errorsendpoint exists -
If it exists, trigger an error
- Check Network tab in DevTools
- Should see POST request to
/api/errors - Request body includes stack trace and context
-
If endpoint doesn't exist
- Error is logged to console (fallback already there)
- App still functions normally
// ErrorBoundary.test.jsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import ErrorBoundary from './ErrorBoundary';
// Component that throws an error
function ThrowError() {
throw new Error('Test error');
}
describe('ErrorBoundary', () => {
// Suppress console errors in tests
beforeAll(() => {
jest.spyOn(console, 'error').mockImplementation(() => {});
});
afterAll(() => {
console.error.mockRestore();
});
test('displays error UI when child component throws', () => {
render(
<ErrorBoundary>
<ThrowError />
</ErrorBoundary>
);
expect(screen.getByText(/Oops! Something Went Wrong/)).toBeInTheDocument();
expect(screen.getByText(/unexpected error/)).toBeInTheDocument();
});
test('includes reload button', () => {
render(
<ErrorBoundary>
<ThrowError />
</ErrorBoundary>
);
const reloadButton = screen.getByText(/Reload Page/);
expect(reloadButton).toBeInTheDocument();
});
test('renders children when no error', () => {
render(
<ErrorBoundary>
<div>Success content</div>
</ErrorBoundary>
);
expect(screen.getByText('Success content')).toBeInTheDocument();
});
});- Navigate to
/error-testpage (with test component) - Verify error boundary UI appears
- Verify message says "Oops! Something Went Wrong"
- Verify app is not blank (has styled error box)
- Error UI is displayed
- Click "🔄 Reload Page" button
- Page reloads successfully
- App returns to normal
- Trigger error from console
- Open DevTools Console tab
- Verify "Error caught by ErrorBoundary:" message
- Verify error stack trace visible
- Create button with throwing event handler
- Click button
- Error appears ONLY in console
- Error boundary UI does NOT appear
- App continues to work
- Error boundary active (showing error UI)
- Click reload button
- Page reloads
- App loads normally (hasError state reset)
- Can navigate and use app again
Solution:
- Check browser console for errors
- Verify JavaScript is enabled
- Try F5 or Cmd+R manually
Solution:
- Check if running in development mode
- Build might be minified in production
- Expected behavior in production
Solution:
- Boundary only catches render errors
- Check if error is in event handler
- Use try-catch in event handlers
- Check if error is async (promises, setTimeout)
Solution:
- Error might be in ErrorBoundary itself
- Check browser console for boundary errors
- Boundary has no error handler (can't catch its own errors)
- Check if error is in outer provider
- Error boundary has minimal performance impact
- No error = no overhead (just wraps children)
- Error caught = minimal processing (render fallback UI)
- Backend logging is non-blocking (doesn't wait for response)
-
Error boundaries are not a replacement for error handling
- Still use try-catch in async code
- Still use error handlers in event listeners
- Boundary is a safety net
-
Multiple boundaries are possible
- Can wrap subtrees with their own boundaries
- Isolates errors to specific sections
- More granular error handling
-
State not recovered
- After reload, component state is reset
- App state should be in localStorage/Redux
- Consider state persistence strategy
-
Testing in React StrictMode
- StrictMode intentionally double-invokes functions
- May trigger error boundary in development
- Doesn't happen in production
After testing, remove any test components or routes added:
# Remove test files
rm frontend/src/pages/ErrorTest.jsx
# Remove test routes from App.jsx
# (Already removed in production code)