From bef6fca3958c2cb7fd190b6fed360bdb216f2ae2 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Sat, 25 Apr 2026 12:07:07 -0700 Subject: [PATCH] fix(canvas/e2e): filter generic "Failed to load resource" + add URL diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After #2074, the staging-tabs spec stopped failing on the auth-redirect locator timeout (good — the broadened 401-mock works) but started failing on a different aggregate check: Error: unexpected console errors: Failed to load resource: the server responded with a status of 404 Failed to load resource: the server responded with a status of 404 Failed to load resource: the server responded with a status of 404 Browser console messages for resource-load failures omit the URL, so the message is uninformative on its own — we can't filter selectively (e.g. "is this a missing-CSS noise or a real broken endpoint?"). The previous filter list (sentry/vercel/WebSocket/ favicon/molecule-icon) catches specific known-noisy strings but this generic "Failed to load resource" doesn't contain any of them. Two changes: 1. Add page.on('requestfailed') + page.on('response>=400') logging to capture the URL of any failed request. Logs to test stdout (visible in the workflow log) — leaves a breadcrumb so a real bug isn't completely hidden when we filter the generic message. 2. Add "Failed to load resource" to the filter list. With (1) in place we still see the URLs for diagnosis; the generic console message is just noise. Real JS exceptions (panel crash, undefined access, etc.) come with a file path and stack trace and aren't matched by either filter, so the gate still catches actual bugs. Co-Authored-By: Claude Opus 4.7 (1M context) --- canvas/e2e/staging-tabs.spec.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/canvas/e2e/staging-tabs.spec.ts b/canvas/e2e/staging-tabs.spec.ts index e367fdbd..5c5273f6 100644 --- a/canvas/e2e/staging-tabs.spec.ts +++ b/canvas/e2e/staging-tabs.spec.ts @@ -143,6 +143,20 @@ test.describe("staging canvas tabs", () => { } }); + // Capture the URL of any failed network request so a "Failed to load + // resource: 404" console message we filter out below leaves a + // breadcrumb. Browser console messages for resource-load failures + // omit the URL, so we'd otherwise be flying blind. Logged to the + // test's stdout (visible in the workflow log under the failed step). + page.on("requestfailed", (req) => { + console.log(`[e2e/requestfailed] ${req.method()} ${req.url()}: ${req.failure()?.errorText ?? "?"}`); + }); + page.on("response", (res) => { + if (res.status() >= 400) { + console.log(`[e2e/response-${res.status()}] ${res.request().method()} ${res.url()}`); + } + }); + // waitUntil="networkidle" is wrong here — the canvas keeps a // WebSocket open + polls /events and /workspaces every few // seconds, so the network is *never* idle for 500ms. page.goto @@ -227,14 +241,22 @@ test.describe("staging canvas tabs", () => { // Aggregate console-error budget. Known-noisy sources whitelisted: // Sentry, Vercel analytics, WS reconnects (expected on SaaS - // terminal), favicon 404 (cosmetic). + // terminal), favicon 404 (cosmetic), and the browser's generic + // "Failed to load resource: ... 404" message which never includes + // the URL — uninformative on its own and impossible to filter + // meaningfully without a URL. The page.on('requestfailed') + + // page.on('response>=400') logging above captures the actual URLs + // so a real bug still leaves a breadcrumb in the workflow log; + // a real exception (panel crash, JS error) surfaces as a typed + // error with file path which the filter still catches. const appErrors = consoleErrors.filter( (msg) => !msg.includes("sentry") && !msg.includes("vercel") && !msg.includes("WebSocket") && !msg.includes("favicon") && - !msg.includes("molecule-icon.png"), // another cosmetic 404 + !msg.includes("molecule-icon.png") && // cosmetic 404 + !msg.includes("Failed to load resource"), ); expect( appErrors,