The comment stripper had a real hole: the line-comment regex was anchored, so it
only removed `//` at the start of a line and a call disabled after code —
`const disabled = true; // configure({ asyncUtilTimeout: 1000 });` — survived it
and the guard passed with no effective configuration. Replaced with a scanner,
because a regex gets this wrong in both directions: it has to strip a comment
that follows code, and it must NOT treat the `//` inside a string literal as one,
which would silently truncate any line holding a URL. Quote tracking (with
escapes) is the only way to have both. Three regression tests.
Two documentation claims were also wrong. The guard header and quality-gate.md
cited #2278 and #2250 as instances of a budget nobody chose; they were not —
#2278 was a missing condition wait around a geometry read and #2250 a real race
in a test's own timing, both fixed by making the test wait for the right thing.
Presenting a race fix as evidence for a larger ceiling argues against #1596,
which this guard exists to uphold. Only the budget and poll-ceiling cases are
cited now, and both files say explicitly why those two are excluded.
And browser-timeouts.mjs overstated its own behavior twice: `bestEffort` can
spend its full budget on an otherwise passing smoke precisely because its expiry
is caught, and raising any budget does delay the report when the thing waited on
never arrives. The diagnostics improve the eventual message; they do not make
the wait shorter. Both now stated plainly, so the header is something to weigh a
change against rather than a reassurance.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PsmUAZ6aLUAFqenjJKSSRp
Signed-off-by: cliffhall <cliff@futurescale.com>
57 lines
2.7 KiB
JavaScript
57 lines
2.7 KiB
JavaScript
/**
|
|
* Playwright wall-clock budgets for the web smokes (#2323).
|
|
*
|
|
* Before this, `smoke-web-tabs.mjs`, `smoke-web-elicitation.mjs` and
|
|
* `smoke-web-browser.mjs` carried 19 budgets between them across three
|
|
* independently-chosen scales, with no config anywhere to raise — 17 locator
|
|
* operations plus a `page.goto` and a `waitForLoadState`. They are the
|
|
* same three or four decisions repeated, so they are named once here and the
|
|
* scripts import them — the same shape `render-smoke.mjs`'s `DEFAULTS` already
|
|
* has, and for the same reason: a budget nobody can find is a budget nobody
|
|
* revisits.
|
|
*
|
|
* Three of the four are ceilings on a poll rather than sleeps — `ui`,
|
|
* `roundTrip` and `nested` each return the instant their locator condition
|
|
* holds, so a passing smoke pays only the time the app actually took. What they
|
|
* absorb is a smoke running against a cold `dist/` build on a machine already
|
|
* carrying other agent sessions' gates.
|
|
*
|
|
* ⚠️ `bestEffort` is the exception and is not free: its expiry is caught and
|
|
* ignored, so a smoke that never reaches network idle spends the full budget on
|
|
* an otherwise **passing** run. That is why it is the smallest of the four, and
|
|
* why it should stay that way.
|
|
*
|
|
* ⚠️ Raising any of these does delay the report when the thing waited on never
|
|
* arrives — a larger budget is a longer wait before the failure. What the
|
|
* launcher-death race in `smoke-web-browser.mjs` and the `waitForStage`
|
|
* diagnostics in the other two buy is a better *eventual* message, naming a
|
|
* cause instead of a locator; they do not make the wait shorter. Weigh both
|
|
* when changing a value here.
|
|
*/
|
|
|
|
export const BROWSER_TIMEOUTS = Object.freeze({
|
|
/**
|
|
* Load the page, or act on a control the app is already showing — a click on
|
|
* a rendered tab or list row, a wait for the first meaningful frame. What it
|
|
* absorbs is the browser's own scheduling under load, not a server.
|
|
*/
|
|
ui: 30_000,
|
|
/**
|
|
* Wait for something that only appears after a round trip to an MCP server:
|
|
* an elicitation modal, a tool result panel. Longer than `ui` because a test
|
|
* server has to boot, negotiate and answer before the DOM can change.
|
|
*/
|
|
roundTrip: 45_000,
|
|
/**
|
|
* Wait on a sub-element of something already on screen — a row inside a
|
|
* populated panel, a section of an open accordion. The enclosing wait has
|
|
* already paid for the round trip, so this only covers the render.
|
|
*/
|
|
nested: 15_000,
|
|
/**
|
|
* A wait whose expiry is caught and ignored, so it must stay short: it is
|
|
* pure added latency on every passing run. `networkidle` is the only one —
|
|
* the Google Fonts request may never idle on a restricted network.
|
|
*/
|
|
bestEffort: 5_000,
|
|
});
|