From fd123da6a318d41b40ba3b9134cf9bb4ab2f904a Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Sun, 7 Jun 2026 23:56:32 -0700 Subject: [PATCH] test(e2e): harden harness for deployed runs (retries, serialize, banner) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test-infra only (e2e/ is not in the deployed artifact). Refines the v0.52.0 deployed-env harness: - retries:2 + on-first-retry trace now meaningful (was dead: retries defaulted to 0); de-risks timing flakes over the public edge. - workers:1 — the metadata specs run in order and write real commits; parallel workers would race on shared state and concurrent bot pushes. - deployed timeouts bumped (60s/20s) when E2E_TEST_AUTH_SECRET is set. - dismissCookies forcibly removes any lingering consent-banner node so it can't intercept catalog-footer checkbox clicks (the recurring flake). Co-Authored-By: Claude Opus 4.8 (1M context) --- e2e/lib/ui.js | 10 +++++++++- e2e/playwright.config.js | 18 ++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/e2e/lib/ui.js b/e2e/lib/ui.js index 81c2659..42bdf89 100644 --- a/e2e/lib/ui.js +++ b/e2e/lib/ui.js @@ -4,7 +4,15 @@ export async function dismissCookies(page) { const banner = page.locator('.cookie-consent-banner') if (await banner.count()) { + // Click to persist the consent choice so it doesn't reappear on + // later navigation... await page.getByRole('button', { name: 'Save choice' }).click().catch(() => {}) - await banner.waitFor({ state: 'hidden' }).catch(() => {}) + await banner.waitFor({ state: 'hidden', timeout: 5000 }).catch(() => {}) + // ...then forcibly remove any node still in the DOM. The dismiss + // click occasionally doesn't land before a test clicks a catalog + // footer checkbox (flaky over the deployed edge), and a lingering + // fixed banner intercepts those pointer events. Removing the node + // makes the dismissal deterministic. + await banner.evaluate((el) => el.remove()).catch(() => {}) } } diff --git a/e2e/playwright.config.js b/e2e/playwright.config.js index fb5024a..db83667 100644 --- a/e2e/playwright.config.js +++ b/e2e/playwright.config.js @@ -1,9 +1,23 @@ import { defineConfig } from '@playwright/test' +// The metadata specs sign in, navigate, and (SLICE-4/5) write real commits, +// so a handful of steps are timing-sensitive: the cookie-consent banner's +// dismiss animation, first-render of the detail panel, and the round trip +// after a write. These flake intermittently on a busy local box and more so +// against a deployed host (network latency). `retries` makes the suite robust +// to that (and finally makes `trace: 'on-first-retry'` meaningful); the +// timeouts are bumped a notch for deployed runs over the public edge. +const DEPLOYED = !!process.env.E2E_TEST_AUTH_SECRET + export default defineConfig({ testDir: '.', - timeout: 30_000, - expect: { timeout: 10_000 }, + timeout: DEPLOYED ? 60_000 : 45_000, + expect: { timeout: DEPLOYED ? 20_000 : 12_000 }, + retries: 2, + // The metadata specs run in order against one seeded collection and write + // real commits (SLICE-4/5); parallel workers would race on shared state — + // and on a deployed host, on concurrent git pushes through the bot. Serialize. + workers: 1, use: { baseURL: process.env.BASE_URL || 'http://localhost:8080', trace: 'on-first-retry',