Skip to content

Commit cb3af96

Browse files
authored
test(resume-parser): add empty-fallback test suite (JhaSourav07#2873) (JhaSourav07#3002)
## Description Adds the comprehensive `resume-parser.empty-fallback.test.ts` test suite to cover all missing fields, empty inputs, malformed contact detail scenarios, and boundary/split sections in the resume parser. Fixes JhaSourav07#2873 ## 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 (Utility/Unit Tests only) ## Checklist before requesting a review: - [x] I have read the `CONTRIBUTING.md` file. - [x] I have tested these changes locally. - [x] I have run `npm run format` and `npm run lint` locally and resolved all errors. - [x] My commits follow the Conventional Commits format. - [x] 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. - [ ] (Recommended) I joined the CommitPulse Discord community.
2 parents f39b2e1 + 08ac8fa commit cb3af96

2 files changed

Lines changed: 131 additions & 5 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { parseResume } from './resume-parser';
3+
4+
describe('resume-parser-empty-fallback', () => {
5+
it('should return empty fields when the buffer is completely empty', async () => {
6+
const buffer = Buffer.from('');
7+
const result = await parseResume(buffer, 'application/pdf');
8+
9+
expect(result).toEqual({
10+
name: '',
11+
email: '',
12+
phone: '',
13+
skills: [],
14+
education: [],
15+
experience: [],
16+
});
17+
});
18+
19+
it('should return empty fields when the buffer contains only whitespace and newlines', async () => {
20+
const buffer = Buffer.from(' \n \r\n ');
21+
const result = await parseResume(buffer, 'application/pdf');
22+
23+
expect(result).toEqual({
24+
name: '',
25+
email: '',
26+
phone: '',
27+
skills: [],
28+
education: [],
29+
experience: [],
30+
});
31+
});
32+
33+
it('should return empty email if no email matches the regex', async () => {
34+
const text = 'John Doe\nSoftware Engineer\nNo contact info here';
35+
const buffer = Buffer.from(text);
36+
const result = await parseResume(buffer, 'application/pdf');
37+
38+
expect(result.email).toBe('');
39+
});
40+
41+
it('should return empty email if email is malformed', async () => {
42+
const text = 'John Doe\nemail@com\n@domain.com\nusername@';
43+
const buffer = Buffer.from(text);
44+
const result = await parseResume(buffer, 'application/pdf');
45+
46+
expect(result.email).toBe('');
47+
});
48+
49+
it('should return empty name if first few lines do not match name regex', async () => {
50+
const text = '12345 Random Line\nengineer@domain.com\nhttp://github.com/johndoe';
51+
const buffer = Buffer.from(text);
52+
const result = await parseResume(buffer, 'application/pdf');
53+
54+
expect(result.name).toBe('');
55+
});
56+
57+
it('should return empty name if first lines have lowercase initials only', async () => {
58+
const text = 'john doe\nsoftware developer';
59+
const buffer = Buffer.from(text);
60+
const result = await parseResume(buffer, 'application/pdf');
61+
62+
expect(result.name).toBe('');
63+
});
64+
65+
it('should return empty phone if phone is missing or contains invalid characters', async () => {
66+
const text = 'John Doe\njohn.doe@example.com\nPhone: abc-def-ghij';
67+
const buffer = Buffer.from(text);
68+
const result = await parseResume(buffer, 'application/pdf');
69+
70+
expect(result.phone).toBe('');
71+
});
72+
73+
it('should return empty skills if no skills section header is present', async () => {
74+
const text = 'John Doe\nHere are some of my tools: Git, JavaScript';
75+
const buffer = Buffer.from(text);
76+
const result = await parseResume(buffer, 'application/pdf');
77+
78+
expect(result.skills).toEqual([]);
79+
});
80+
81+
it('should handle empty section content when section header is present but followed immediately by another section', async () => {
82+
const text = `John Doe
83+
Skills
84+
Education
85+
University of Toronto 2018 - 2022
86+
`;
87+
const buffer = Buffer.from(text);
88+
const result = await parseResume(buffer, 'application/pdf');
89+
90+
expect(result.skills).toEqual([]);
91+
expect(result.education).toEqual([
92+
{
93+
institution: 'University of Toronto 2018 - 2022',
94+
degree: '',
95+
field: '',
96+
startDate: '2018',
97+
endDate: '2022',
98+
},
99+
]);
100+
});
101+
102+
it('should return empty education list when education section is missing or date is missing', async () => {
103+
const text = `John Doe
104+
Education
105+
University of Toronto
106+
No date here
107+
`;
108+
const buffer = Buffer.from(text);
109+
const result = await parseResume(buffer, 'application/pdf');
110+
111+
expect(result.education).toEqual([]);
112+
});
113+
114+
it('should return empty experience list when experience section is missing or date is missing', async () => {
115+
const text = `John Doe
116+
Experience
117+
Software Developer at Google
118+
No date mentioned
119+
`;
120+
const buffer = Buffer.from(text);
121+
const result = await parseResume(buffer, 'application/pdf');
122+
123+
expect(result.experience).toEqual([]);
124+
});
125+
});

lib/resume-parser.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ function extractSection(text: string, headers: RegExp): string[] {
4141
}
4242
if (inSection) {
4343
if (
44-
SKILL_SECTION_HEADERS.test(line) ||
45-
EDUCATION_SECTION_HEADERS.test(line) ||
46-
EXPERIENCE_SECTION_HEADERS.test(line)
44+
(SKILL_SECTION_HEADERS.test(line) && !headers.test(line)) ||
45+
(EDUCATION_SECTION_HEADERS.test(line) && !headers.test(line)) ||
46+
(EXPERIENCE_SECTION_HEADERS.test(line) && !headers.test(line))
4747
) {
48-
if (line !== lines[lines.indexOf(line)]) break;
48+
break;
4949
}
5050
sectionLines.push(line);
5151
}
@@ -113,7 +113,8 @@ function extractTextFromBuffer(buffer: Buffer, _mimeType: string): string {
113113
const text = buffer.toString('utf-8');
114114
const printable = text
115115
.replace(/[^\x20-\x7E\n\r]/g, ' ')
116-
.replace(/\s+/g, ' ')
116+
.replace(/[ \t]+/g, ' ')
117+
.replace(/\r/g, '')
117118
.trim();
118119
return printable;
119120
}

0 commit comments

Comments
 (0)