WFDASH-WEBAPP/scripts/smoke/screenshot-pages.mjs
SJCoetz 7f924ccc45 refactor: switch hardcoded UI colors to semantic theme tokens
Overhaul the app's color system by replacing all hardcoded Tailwind color classes with semantic theme variables to ensure consistent theming across all components, pages, and tests.

Additional changes:
- Add assigned date support for order item status updates: add `assignedDate` field to the order item status PATCH API, implement server-side normalization/validation, and add corresponding tests
- Refactor purchase order PDF workflows to use the consolidated `purchase_orders.documents` field instead of the legacy separate `purchase_order_pdfs` collection
- Fix quote number parsing and formatting to support both dashed (Q-YYYY-MM-NNN) and dashless (QYYYYMMNNN) formats
- Rename `driver_pool` item status to `collection_pool` across the codebase
- Add null handling for order item quantities and pricing to display "—" for missing values
- Improve filter tab styling: make mobile tabs scrollable, prevent text wrapping, hide scrollbar
- Add new utility scripts, API routes, migrations, and polish small UI/UX fixes including tsconfig updates and theme hook improvements
2026-07-07 17:22:03 +02:00

63 lines
2.3 KiB
JavaScript

import { chromium } from "playwright";
import { mkdirSync } from "node:fs";
const OUT = "/tmp/wfdash-shots";
mkdirSync(OUT, { recursive: true });
const BASE = "http://localhost:4000";
const TOKEN = "123456";
const pages = [
{ path: "/companies", name: "companies-list" },
{ path: "/customers", name: "customers-list" },
{ path: "/quotes", name: "quotes-list" },
{ path: "/quotes/approvals", name: "quotes-approvals" },
{ path: "/quotes/archived", name: "quotes-archived" },
{ path: "/dashboard", name: "dashboard" },
];
const browser = await chromium.launch();
const ctx = await browser.newContext({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1,
});
// set dev identity cookie + agent auth cookie-ish
await ctx.addCookies([
{ name: "wfdash_dev_email", value: "david.els1%40outlook.com", domain: "localhost", path: "/" },
]);
const page = await ctx.newPage();
const errors = [];
page.on("console", (m) => {
if (m.type() === "error") errors.push(`[${page.url()}] console.error: ${m.text()}`);
});
page.on("pageerror", (e) => errors.push(`[${page.url()}] pageerror: ${e.message}`));
for (const p of pages) {
const url = BASE + p.path;
console.log(`\n→ ${p.path}`);
try {
const resp = await page.goto(url, { waitUntil: "domcontentloaded", timeout: 20000 });
console.log(` status: ${resp?.status}`);
await page.waitForTimeout(2500);
await page.screenshot({ path: `${OUT}/${p.name}.png`, fullPage: false });
// capture the H1 / title text
const h1 = await page.locator("h1").first().textContent().catch(() => null);
console.log(` h1: ${JSON.stringify(h1)}`);
// count rows in the main table if any
const rowCount = await page.locator("table tbody tr").count().catch(() => 0);
console.log(` table rows: ${rowCount}`);
// capture any visible error banners
const errBanner = await page.locator('[role="alert"], .text-red-600, .text-destructive').first().textContent().catch(() => null);
if (errBanner) console.log(` ⚠ banner: ${errBanner.trim().slice(0, 200)}`);
} catch (e) {
console.log(` ✗ failed: ${e.message}`);
await page.screenshot({ path: `${OUT}/${p.name}-error.png` }).catch(() => {});
}
}
await browser.close();
console.log(`\n--- console/page errors (${errors.length}) ---`);
for (const e of errors.slice(0, 30)) console.log(e);
console.log(`\nScreenshots written to ${OUT}/`);