fix(jobbank-search): degrade an unparseable pubDate to a null date instead of crashing the search (#416) (#417)

new Date(<unparseable>) yields an Invalid Date whose toISOString()
throws RangeError, and normalizeSearchItem runs inside an unguarded
items.map(), so one malformed RSS item killed the entire search with
{"error": "Invalid Date", "code": "API_ERROR"} and exit 1. The
un-CDATA'd fallback capture in parseRssItems can deliver exactly such a
value. An unparseable pubDate now degrades to the same shape as an
absent one (posted "", date null); every other item survives. Three
new cases pin the malformed shapes, each failing on the unfixed code.
This commit is contained in:
Ayobami Adegoke
2026-09-02 21:34:53 +02:00
committed by GitHub
parent c42806674b
commit 0883958d43
3 changed files with 32 additions and 1 deletions
@@ -5,7 +5,13 @@ import { rssFetch, fetchWithUA, writeError, parseRssDescription, extractJobIdFro
export function normalizeSearchItem(item: RssItem): Record<string, unknown> {
const parsed = parseRssDescription(item.description)
const id = extractJobIdFromUrl(item.link)
const posted = item.pubDate ? new Date(item.pubDate).toISOString() : ""
// Guard the parse: new Date(<unparseable>) is an Invalid Date whose
// toISOString() throws RangeError, and this runs inside an unguarded
// items.map() - one bad feed item would kill the whole search as
// API_ERROR (#416). An unparseable pubDate degrades to the same shape
// as an absent one: posted "", date null.
const parsedDate = item.pubDate ? new Date(item.pubDate) : null
const posted = parsedDate && !Number.isNaN(parsedDate.getTime()) ? parsedDate.toISOString() : ""
return {
id,
title: item.title,
@@ -27,6 +27,21 @@ describe("Jobbank search normalization", () => {
expect(result.date).toBeNull();
});
// A present-but-unparseable pubDate must degrade to the same null-date shape
// as an absent one, never throw: toISOString() on an Invalid Date raises
// RangeError, and normalizeSearchItem runs inside an unguarded items.map(),
// so one bad feed item killed the whole search as API_ERROR (#416). The
// un-CDATA'd fallback capture in parseRssItems can deliver exactly such a
// value.
for (const bad of ["date unavailable", "2026-09-02T08:00:00+02:00x", "I går"]) {
test(`emits a null date instead of throwing on unparseable pubDate ${JSON.stringify(bad)}`, () => {
const result = normalizeSearchItem({ ...rssItem(), pubDate: bad });
expect(result.posted).toBe("");
expect(result.date).toBeNull();
});
}
test("keeps the native fields alongside the contract date (additive)", () => {
const result = normalizeSearchItem(rssItem());