diff --git a/.gitignore b/.gitignore index f961508..97db459 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules .env* *.log .DS_Store +tests/shots/ diff --git a/tests/live-check.mjs b/tests/live-check.mjs new file mode 100644 index 0000000..3942461 --- /dev/null +++ b/tests/live-check.mjs @@ -0,0 +1,49 @@ +#!/usr/bin/env node +// LIVE check against https://bidaangmamamayan.com (production, real crawl). +// Verifies: front page renders real stories, disclaimer present, board accepts +// a post THROUGH nginx (X-Forwarded-For -> rate limit), and a rate-limit 429 +// fires when posting 3x from the same IP. +import pw from "playwright"; + +const BASE = "https://bidaangmamamayan.com"; +const browser = await pw.chromium.launch(); +const page = await browser.newPage({ viewport: { width: 1280, height: 900 } }); +const errors = []; +page.on("pageerror", (e) => errors.push("pageerror: " + e.message)); +page.on("console", (m) => { if (m.type() === "error") errors.push("console: " + m.text()); }); + +await page.goto(BASE, { waitUntil: "domcontentloaded", timeout: 40000 }); +await page.waitForTimeout(3500); +const body = await page.textContent("body"); +const must = ["BIDA ANG MAMAMAYAN", "DISCLAIMER", "not affiliated with", "Thank You Board"]; +for (const s of must) if (!body.includes(s)) errors.push("missing: " + s); +const storyCards = await page.locator(".panel.lead, .story").count(); +console.log("story cards (lead+rows):", storyCards); +await page.screenshot({ path: "/root/projects/bidaangmamamayan/tests/shots/live-front.png" }); + +// desk count line +const deskLine = await page.locator(".count").allTextContents(); +console.log("count pills:", deskLine.slice(0, 6).join(" | ")); + +// board: post 3x from the (same) egress IP through nginx -> 3rd or 4th should 429 +await page.getByRole("link", { name: "Thank You Board" }).click(); +await page.waitForTimeout(1000); +let accepted = 0, rejected = 0; +for (let i = 0; i < 4; i++) { + await page.fill("#nick", "LiveCheck" + i); + await page.fill("#msg", `Live board check post number ${i + 1} — thank you Senator BAM.`); + await page.locator("button.go").click(); + await page.waitForTimeout(700); + const err = await page.locator(".err").textContent().catch(() => null); + const list = await page.locator(".postlist").textContent().catch(() => ""); + if (err && /slow down|plenty of thanks/i.test(err)) { rejected++; console.log("post " + (i + 1) + ": RATE-LIMITED (good)"); } + else if (list.includes("LiveCheck" + i)) { accepted++; console.log("post " + (i + 1) + ": accepted + rendered"); } + else { console.log("post " + (i + 1) + ": " + (err ? "rejected: " + err.slice(0, 50) : "unknown state")); } +} +console.log("accepted=" + accepted + " rejected=" + rejected); +if (rejected === 0) errors.push("expected at least one rate-limit 429 from the same egress IP"); +await page.screenshot({ path: "/root/projects/bidaangmamamayan/tests/shots/live-board.png" }); + +console.log(errors.length ? "LIVE ERRORS:\n" + errors.join("\n") : "LIVE CLEAN — no page errors, board rate-limit fires"); +await browser.close(); +process.exit(errors.length ? 1 : 0);