test: verify Hydration Stability, Exception Safety & Error Fallbacks (Variation 6) #7082#7402
Conversation
|
@BikramMondal5 is attempting to deploy a commit to the jhasourav07's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
Adds a new Vitest/@testing-library test suite intended to validate ReviewAnalytics behavior under runtime failures, including localized error-boundary fallbacks, telemetry forwarding, and recovery controls.
Changes:
- Introduces
ReviewAnalytics.error-resilience.test.tsxwith five resilience-focused test cases. - Adds a custom
TestErrorBoundaryfixture to assert fallback UI, telemetry callbacks, and reload control visibility.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import React, { Component, type ReactNode } from 'react'; | ||
| import { render, screen } from '@testing-library/react'; | ||
| import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; |
| // Stub framer-motion so animation wrappers render as plain divs in JSDOM. | ||
| // --------------------------------------------------------------------------- | ||
| vi.mock('framer-motion', () => ({ | ||
| motion: { | ||
| div: ({ children, ...props }: React.HTMLAttributes<HTMLDivElement>) => ( | ||
| <div {...props}>{children}</div> | ||
| ), | ||
| }, | ||
| })); |
| beforeEach(() => { | ||
| errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); | ||
| }); |
| it('Test 2: boundary element is transparent when the component renders without fault', () => { | ||
| // Normal, well-formed data — no exception should be thrown. | ||
| render( | ||
| <TestErrorBoundary> | ||
| <ReviewAnalytics data={baseData} /> |
| it('Test 3: renders a clean error recovery UI with role="alert" when an inner child throws an unhandled exception', () => { | ||
| // A minimal component that always throws — models a dependency that | ||
| // explodes when the external service connection is lost. | ||
| const BrokenReviewChild = (): never => { | ||
| throw new Error('503 Service Unavailable — review analytics unreachable'); | ||
| }; | ||
|
|
||
| render( | ||
| <TestErrorBoundary> | ||
| <BrokenReviewChild /> | ||
| </TestErrorBoundary> | ||
| ); | ||
|
|
||
| // The recovery panel must carry role="alert" for assistive technologies. | ||
| const panel = screen.getByRole('alert'); | ||
| expect(panel).toBeDefined(); | ||
| expect(panel).toHaveAttribute('data-testid', 'error-recovery-panel'); | ||
|
|
||
| // A meaningful human-readable message must be shown. | ||
| expect(screen.getByText('The review analytics panel failed to load.')).toBeInTheDocument(); | ||
| }); |
| it('Test 4: exceptions are forwarded to the telemetry callback with the correct error message', () => { | ||
| const telemetry = vi.fn(); | ||
| const DB_ERROR_MSG = 'MongoDB connection pool exhausted'; | ||
|
|
||
| const DatabaseFailureChild = (): never => { | ||
| throw new Error(DB_ERROR_MSG); | ||
| }; | ||
|
|
||
| render( | ||
| <TestErrorBoundary onError={telemetry}> | ||
| <DatabaseFailureChild /> | ||
| </TestErrorBoundary> | ||
| ); | ||
|
|
||
| // onError must be called exactly once per error event. | ||
| expect(telemetry).toHaveBeenCalledOnce(); | ||
|
|
||
| // The propagated error must carry the original message so log | ||
| // aggregators can group and alert on it correctly. | ||
| const receivedError: Error = telemetry.mock.calls[0][0]; | ||
| expect(receivedError).toBeInstanceOf(Error); | ||
| expect(receivedError.message).toBe(DB_ERROR_MSG); | ||
| }); |
| it('Test 5: the recovery panel exposes a reload button that is reachable by assistive technologies', () => { | ||
| const AlwaysBroken = (): never => { | ||
| throw new Error('Simulated background service interruption'); | ||
| }; | ||
|
|
||
| render( | ||
| <TestErrorBoundary> | ||
| <AlwaysBroken /> | ||
| </TestErrorBoundary> | ||
| ); | ||
|
|
||
| // The recovery panel must be in the DOM. | ||
| expect(screen.getByTestId('error-recovery-panel')).toBeInTheDocument(); | ||
|
|
||
| // A clearly labelled reset button must be discoverable via accessible | ||
| // role query — not just by class name or data-testid — so keyboard and | ||
| // screen-reader users can invoke it. | ||
| const reloadBtn = screen.getByRole('button', { name: /reload panel/i }); | ||
| expect(reloadBtn).toBeInTheDocument(); | ||
| }); | ||
| }); |
📦 Next.js Bundle Size Report (Gzipped Sizes)✨ No significant bundle size changes detected. 📊 Summary of Totals
|
Aamod007
left a comment
There was a problem hiding this comment.
Hey! Thanks for adding error resilience and hydration stability tests for ReviewAnalytics. Ensuring that downstream failures trigger appropriate error boundaries and don't break the app is crucial for stability.
I'm assigning level:intermediate for handling hydration fallbacks, type:testing, and quality:clean.
Great job, I'm approving this PR!
|
Thanks! Happy to contribute |
|
🎉 Congratulations @BikramMondal5! Your PR has been successfully merged. 🚀 Thank you for contributing to CommitPulse. Your work helps us build a better tool for the community.
Keep building! 💻✨ |
Description
Fixes #7082
Add isolated unit and integration test suite
ReviewAnalytics.error-resilience.test.tsxtargeting Hydration Stability, Exception Safety & Error Fallbacks. The suite verifies that:ReviewAnalyticsdo not crash the React app and are caught by a localized error boundary.alert.Pillar
Visual Preview
(N/A - This PR only introduces test suite additions)
Checklist before requesting a review:
CONTRIBUTING.mdfile.localhost:3000/api/streak?user=YOUR_USERNAME).npm run formatandnpm run lintlocally and resolved all errors (CI will fail otherwise).feat(themes): ...,fix(calculate): ...).README.mdif I added a new theme or URL parameter.