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 }