mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
fix(freehire-search): decode HTML entities and trim whitespace in titles (#505)
Titles are indexed as the source ATS wrote them and toResult passed them through untouched, so `detail intern-fullstack-amp-ai-innovation-noise-edaawqq2` printed `Intern - Fullstack & AI Innovation ` and the same title reached `search` output. In a 93-result /scrape batch, 1 title carried `&` and 3 ended in whitespace; /scrape Step 4.75 reads an undecoded entity in a title as a half-working parser. Run the title through the existing decodeHtmlEntities (already used for detail descriptions) and trim it; an empty or whitespace-only title still falls back to "(untitled)". Three new parsing.test.ts cases pin it; all three fail on the old pass-through. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9187f894a5
commit
4f5520841f
3 files changed
+37
-2
No files matched your search
@@ -145,11 +145,15 @@ export interface JobDetailResult extends JobResult {
|
||||
description: string | null
|
||||
}
|
||||
|
||||
/** Reshape a freehire job into the contract search-result fields. */
|
||||
/**
|
||||
* Reshape a freehire job into the contract search-result fields. The title comes
|
||||
* from the source ATS as indexed, which can carry HTML entities and stray
|
||||
* whitespace ("Intern - Fullstack & AI Innovation "), so it is decoded and trimmed.
|
||||
*/
|
||||
export function toResult(j: FreehireJob): JobResult {
|
||||
return {
|
||||
id: j.public_slug,
|
||||
title: j.title || "(untitled)",
|
||||
title: decodeHtmlEntities(j.title || "").trim() || "(untitled)",
|
||||
company: j.company || null,
|
||||
company_slug: j.company_slug || null,
|
||||
location: j.location || null,
|
||||
|
||||
@@ -49,6 +49,24 @@ describe("toResult — reshape into the portal-skill contract", () => {
|
||||
expect(r.date).toBeNull();
|
||||
expect(r.work_mode).toBeNull();
|
||||
});
|
||||
|
||||
test("decodes HTML entities and trims whitespace in the title", () => {
|
||||
// Real title from the index (freehire slug intern-fullstack-amp-ai-innovation-noise-edaawqq2).
|
||||
expect(toResult(job({ title: "Intern - Fullstack & AI Innovation " })).title).toBe(
|
||||
"Intern - Fullstack & AI Innovation",
|
||||
);
|
||||
expect(toResult(job({ title: "R&D Engineer" })).title).toBe("R&D Engineer");
|
||||
expect(toResult(job({ title: "SDE Intern - Frontend " })).title).toBe("SDE Intern - Frontend");
|
||||
});
|
||||
|
||||
test("a whitespace-only title still falls back to (untitled)", () => {
|
||||
expect(toResult(job({ title: " " })).title).toBe("(untitled)");
|
||||
expect(toResult(job({ title: "" })).title).toBe("(untitled)");
|
||||
});
|
||||
|
||||
test("detail inherits the cleaned title", () => {
|
||||
expect(toDetail(job({ title: "Data & Analytics Intern" })).title).toBe("Data & Analytics Intern");
|
||||
});
|
||||
});
|
||||
|
||||
describe("toDetail — adds cleaned description + enrichment", () => {
|
||||
|
||||
Reference in new issue
Block a user