Import source: cshare-app/src/components/ErrorBoundary

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:14:02 +03:30
parent 778d792610
commit 2eb61e1adc
2 changed files with 131 additions and 0 deletions
@@ -0,0 +1,79 @@
import { Component } from 'react';
export class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { error: null };
}
static getDerivedStateFromError(error) {
return { error };
}
componentDidCatch(error, info) {
console.error('[ErrorBoundary]', error, info.componentStack);
}
reset() {
this.setState({ error: null });
}
render() {
if (this.state.error) {
if (this.props.fallback) {
return this.props.fallback(this.state.error, () => this.reset());
}
return (
<div style={{
minHeight: '60vh',
display: 'grid',
placeItems: 'center',
padding: '2rem',
textAlign: 'center',
}}>
<div style={{ maxWidth: '480px' }}>
<div style={{
width: 56,
height: 56,
borderRadius: '50%',
background: 'rgba(239,68,68,0.12)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
margin: '0 auto 1.25rem',
fontSize: 28,
}}>
⚠
</div>
<h2 style={{
fontFamily: 'var(--font-heading)',
fontSize: '1.25rem',
fontWeight: 600,
color: 'var(--text-primary)',
marginBottom: '0.5rem',
}}>
Something went wrong
</h2>
<p style={{ color: 'var(--text-muted)', fontSize: '0.9rem', marginBottom: '1.5rem' }}>
{this.state.error?.message || 'An unexpected error occurred.'}
</p>
<button
className="btn btn-primary"
onClick={() => {
this.reset();
window.location.href = '/';
}}
>
Go home
</button>
</div>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
@@ -0,0 +1,52 @@
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import ErrorBoundary from './ErrorBoundary';
// Suppress console.error noise during error boundary tests
const originalError = console.error;
beforeEach(() => { console.error = vi.fn(); });
afterEach(() => { console.error = originalError; });
function Bomb({ shouldThrow }) {
if (shouldThrow) throw new Error('Test error');
return <div>OK</div>;
}
describe('ErrorBoundary', () => {
it('renders children when no error', () => {
render(
<ErrorBoundary>
<Bomb shouldThrow={false} />
</ErrorBoundary>,
);
expect(screen.getByText('OK')).toBeInTheDocument();
});
it('renders fallback UI on error', () => {
render(
<ErrorBoundary>
<Bomb shouldThrow={true} />
</ErrorBoundary>,
);
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
expect(screen.getByText(/Test error/)).toBeInTheDocument();
});
it('renders custom fallback when provided', () => {
render(
<ErrorBoundary fallback={(err) => <div>Custom: {err.message}</div>}>
<Bomb shouldThrow={true} />
</ErrorBoundary>,
);
expect(screen.getByText('Custom: Test error')).toBeInTheDocument();
});
it('shows a go-home button on default fallback', () => {
render(
<ErrorBoundary>
<Bomb shouldThrow={true} />
</ErrorBoundary>,
);
expect(screen.getByRole('button', { name: /go home/i })).toBeInTheDocument();
});
});