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
63 lines
2.3 KiB
JavaScript
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}/`);
|