Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions wp-ict-platform/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# Build outputs
/assets/js/dist
/assets/js/css
/assets/css/dist
*.map

Expand Down
3 changes: 0 additions & 3 deletions wp-ict-platform/assets/js/css/admin.css

This file was deleted.

13 changes: 8 additions & 5 deletions wp-ict-platform/src/components/common/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface State {
hasError: boolean;
error: Error | null;
errorInfo: ErrorInfo | null;
resetKey: number;
}

export class ErrorBoundary extends Component<Props, State> {
Expand All @@ -30,6 +31,7 @@ export class ErrorBoundary extends Component<Props, State> {
hasError: false,
error: null,
errorInfo: null,
resetKey: 0,
};
}

Expand All @@ -45,7 +47,7 @@ export class ErrorBoundary extends Component<Props, State> {
type: 'react_error',
message: error.message,
stack: error.stack,
componentStack: errorInfo.componentStack,
componentStack: errorInfo.componentStack ?? undefined,
timestamp: new Date().toISOString(),
});

Expand All @@ -54,15 +56,16 @@ export class ErrorBoundary extends Component<Props, State> {
}

handleRetry = (): void => {
this.setState({
this.setState((prevState) => ({
hasError: false,
error: null,
errorInfo: null,
});
resetKey: prevState.resetKey + 1,
}));
};

render(): ReactNode {
const { hasError, error, errorInfo } = this.state;
const { hasError, error, errorInfo, resetKey } = this.state;
const { children, fallback, showDetails } = this.props;

if (hasError) {
Expand Down Expand Up @@ -148,7 +151,7 @@ export class ErrorBoundary extends Component<Props, State> {
);
}

return children;
return <React.Fragment key={resetKey}>{children}</React.Fragment>;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { ErrorBoundary } from '../ErrorBoundary';

// Mock the errorLogger
Expand Down Expand Up @@ -87,27 +87,42 @@ describe('ErrorBoundary', () => {
expect(screen.getByText('Technical Details')).toBeInTheDocument();
});

it('provides try again button that resets error state', () => {
it('provides try again button that resets error state', async () => {
const TestComponent: React.FC<{ throwError: boolean }> = ({ throwError }) => {
if (throwError) {
throw new Error('Test error');
}
return <div>No error</div>;
};

let throwError = true;
const { rerender } = render(
<ErrorBoundary>
<ThrowError />
<TestComponent throwError={throwError} />
</ErrorBoundary>
);

// Error boundary should show error UI
expect(screen.getByText('Something went wrong')).toBeInTheDocument();

// Click try again
fireEvent.click(screen.getByText('Try Again'));

// Re-render with a component that doesn't throw
// First, update the component to not throw
throwError = false;
rerender(
<ErrorBoundary>
<ThrowError shouldThrow={false} />
<TestComponent throwError={throwError} />
</ErrorBoundary>
);

expect(screen.getByText('No error')).toBeInTheDocument();
// The error UI should still be shown (error state persists)
expect(screen.getByText('Something went wrong')).toBeInTheDocument();

// Now click try again - this resets the error state and re-renders children
fireEvent.click(screen.getByText('Try Again'));

// Now the component should render without error
await waitFor(() => {
expect(screen.getByText('No error')).toBeInTheDocument();
});
});

it('is accessible with proper ARIA attributes', () => {
Expand Down