Lines 64-104javascript
64// {ok:false} and the run CONTINUES (best-effort QA) — EXCEPT a `goto`
65// that throws is FATAL: remaining steps are marked skipped.
66// - assertText passes if the text is visible anywhere on the page; on miss
67// the step is {ok:false} but the run continues.
68// - text extracts a selector's textContent into the step result.
69// - screenshot writes <out-dir>/<basename>.png (full page).
71// Final stdout: one JSON object
72// { ok, baseUrl, steps:[{index,action,ok,ms,text?,screenshot?,error?}],
73// consoleErrors:[...], screenshots:[paths] }
74// Exit 0 even when steps failed (the agent reads the JSON to judge). Exit
75// non-zero only on a FATAL harness error (bad flow file, launch failure).
77// Dependency-free apart from playwright.
79import { readFileSync, mkdirSync } from 'node:fs';
80import { resolve, join } from 'node:path';
81import { createRequire } from 'node:module';
83// This file is ESM (.mjs); playwright is a CJS package. createRequire gives us
84// a `require` that resolves an absolute package-dir path (see loadPlaywright).
85const require = createRequire(import.meta.url);
86
MediumDynamic Require
Package source references dynamic require/import behavior.
skills/browser-qa/scripts/agent-browser.mjsView on unpkg · L84 87const WAIT_TIMEOUT = 10_000; // sane default for waitFor / assertText probes
88// When recording, hold the page open briefly after the last step before closing
89// the context (which flushes the .webm). A bare goto→waitFor→text flow finishes
90// in ~250 ms — too short for Playwright's video to capture a *painted* frame, so
91// the clip can come out blank (the /demo before/after's "before" panel did).
92// Settling lets late paints + async data ("Loading…") resolve and guarantees a
93// watchable tail. Override with --record-settle-ms / LASTLIGHT_RECORD_SETTLE_MS.
94const RECORD_SETTLE_MS = Number(process.env.LASTLIGHT_RECORD_SETTLE_MS) || 1500;
96// ── Demo-mode pacing ─────────────────────────────────────────────────────────
97// Headless Chromium paints NO cursor and fires actions instantly, so a raw
98// recording looks like the UI mutating on its own. "Demo mode" (auto-on whenever
99// the session is recorded — see run()) makes the capture human-watchable: a
100// synthetic cursor overlay that animates to each target, char-by-char typing,
101// and a deliberate pause between steps. These are no-ops outside demo mode, so
102// screenshot QA runs are untouched. All tunable via flags / env.
103const DEMO_STEP_DELAY_MS = Number(process.env.LASTLIGHT_STEP_DELAY_MS) || 700;
104const DEMO_TYPE_DELAY_MS = Number(process.env.LASTLIGHT_TYPE_DELAY_MS) || 70;