BidaAngMamayan: no-image lead hero watermark + Playwright UI suite
- .lead .hero.noimg: faint giant 'BAM' watermark so a photoless lead (most Bing-wire stories) never reads as a dead dark void. - tests/ui-check.mjs: headless Chromium suite (front, reader, board post + render, desk view, mobile) with a seeded scratch Mongo. - Fixed board rate-limit to compare BSON Date against Date (a numeric epoch matched nothing, so the counter stayed 0) — caught by tests/board-test.mjs. - Fixed /api/health double-await: getDb() is async, so 'await getDb().command(...)' called .command on the Promise. Caught by tests/e2e-run.mjs.
This commit is contained in:
parent
6b06e08c08
commit
49e5df5af0
@ -309,6 +309,29 @@ input, textarea { font-family: inherit; }
|
||||
inset: 0;
|
||||
background: linear-gradient(to top, rgba(12, 11, 9, 0.95) 12%, rgba(12, 11, 9, 0.25) 55%, transparent);
|
||||
}
|
||||
/* no-image lead: a faint giant "BAM" watermark so the hero never reads as a
|
||||
dead dark void (most Bing-wire stories carry no photo). */
|
||||
.lead .hero.noimg {
|
||||
background:
|
||||
radial-gradient(120% 140% at 78% 18%, rgba(255, 205, 36, 0.10), transparent 55%),
|
||||
repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.014) 0 2px, transparent 2px 26px),
|
||||
var(--bg-2);
|
||||
}
|
||||
.lead .hero.noimg .ghost {
|
||||
position: absolute;
|
||||
right: 4%;
|
||||
bottom: -6%;
|
||||
z-index: 0;
|
||||
font-family: var(--font-display);
|
||||
font-weight: 900;
|
||||
font-size: clamp(72px, 15vw, 190px);
|
||||
letter-spacing: 0.02em;
|
||||
color: rgba(255, 205, 36, 0.07);
|
||||
text-shadow: 0 0 40px rgba(255, 205, 36, 0.05);
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
line-height: 1;
|
||||
}
|
||||
.lead .hero .ph-tag {
|
||||
position: absolute;
|
||||
left: 12px; bottom: 12px;
|
||||
|
||||
@ -258,7 +258,8 @@ export default function Home() {
|
||||
)}
|
||||
{lead && (
|
||||
<article className="panel lead" onClick={() => openStory(lead)}>
|
||||
<div className="hero" style={lead.image ? { backgroundImage: `url(${imgSrc(lead.image)})` } : null}>
|
||||
<div className={`hero ${lead.image ? "" : "noimg"}`} style={lead.image ? { backgroundImage: `url(${imgSrc(lead.image)})` } : null}>
|
||||
{!lead.image && <span className="ghost">BAM</span>}
|
||||
<div className="ph-tag">
|
||||
{lead.named && <span className="tag named">★ NAMED BAM</span>}
|
||||
<span className="tag desk">{sectionName(lead.category)}</span>
|
||||
|
||||
BIN
tests/shots/01-front.png
Normal file
BIN
tests/shots/01-front.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 328 KiB |
BIN
tests/shots/02-reader.png
Normal file
BIN
tests/shots/02-reader.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
BIN
tests/shots/03-board-empty.png
Normal file
BIN
tests/shots/03-board-empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 175 KiB |
BIN
tests/shots/04-board-posted.png
Normal file
BIN
tests/shots/04-board-posted.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 177 KiB |
BIN
tests/shots/05-desk-education.png
Normal file
BIN
tests/shots/05-desk-education.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 178 KiB |
BIN
tests/shots/06-front-mobile.png
Normal file
BIN
tests/shots/06-front-mobile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
147
tests/ui-check.mjs
Normal file
147
tests/ui-check.mjs
Normal file
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env node
|
||||
// Playwright visual check for the BAM front page (headless Chromium).
|
||||
// Seeds the bama_ui scratch DB with realistic stories first, then:
|
||||
// - loads / (asserts no console/page errors, masthead present)
|
||||
// - screenshots the front page
|
||||
// - clicks a story card -> reader opens with body
|
||||
// - switches to the board view, posts a thank-you, asserts it renders
|
||||
// - switches to a desk view
|
||||
import pw from "playwright";
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
const BASE = process.env.BASE || "http://127.0.0.1:4005";
|
||||
const OUT = "/root/projects/bidaangmamamayan/tests/shots";
|
||||
import { mkdirSync } from "fs";
|
||||
mkdirSync(OUT, { recursive: true });
|
||||
|
||||
// ── seed (shape MUST match what lib/crawl.js stores, or the feed query
|
||||
// `discoveredAt >= now-14d` returns nothing) ───────────────────────────────
|
||||
const mc = new MongoClient("mongodb://127.0.0.1:27099/bama");
|
||||
await mc.connect();
|
||||
const db = mc.db("bama_ui");
|
||||
await db.collection("stories").deleteMany({});
|
||||
const now = Date.now();
|
||||
const H = 3600e3;
|
||||
const mk = (o) => ({
|
||||
url: o.url, title: o.title, summary: o.description, image: null,
|
||||
source: o.source, category: o.category, desk: "BAM Wire", feedKind: "query",
|
||||
named: !!o.named, fallback: false,
|
||||
published: new Date(o.published),
|
||||
discoveredAt: new Date(o.published + H), // discovered an hour after publish
|
||||
ingestedAt: new Date(o.published + H),
|
||||
});
|
||||
const rawSeed = [
|
||||
{
|
||||
url: "https://www.inquirer.net/bam/1", title: "Sen. Bam Aquino unveils college scholarship expansion for Pampanga students",
|
||||
description: "Senator Bam Aquino on Tuesday unveiled the expanded scholarship program that will fund 50,000 college students across the country, calling education 'the great equalizer'.",
|
||||
source: "Inquirer.net", published: now - 2 * H, named: true, category: "education",
|
||||
},
|
||||
{
|
||||
url: "https://www.pna.gov.ph/bam/2", title: "Aquino echoes House call to probe VisMin power outages, rates",
|
||||
description: "Senator Bam Aquino backed the congressional inquiry into rotational brownouts in the Visayas, urging regulators to audit system loss charges.",
|
||||
source: "Philippine News Agency", published: now - 5 * H, named: true, category: "energy",
|
||||
},
|
||||
{
|
||||
url: "https://rappler.com/bam/3", title: "Bam Aquino's esports bill clears Senate committee",
|
||||
description: "The bill that would recognize esports as a sport and fund university esports programs passed the committee, with Sen. Bam Aquino as prime sponsor.",
|
||||
source: "Rappler", published: now - 8 * H, named: true, category: "gaming",
|
||||
},
|
||||
{
|
||||
url: "https://www.pna.gov.ph/bam/4", title: "Aquino joins senators in okays of barangay, SK terms bill",
|
||||
description: "The Senate approved the bill setting five-year terms for barangay and SK officials on third reading.",
|
||||
source: "Philippine News Agency", published: now - 20 * H, named: false, category: "politics",
|
||||
},
|
||||
{
|
||||
url: "https://www.inquirer.net/bam/5", title: "Bam Aquino pushes student loan reform for higher education",
|
||||
description: "The Pampanga senator said the reform would cap interest rates on student loans and extend repayment windows for fresh graduates.",
|
||||
source: "Inquirer.net", published: now - 30 * H, named: true, category: "education",
|
||||
},
|
||||
{
|
||||
url: "https://www.inquirer.net/bam/6", title: "Senate okays 5-year barangay, SK terms; 2026 polls moved to 2028",
|
||||
description: "The upper house approved the measure on third reading.",
|
||||
source: "Inquirer.net", published: now - 40 * H, named: false, category: "politics",
|
||||
},
|
||||
{
|
||||
url: "https://rappler.com/bam/7", title: "Bam Aquino calls for fairer power rate adjustment mechanism",
|
||||
description: "The senator said consumers should not shoulder transmission losses.",
|
||||
source: "Rappler", published: now - 50 * H, named: true, category: "energy",
|
||||
},
|
||||
{
|
||||
url: "https://www.inquirer.net/bam/8", title: "Gaming: Bamboo Aquino's e-sports arena bill heads to plenary",
|
||||
description: "The measure will fund e-sports facilities in state colleges and universities nationwide.",
|
||||
source: "Inquirer.net", published: now - 60 * H, named: false, category: "gaming",
|
||||
},
|
||||
];
|
||||
const seed = rawSeed.map(mk);
|
||||
await db.collection("stories").insertMany(seed);
|
||||
await db.collection("board").deleteMany({});
|
||||
console.log("seeded", seed.length, "stories");
|
||||
|
||||
// ── browser ──────────────────────────────────────────────────────────────
|
||||
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: 30000 });
|
||||
await page.waitForTimeout(2500); // feed fetch + render
|
||||
|
||||
const masthead = await page.textContent("body");
|
||||
if (!/BIDA ANG MAMAMAYAN/.test(masthead || "")) errors.push("masthead missing");
|
||||
if (!/BAM/.test(masthead || "")) errors.push("BAM highlight missing");
|
||||
await page.screenshot({ path: OUT + "/01-front.png" });
|
||||
console.log("front page screenshot done");
|
||||
|
||||
// open the lead story
|
||||
const lead = page.locator(".panel.lead");
|
||||
if (await lead.count()) {
|
||||
await lead.click();
|
||||
await page.waitForTimeout(1500);
|
||||
await page.screenshot({ path: OUT + "/02-reader.png" });
|
||||
const readerText = await page.textContent("body");
|
||||
if (!/SCHOLARSHIP|scholarship|PAMPANGA|Pampanga/i.test(readerText || "")) errors.push("reader did not open lead story");
|
||||
await page.keyboard.press("Escape");
|
||||
await page.waitForTimeout(400);
|
||||
} else {
|
||||
errors.push("no lead story card");
|
||||
}
|
||||
|
||||
// board view — the nav tab (there's also a "SIGN THE BOARD" link on the front)
|
||||
await page.getByRole("link", { name: "Thank You Board" }).click();
|
||||
await page.waitForTimeout(800);
|
||||
await page.screenshot({ path: OUT + "/03-board-empty.png" });
|
||||
await page.fill("#nick", "PampangaGamer");
|
||||
await page.fill("#msg", "Thank you Senator BAM for the scholarship expansion — my whole batch is riding on it!");
|
||||
await page.locator("button.go").click();
|
||||
await page.waitForTimeout(1200);
|
||||
await page.screenshot({ path: OUT + "/04-board-posted.png" });
|
||||
const boardText = await page.textContent(".postlist");
|
||||
if (!/PampangaGamer/.test(boardText || "")) errors.push("posted nick not rendered");
|
||||
if (!/Thank you Senator BAM for the scholarship/.test(boardText || "")) errors.push("posted message not rendered");
|
||||
|
||||
// back to front, then a desk view — click the Education desk card (grid lives on front)
|
||||
await page.getByRole("link", { name: "Front", exact: true }).click();
|
||||
await page.waitForTimeout(400);
|
||||
const eduCard = page.locator(".deskcard", { hasText: /Education/ }).first();
|
||||
if (await eduCard.count()) {
|
||||
await eduCard.click();
|
||||
await page.waitForTimeout(600);
|
||||
await page.screenshot({ path: OUT + "/05-desk-education.png" });
|
||||
const deskBody = await page.textContent("main");
|
||||
if (!/scholarship|Scholarship|student|Student/i.test(deskBody || "")) errors.push("education desk view shows no education story");
|
||||
} else {
|
||||
errors.push("education desk card missing from grid");
|
||||
}
|
||||
|
||||
// desktop + mobile front
|
||||
await page.getByRole("link", { name: "Front", exact: true }).click();
|
||||
await page.waitForTimeout(500);
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.waitForTimeout(600);
|
||||
await page.screenshot({ path: OUT + "/06-front-mobile.png" });
|
||||
|
||||
console.log(errors.length ? "UI ERRORS:\n" + errors.join("\n") : "UI CLEAN — no console/page errors");
|
||||
await browser.close();
|
||||
await mc.close();
|
||||
process.exit(errors.length ? 1 : 0);
|
||||
Loading…
x
Reference in New Issue
Block a user