/** * Cycle 12 — submit a manual entry and verify the success screen * renders. Uses yesterday's date so the server's 30-day window * accepts it. */ import { chromium } from "playwright"; import { mkdirSync } from "node:fs"; const BASE = process.env.PLAYWRIGHT_URL ?? "http://localhost:4000"; const OUT = "tests/_artifacts/cycle12"; mkdirSync(OUT, { recursive: true }); const COOKIE_VALUE = [ "5a83c1a3-8eb5-44c4-bb66-323e72d38c91", "smoke-" + Math.random().toString(36).slice(2, 10), new Date(Date.now() + 12 * 3600 * 1000).toISOString(), "Worker 1", "time_admin", "en", "11111111-1111-1111-1111-111111111111", ].join("|"); async function main() { const browser = await chromium.launch({ headless: true }); const ctx = await browser.newContext({ viewport: { width: 412, height: 900 }, deviceScaleFactor: 2, }); await ctx.addCookies([ { name: "time_tracking_session", value: COOKIE_VALUE, url: BASE, httpOnly: false, secure: false, sameSite: "Lax", }, ]); const page = await ctx.newPage(); page.on("pageerror", (e) => console.error("PAGE ERROR:", e.message)); page.on("console", (m) => { if (m.type() === "error") console.error("CONSOLE ERR:", m.text()); }); await page.goto(`${BASE}/tuxedo/time-clock`, { waitUntil: "domcontentloaded" }); await page.waitForTimeout(2000); // Hub → Manual entry await page.locator('button:has-text("Manual entry")').first().click(); await page.waitForTimeout(800); // Fill form. Date defaults to today; use yesterday's date to make // sure we're definitely within the 30-day window and not in the // future. Use a real-looking shift: 07:00 → 15:30 (8h 30m, minus // 30m lunch = 8h). const yesterday = new Date(Date.now() - 86_400_000); const yyyy = yesterday.getFullYear(); const mm = String(yesterday.getMonth() + 1).padStart(2, "0"); const dd = String(yesterday.getDate()).padStart(2, "0"); const dateStr = `${yyyy}-${mm}-${dd}`; await page.locator('input[type="date"]').first().fill(dateStr); await page.locator('input[placeholder*="Harvesting"]').first().fill("Harvesting"); await page .locator('input[placeholder*="Required"]') .first() .fill("Forgot to clock in this morning"); await page.screenshot({ path: `${OUT}/05_manual_before_submit.png` }); await page.locator('button:has-text("Submit entry")').click(); // Wait for either success or error await page.waitForTimeout(3000); await page.screenshot({ path: `${OUT}/06_after_submit.png` }); const text = await page.locator("body").innerText(); if (/Entry submitted|Entrada enviada/i.test(text)) { console.log("✓ Success screen rendered"); } else if (/16 hours|30 days|3 characters|cannot be in the future|Must be after|Reason/i.test(text)) { console.error("✗ Validation error visible:"); console.error(text.slice(0, 1500)); process.exit(1); } else { console.error("? Unknown state after submit:"); console.error(text.slice(0, 1500)); process.exit(1); } // Take a clean success shot by scrolling to top await page.evaluate(() => window.scrollTo(0, 0)); await page.waitForTimeout(300); await page.screenshot({ path: `${OUT}/07_success.png` }); await browser.close(); } main().catch((e) => { console.error(e); process.exit(1); });