qa(idle-poll): assert zero background reqs in a 55s idle window
Previous audit allowed up to 5 requests in a 30s window — generous, hid real regressions. Tighten: - 5s settle after each scene becomes interactive (covers the burst of mount-time fetches every scene legitimately fires) - 55s observation window after settle, sized to fit between two consecutive 60s topbar badge polls - MAX_REQ_PER_WINDOW = 0; any /api/* or /internal/* request during the window fails the assertion This is the operator-experience contract: when you stop typing, canvas stops fetching.
This commit is contained in:
+19
-10
@@ -1,8 +1,16 @@
|
||||
// Idle-poll audit. User explicitly complained "way too many GETs / non-stop".
|
||||
// For each scene: visit, settle, then watch network for 30s with no user input.
|
||||
// Pass if total requests in that 30s window is reasonable (<= 5).
|
||||
// The topbar identity-hydration + chat/queue badge polls at 60s, so a 30s
|
||||
// window should see at most 1 such fire.
|
||||
// For each scene: visit, settle for a generous burst window, then watch network
|
||||
// for 60s with no user input. Strict assertion: zero background /api/* or
|
||||
// /internal/* requests during that window.
|
||||
//
|
||||
// What counts as "background":
|
||||
// - Anything fired more than SETTLE_MS after the scene becomes interactive
|
||||
// - Excludes the 60s topbar badge poll fired exactly at minute boundaries —
|
||||
// the window is sized to fit BETWEEN two such fires
|
||||
//
|
||||
// The topbar badge poll runs every 60s. A 55s observation window after a
|
||||
// 5s settle covers a full minute of operator inactivity without spanning
|
||||
// the next poll boundary, so the strict assertion "zero" is correct.
|
||||
import { chromium } from "playwright";
|
||||
|
||||
const URL = "https://canvas.flow-master.ai/";
|
||||
@@ -19,8 +27,9 @@ const SCENES = [
|
||||
{ chip: /What is FlowMaster/, label: "explainer" },
|
||||
];
|
||||
|
||||
const IDLE_WINDOW_MS = 30_000;
|
||||
const MAX_REQ_PER_WINDOW = 5;
|
||||
const SETTLE_MS = 5_000;
|
||||
const IDLE_WINDOW_MS = 55_000;
|
||||
const MAX_REQ_PER_WINDOW = 0;
|
||||
|
||||
const results = [];
|
||||
function record(name, ok, detail = "") {
|
||||
@@ -49,7 +58,7 @@ for (const s of SCENES) {
|
||||
|
||||
// Settle period — the scene's initial fetch burst should complete here.
|
||||
await p.waitForLoadState("networkidle").catch(() => {});
|
||||
await p.waitForTimeout(1500);
|
||||
await p.waitForTimeout(SETTLE_MS);
|
||||
|
||||
// Now record every request fired for the next IDLE_WINDOW_MS.
|
||||
const requests = [];
|
||||
@@ -65,9 +74,9 @@ for (const s of SCENES) {
|
||||
|
||||
const ok = requests.length <= MAX_REQ_PER_WINDOW;
|
||||
const summary = requests.length
|
||||
? `${requests.length} reqs · ${requests.slice(0, 3).map((r) => `${r.method} ${r.url.slice(0, 50)}`).join(", ")}${requests.length > 3 ? "…" : ""}`
|
||||
: "0 reqs · quiet";
|
||||
record(`idle_${s.label}_quiet_at_30s`, ok, summary);
|
||||
? `${requests.length} background reqs in ${IDLE_WINDOW_MS / 1000}s · ${requests.slice(0, 3).map((r) => `${r.method} ${r.url.slice(0, 50)}`).join(", ")}${requests.length > 3 ? "…" : ""}`
|
||||
: `0 background reqs in ${IDLE_WINDOW_MS / 1000}s`;
|
||||
record(`idle_${s.label}_zero_background_traffic`, ok, summary);
|
||||
}
|
||||
|
||||
await b.close();
|
||||
|
||||
Reference in New Issue
Block a user