Skip to content

Commit a24b88a

Browse files
authored
test: add error resilience tests for ResumePreviewForm (JhaSourav07#3521)
## Description Fixes JhaSourav07#2698 Added error resilience test coverage for `ResumePreviewForm`. ### Tests Added * Handles missing required fields gracefully * Handles failed API responses with custom error messages * Handles non-OK API responses with fallback error messages * Handles network exceptions safely * Verifies recovery after a failed request and successful retry All tests pass locally with Vitest. ## Pillar * [ ] 🎨 Pillar 1 — New Theme Design * [ ] 📐 Pillar 2 — Geometric SVG Improvement * [ ] 🕐 Pillar 3 — Timezone Logic Optimization * [x] 🛠️ Other (Bug fix, refactoring, docs) ## Visual Preview N/A (test-only changes) ## Checklist before requesting a review: * [x] I have read the `CONTRIBUTING.md` file. * [ ] I have tested these changes locally (`localhost:3000/api/streak?user=YOUR_USERNAME`). * [x] I have run `npm run format` and `npm run lint` locally and resolved all errors (CI will fail otherwise). * [x] My commits follow the Conventional Commits format (e.g., `feat(themes): ...`, `fix(calculate): ...`). * [ ] I have updated `README.md` if I added a new theme or URL parameter. * [x] I have started the repo. * [x] I have made sure that i have only one commit to merge in this PR. * [ ] The SVG output matches the CommitPulse "premium quality" aesthetic standard (no raw elements, smooth animations, correct fonts). * [x] (Recommended) I joined the CommitPulse Discord community for contributor discussions, mentorship, and faster PR support.
2 parents a0bf4c6 + 4d2a7ca commit a24b88a

1 file changed

Lines changed: 177 additions & 0 deletions

File tree

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
2+
import { describe, it, expect, vi, beforeEach } from 'vitest';
3+
import ResumePreviewForm from './ResumePreviewForm';
4+
import type { ReactNode, HTMLAttributes } from 'react';
5+
import '@testing-library/jest-dom';
6+
7+
const toastMocks = vi.hoisted(() => ({
8+
error: vi.fn(),
9+
success: vi.fn(),
10+
}));
11+
12+
vi.mock('sonner', () => ({
13+
toast: {
14+
error: toastMocks.error,
15+
success: toastMocks.success,
16+
},
17+
}));
18+
19+
vi.mock('framer-motion', () => ({
20+
motion: {
21+
div: ({ children, ...props }: HTMLAttributes<HTMLDivElement> & { children?: ReactNode }) => (
22+
<div {...props}>{children}</div>
23+
),
24+
},
25+
}));
26+
27+
const parsed = {
28+
name: 'John Doe',
29+
email: 'john@example.com',
30+
phone: '1234567890',
31+
skills: ['React'],
32+
education: [],
33+
experience: [],
34+
};
35+
36+
describe('ResumePreviewForm - Error Resilience', () => {
37+
const onBack = vi.fn();
38+
const onComplete = vi.fn();
39+
40+
beforeEach(() => {
41+
vi.clearAllMocks();
42+
});
43+
44+
it('handles missing required fields gracefully', () => {
45+
render(
46+
<ResumePreviewForm
47+
githubUsername="john"
48+
parsed={{
49+
...parsed,
50+
name: '',
51+
email: '',
52+
}}
53+
fileName="resume.pdf"
54+
onBack={onBack}
55+
onComplete={onComplete}
56+
/>
57+
);
58+
59+
fireEvent.click(screen.getByText('Save Profile'));
60+
61+
expect(toastMocks.error).toHaveBeenCalledWith('Name and email are required');
62+
63+
expect(onComplete).not.toHaveBeenCalled();
64+
});
65+
66+
it('handles failed API responses with custom error message', async () => {
67+
global.fetch = vi.fn().mockResolvedValue({
68+
ok: true,
69+
json: async () => ({
70+
success: false,
71+
error: 'Profile validation failed',
72+
}),
73+
}) as typeof fetch;
74+
75+
render(
76+
<ResumePreviewForm
77+
githubUsername="john"
78+
parsed={parsed}
79+
fileName="resume.pdf"
80+
onBack={onBack}
81+
onComplete={onComplete}
82+
/>
83+
);
84+
85+
fireEvent.click(screen.getByText('Save Profile'));
86+
87+
await waitFor(() => {
88+
expect(toastMocks.error).toHaveBeenCalledWith('Profile validation failed');
89+
});
90+
91+
expect(onComplete).not.toHaveBeenCalled();
92+
});
93+
94+
it('handles non-ok API responses with fallback error message', async () => {
95+
global.fetch = vi.fn().mockResolvedValue({
96+
ok: false,
97+
json: async () => ({
98+
success: false,
99+
}),
100+
}) as typeof fetch;
101+
102+
render(
103+
<ResumePreviewForm
104+
githubUsername="john"
105+
parsed={parsed}
106+
fileName="resume.pdf"
107+
onBack={onBack}
108+
onComplete={onComplete}
109+
/>
110+
);
111+
112+
fireEvent.click(screen.getByText('Save Profile'));
113+
114+
await waitFor(() => {
115+
expect(toastMocks.error).toHaveBeenCalledWith('Failed to save profile');
116+
});
117+
118+
expect(onComplete).not.toHaveBeenCalled();
119+
});
120+
121+
it('handles network exceptions safely', async () => {
122+
global.fetch = vi.fn().mockRejectedValue(new Error('Network failure')) as typeof fetch;
123+
124+
render(
125+
<ResumePreviewForm
126+
githubUsername="john"
127+
parsed={parsed}
128+
fileName="resume.pdf"
129+
onBack={onBack}
130+
onComplete={onComplete}
131+
/>
132+
);
133+
134+
fireEvent.click(screen.getByText('Save Profile'));
135+
136+
await waitFor(() => {
137+
expect(toastMocks.error).toHaveBeenCalledWith('Network error. Please try again.');
138+
});
139+
140+
expect(onComplete).not.toHaveBeenCalled();
141+
});
142+
143+
it('recovers correctly after a failed request and allows successful retry', async () => {
144+
global.fetch = vi
145+
.fn()
146+
.mockRejectedValueOnce(new Error('Network failure'))
147+
.mockResolvedValueOnce({
148+
ok: true,
149+
json: async () => ({
150+
success: true,
151+
}),
152+
}) as typeof fetch;
153+
154+
render(
155+
<ResumePreviewForm
156+
githubUsername="john"
157+
parsed={parsed}
158+
fileName="resume.pdf"
159+
onBack={onBack}
160+
onComplete={onComplete}
161+
/>
162+
);
163+
164+
fireEvent.click(screen.getByText('Save Profile'));
165+
166+
await waitFor(() => {
167+
expect(toastMocks.error).toHaveBeenCalledWith('Network error. Please try again.');
168+
});
169+
170+
fireEvent.click(screen.getByText('Save Profile'));
171+
172+
await waitFor(() => {
173+
expect(toastMocks.success).toHaveBeenCalledWith('Profile saved successfully!');
174+
expect(onComplete).toHaveBeenCalled();
175+
});
176+
});
177+
});

0 commit comments

Comments
 (0)