From 6c0fba8cc15b600b1a07e1ad70e95700dacde502 Mon Sep 17 00:00:00 2001 From: cynarAI <155274210+cynarAI@users.noreply.github.com> Date: Fri, 9 Oct 2026 10:56:32 +0200 Subject: [PATCH] E2E: longer waits for slow fixture renders, shorter Playwright artifact retention (#174) * fix(mobile): align Expo SDK 57 patch deps for install --check Bump @expo/ui, expo, expo-constants, expo-linking, expo-modules-core, expo-notifications, expo-router, and expo-updates to the versions expo install --check expects after upstream patch releases. Co-authored-by: cynarAI * ci(e2e): harden flaky waits and trim Playwright artifact uploads Chart fixture reloads and shell readiness can exceed 30s on loaded self-hosted runners. Align timeouts with the rest of the suite and wait for gallery mount before counting species. Stop uploading per-test trace folders to Actions (HTML report only) with 1-day retention so quota errors stay non-blocking. Co-authored-by: cynarAI * evo-deploy: probe health before checking the timeout With a short timeout the clock could tick past it before the first probe, so a healthy service was reported as timed out. Probe first, then check the clock. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs --------- Co-authored-by: Cursor Agent Co-authored-by: cynarAI Co-authored-by: Claude --- .github/workflows/playwright.yml | 5 ++--- apps/web/e2e/chart-links.spec.ts | 8 ++++---- apps/web/e2e/helpers.ts | 2 +- apps/web/e2e/oo-avatar.spec.ts | 4 ++++ ops/evo-deploy/deploy.sh | 11 ++++++----- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 25756e7..7ea5a74 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -165,15 +165,14 @@ jobs: - name: Upload Playwright artifacts if: always() && inputs.upload_artifacts continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: playwright-artifacts-${{ github.run_id }}-${{ github.run_attempt }} path: | playwright-report playwright-report-www - apps/web/test-results test-report/e2e - retention-days: 7 + retention-days: 1 if-no-files-found: warn - name: Publish Playwright visual report if: always() && inputs.publish_report diff --git a/apps/web/e2e/chart-links.spec.ts b/apps/web/e2e/chart-links.spec.ts index d67b26d..4813a0e 100644 --- a/apps/web/e2e/chart-links.spec.ts +++ b/apps/web/e2e/chart-links.spec.ts @@ -21,7 +21,7 @@ test.describe await page.goto(`${fixture}?${new URLSearchParams({ href, inspect })}`); const circle = page.locator("svg circle").first(); // Every navigation renders Plot again, which takes seconds on a loaded CI runner. - await expect(circle).toBeVisible({ timeout: 30_000 }); + await expect(circle).toBeVisible({ timeout: 90_000 }); const assertInert = async () => { const links = page.locator("svg a"); expect(await links.count()).toBeGreaterThan(0); @@ -43,7 +43,7 @@ test.describe await assertInert(); await page.getByRole("button", { name: "Expand", exact: true }).click(); const dialog = page.getByRole("dialog"); - await expect(dialog.locator("svg circle")).toBeVisible({ timeout: 30_000 }); + await expect(dialog.locator("svg circle")).toBeVisible({ timeout: 90_000 }); await dialog.locator("svg circle").click(); await assertInert(); await expect(page).toHaveURL(`${fixture}?${new URLSearchParams({ href, inspect })}`); @@ -62,7 +62,7 @@ test.describe route.fulfill({ body: "Chart destination" }), ); await page.goto(`${fixture}?${new URLSearchParams({ href: "#details" })}`); - await expect(page.locator("svg circle").first()).toBeVisible({ timeout: 30_000 }); + await expect(page.locator("svg circle").first()).toBeVisible({ timeout: 90_000 }); for (const href of [ "https://example.test/chart?a=1&b=2", "mailto:chart@example.test", @@ -73,7 +73,7 @@ test.describe "java%73cript:void(0)", ]) { await page.goto(`${fixture}?${new URLSearchParams({ href })}`); - await expect(page.locator("svg circle").first()).toBeVisible({ timeout: 30_000 }); + await expect(page.locator("svg circle").first()).toBeVisible({ timeout: 90_000 }); const link = page.locator("svg a").first(); await expect(link).toBeAttached(); expect( diff --git a/apps/web/e2e/helpers.ts b/apps/web/e2e/helpers.ts index ea65103..9913e10 100644 --- a/apps/web/e2e/helpers.ts +++ b/apps/web/e2e/helpers.ts @@ -337,7 +337,7 @@ export async function openUserSettings( /** Wait until the shell thread is loaded and the message composer is interactive. */ export async function waitForChatComposer(page: Page) { await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true", { - timeout: 30_000, + timeout: 60_000, }); await expect(page.getByRole("combobox", { name: /^Message$|^Nachricht$/i })).toBeVisible(); } diff --git a/apps/web/e2e/oo-avatar.spec.ts b/apps/web/e2e/oo-avatar.spec.ts index 26b7532..3c6d762 100644 --- a/apps/web/e2e/oo-avatar.spec.ts +++ b/apps/web/e2e/oo-avatar.spec.ts @@ -5,6 +5,10 @@ for (const theme of ["light", "dark"] as const) { test(`Oo looks render every species with the Oo eyes (${theme})`, async ({ page }, testInfo) => { await page.goto(`/e2e/fixtures/oo-gallery.html?theme=${theme}`); const gallery = page.getByTestId("oo-gallery"); + await expect(gallery).toBeVisible({ timeout: 60_000 }); + await expect(gallery.locator("svg[data-oo-species]").first()).toBeVisible({ + timeout: 90_000, + }); await expect(gallery.locator("svg[data-oo-species]")).toHaveCount(12); for (const species of ["cat", "dog", "bunny", "bear", "robot", "ghost", "frog", "penguin"]) { await expect(gallery.locator(`svg[data-oo-species="${species}"]`).first()).toBeVisible(); diff --git a/ops/evo-deploy/deploy.sh b/ops/evo-deploy/deploy.sh index ac6bb05..dbd6881 100755 --- a/ops/evo-deploy/deploy.sh +++ b/ops/evo-deploy/deploy.sh @@ -291,17 +291,18 @@ wait_for_url() { log "[dry-run] would wait for $label at $url" return 0 fi + # Probe before checking the clock so a slow host still gets at least one attempt. while true; do - now="$(date +%s)" - if (( now - start >= timeout )); then - log "ERROR: $label health check timed out after ${timeout}s (last: ${last:-unknown})" - return 1 - fi if curl -fsS --max-time 5 "$url" >/dev/null 2>&1; then log "$label healthy" return 0 fi last="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 5 "$url" 2>/dev/null || echo unreachable)" + now="$(date +%s)" + if (( now - start >= timeout )); then + log "ERROR: $label health check timed out after ${timeout}s (last: ${last:-unknown})" + return 1 + fi sleep 2 done }