bidaangmamamayan/tests/category-test.mjs
Ryan 6b06e08c08 BidaAngMamayan: public supporter tribute news desk for Senator BAM Aquino
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.
2026-09-15 08:37:03 +00:00

41 lines
1.9 KiB
JavaScript

// Desk registry — the 7-desk tribute era.
// Verifies lib/categories.js: unique keys, labels, normalize fallback to "bam",
// and the classifier's ordering (gaming/education/energy before politics/ph).
import { CATEGORIES, CATEGORY_KEYS, normalizeCategory, sectionName, classifyStory } from "../lib/categories.js";
let fails = 0;
const check = (name, cond, detail = "") => {
console.log(` ${cond ? "ok " : "FAIL"} ${name}${detail ? " — " + detail : ""}`);
if (!cond) fails++;
};
console.log("registry:");
check("7 desks", CATEGORIES.length === 7, `got ${CATEGORIES.length}`);
check("unique keys", new Set(CATEGORIES.map((c) => c.key)).size === CATEGORIES.length);
check("keys valid", [...CATEGORY_KEYS].every((k) => /^[a-z-]+$/.test(k)));
check("every desk has a label", CATEGORIES.every((c) => typeof c.label === "string" && c.label.length > 2));
console.log("normalize:");
check("bam stays bam", normalizeCategory("bam") === "bam");
check("education stays", normalizeCategory("education") === "education");
check("junk falls to bam", normalizeCategory("nonsense") === "bam");
check("null falls to bam", normalizeCategory(null) === "bam");
check("sectionName of junk is the lead desk", sectionName("??") === "BAM Front");
console.log("classify (order matters):");
const fixtures = [
["Sen. Bam Aquino, esports runner-up, opens gaming center", "gaming"],
["Bam Aquino pushes scholarship bill for college students", "education"],
["Senator backs VAT removal on power system losses", "energy"],
["Senate committee approves barangay terms bill", "politics"],
["Pampanga floods hit three towns", "ph"],
["Aquino joins senate floor vote on trade", "politics"],
["A story with no keywords at all", "bam"],
];
for (const [text, want] of fixtures) {
check(`"${text.slice(0, 44)}..." -> ${want}`, classifyStory({ title: text }) === want, `got ${classifyStory({ title: text })}`);
}
console.log(fails ? `\n${fails} FAILED` : "\nall passed");
process.exit(fails ? 1 : 0);