From c659ff0fd03e9aa12853dab5f353200d4aceb136 Mon Sep 17 00:00:00 2001 From: Zachary Lowden Date: Thu, 11 Jun 2026 15:14:11 -0500 Subject: [PATCH] test(preview): raise heavy-SSR/whatIf timeouts so slow windows flake not fail (#2480) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a contended preview node the single-replica pod gets CPU-throttled and the heaviest flows intermittently crossed their timeout ceilings and HARD-failed (both attempts), instead of flaking-and-recovering on retry: - /user/membership, /models SSR goto: observed ~66s, just past the 60s test + nav timeout. - generation whatIf waitForResponse: pushed past 25s (page+hydrate+form+resource +orchestrator chain) under load. Raise per-test + navigationTimeout 60s -> 90s, and the whatIf waitForResponse 25s -> 45s. These are margins for slow windows, not masks for real breaks: the orchestrator is ~57ms and /generate SSR ~0.4s when healthy, so a healthy run never approaches these. Removes the hard-fail mode that made the report-only smoke comment show ❌ on clean PRs — a prerequisite for ever flipping smoke to gating. Co-authored-by: Claude Opus 4.8 (1M context) --- playwright.preview.config.ts | 12 ++++++++---- tests/preview-generation.spec.ts | 7 ++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/playwright.preview.config.ts b/playwright.preview.config.ts index 780e15ff0a..f577d563a2 100644 --- a/playwright.preview.config.ts +++ b/playwright.preview.config.ts @@ -37,16 +37,20 @@ export default defineConfig({ // and opens DB pools. The default 30s per-test timeout is too tight for that cold // first hit, so raise both the per-test and navigation timeouts. The setup project // also fires a warm-up request before the suite (preview-auth.setup.ts). - timeout: 60_000, + // 90s (was 60s): on a contended preview node the single-replica pod gets CPU- + // throttled and the heaviest SSR pages (/user/membership, /models) intermittently + // crossed the 60s ceiling (observed ~66s) — a slow window should flake-and-recover + // on retry, not hard-fail. 90s gives comfortable margin without masking a real hang. + timeout: 90_000, reporter: [['list'], ['html', { open: 'never', outputFolder: 'playwright-report' }]], use: { baseURL: PREVIEW_URL, trace: 'on-first-retry', screenshot: 'only-on-failure', // Align with the per-test timeout: a cold heavy-page (/models) goto can need - // most of the budget, and a 45s nav cap would fail it even though the test has - // 60s. The setup project also pre-warms /models + /images authenticated. - navigationTimeout: 60_000, + // most of the budget, and a tighter nav cap would fail it even though the test + // has 90s. The setup project also pre-warms /models + /images authenticated. + navigationTimeout: 90_000, }, projects: [ { name: 'preview-setup', testMatch: /(^|\/)preview-auth\.setup\.ts$/ }, diff --git a/tests/preview-generation.spec.ts b/tests/preview-generation.spec.ts index 8fa07fab21..d8ed77a6b4 100644 --- a/tests/preview-generation.spec.ts +++ b/tests/preview-generation.spec.ts @@ -46,9 +46,14 @@ test.describe('generation cost quote (gold)', () => { // 1. Primary, network-based: whatIf fires on /generate load and quotes a cost. test('whatIfFromGraph fires on /generate and returns a numeric cost', async ({ page }) => { // Arm the response listener BEFORE navigating so an on-load fire isn't missed. + // 45s (was 25s): whatIf is the heaviest client-side flow — page load + hydrate + + // form init + resource resolve + orchestrator round-trip must all complete before + // it fires. On a CPU-throttled preview pod a slow window pushed this past 25s and + // it hard-failed (both attempts). 45s lets a slow window flake-and-recover; the + // orchestrator itself is fast (~57ms), so this never approaches 45s when healthy. const whatIfResponse = page.waitForResponse( (r) => r.url().includes(WHATIF_URL) && r.status() === 200, - { timeout: 25_000 } + { timeout: 45_000 } ); const resp = await page.goto('/generate', { waitUntil: 'domcontentloaded' });