Forked from Forthena (PERSONAL/forthena) and retargeted: - NO login, NO LLM: the edition is public and the ranking is deterministic (stories that name Sen. BAM lead; freshest first) — Daniel: no like/dislike or store profile for visitors. - Crawler scoped to BAM: Bing news keyword queries + Inquirer/Rappler fallback wires, with a two-tier relevance gate (named-BAM always; Aquino+legislative-context only from fallback) so op-eds and non-Bam senators are dropped. - Desks: BAM (lead), Gaming, Education, Politics, Energy, PH, Business. - Community board /board: 'Thank you Senator BAM' — nickname-only posts, HTML-stripped, URL-only rejected, IP rate-limited (3/10min, 20/day). - Yellow-gamer theme (Orbitron/Rajdhani/JetBrains Mono, dark + gold, HUD corners), supporter disclaimer in header and footer. - Tests: category/date/relevance/text suites + Mongo board suite + full HTTP e2e (all passing). Infra: 66.181.46.132 (bidaangmamamayan.com), local Mongo 7.0, nginx + certbot TLS, PM2 bama (:3000) + 15-min crawl cron.
31 lines
1.9 KiB
JavaScript
31 lines
1.9 KiB
JavaScript
// Tests the crawler's headline-date scanner (extracted from module source so we
|
|
// don't widen the module's public surface just for tests).
|
|
import { readFileSync } from "fs";
|
|
|
|
const src = readFileSync(new URL("../lib/crawl.js", import.meta.url), "utf8");
|
|
const monthsLine = /const MONTHS = .*;\n/.exec(src);
|
|
const fnBlock = /function headlineDateAge[\s\S]*?\n\}\n/.exec(src);
|
|
if (!monthsLine || !fnBlock) { console.log("FAIL could not locate headlineDateAge in source"); process.exit(1); }
|
|
const fn = new Function(monthsLine[0] + fnBlock[0] + "; return headlineDateAge;")();
|
|
|
|
const now = new Date("2026-08-30T12:00:00Z").getTime();
|
|
let fails = 0;
|
|
const ok = (c, msg) => { if (!c) { fails++; console.log(" FAIL " + msg); } else console.log(" ok " + msg); };
|
|
|
|
console.log("headlineDateAge:");
|
|
const march = fn("Peso weakens to 59.735 on March 13, 2026", now);
|
|
ok(march !== null && march > 160, `"March 13, 2026" is ~5 months old (got ${march?.toFixed(0)}d)`);
|
|
const yest = fn("On Aug 29, the monetary board decided", now);
|
|
ok(yest !== null && yest >= 0 && yest < 2, `"Aug 29" reads as ~1 day (got ${yest?.toFixed(1)}d)`);
|
|
const july = fn("Inflation quickens in July 2026", now);
|
|
ok(july !== null && july > 25 && july < 90, `"July 2026" is a month+ old (got ${july?.toFixed(0)}d)`);
|
|
ok(fn("Diesel prices climb for third straight week", now) === null, "no month-date in text -> null (pubDate governs)");
|
|
ok(fn("2025 inflation sinks to nine-year low", now) === null, "bare year (no month) -> null, conservative");
|
|
const dayfirst = fn("recorded 13 March 2026 by the BSP", now);
|
|
ok(dayfirst !== null && dayfirst > 160, `"13 March 2026" day-first form also caught (got ${dayfirst?.toFixed(0)}d)`);
|
|
const future = fn("Summit begins September 15, 2026", now);
|
|
ok(future === null, "a date in the future is ignored, not treated as ancient");
|
|
|
|
console.log(fails ? `\n${fails} FAILED` : "\nall passed");
|
|
process.exit(fails ? 1 : 0);
|