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 <cynarAI@users.noreply.github.com> * 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 <cynarAI@users.noreply.github.com> * 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) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b1b76a846e
commit
6c0fba8cc1
5
.github/workflows/playwright.yml
vendored
5
.github/workflows/playwright.yml
vendored
@ -165,15 +165,14 @@ jobs:
|
|||||||
- name: Upload Playwright artifacts
|
- name: Upload Playwright artifacts
|
||||||
if: always() && inputs.upload_artifacts
|
if: always() && inputs.upload_artifacts
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||||
with:
|
with:
|
||||||
name: playwright-artifacts-${{ github.run_id }}-${{ github.run_attempt }}
|
name: playwright-artifacts-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
path: |
|
path: |
|
||||||
playwright-report
|
playwright-report
|
||||||
playwright-report-www
|
playwright-report-www
|
||||||
apps/web/test-results
|
|
||||||
test-report/e2e
|
test-report/e2e
|
||||||
retention-days: 7
|
retention-days: 1
|
||||||
if-no-files-found: warn
|
if-no-files-found: warn
|
||||||
- name: Publish Playwright visual report
|
- name: Publish Playwright visual report
|
||||||
if: always() && inputs.publish_report
|
if: always() && inputs.publish_report
|
||||||
|
|||||||
@ -21,7 +21,7 @@ test.describe
|
|||||||
await page.goto(`${fixture}?${new URLSearchParams({ href, inspect })}`);
|
await page.goto(`${fixture}?${new URLSearchParams({ href, inspect })}`);
|
||||||
const circle = page.locator("svg circle").first();
|
const circle = page.locator("svg circle").first();
|
||||||
// Every navigation renders Plot again, which takes seconds on a loaded CI runner.
|
// 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 assertInert = async () => {
|
||||||
const links = page.locator("svg a");
|
const links = page.locator("svg a");
|
||||||
expect(await links.count()).toBeGreaterThan(0);
|
expect(await links.count()).toBeGreaterThan(0);
|
||||||
@ -43,7 +43,7 @@ test.describe
|
|||||||
await assertInert();
|
await assertInert();
|
||||||
await page.getByRole("button", { name: "Expand", exact: true }).click();
|
await page.getByRole("button", { name: "Expand", exact: true }).click();
|
||||||
const dialog = page.getByRole("dialog");
|
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 dialog.locator("svg circle").click();
|
||||||
await assertInert();
|
await assertInert();
|
||||||
await expect(page).toHaveURL(`${fixture}?${new URLSearchParams({ href, inspect })}`);
|
await expect(page).toHaveURL(`${fixture}?${new URLSearchParams({ href, inspect })}`);
|
||||||
@ -62,7 +62,7 @@ test.describe
|
|||||||
route.fulfill({ body: "Chart destination" }),
|
route.fulfill({ body: "Chart destination" }),
|
||||||
);
|
);
|
||||||
await page.goto(`${fixture}?${new URLSearchParams({ href: "#details" })}`);
|
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 [
|
for (const href of [
|
||||||
"https://example.test/chart?a=1&b=2",
|
"https://example.test/chart?a=1&b=2",
|
||||||
"mailto:chart@example.test",
|
"mailto:chart@example.test",
|
||||||
@ -73,7 +73,7 @@ test.describe
|
|||||||
"java%73cript:void(0)",
|
"java%73cript:void(0)",
|
||||||
]) {
|
]) {
|
||||||
await page.goto(`${fixture}?${new URLSearchParams({ href })}`);
|
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();
|
const link = page.locator("svg a").first();
|
||||||
await expect(link).toBeAttached();
|
await expect(link).toBeAttached();
|
||||||
expect(
|
expect(
|
||||||
|
|||||||
@ -337,7 +337,7 @@ export async function openUserSettings(
|
|||||||
/** Wait until the shell thread is loaded and the message composer is interactive. */
|
/** Wait until the shell thread is loaded and the message composer is interactive. */
|
||||||
export async function waitForChatComposer(page: Page) {
|
export async function waitForChatComposer(page: Page) {
|
||||||
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true", {
|
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();
|
await expect(page.getByRole("combobox", { name: /^Message$|^Nachricht$/i })).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) => {
|
test(`Oo looks render every species with the Oo eyes (${theme})`, async ({ page }, testInfo) => {
|
||||||
await page.goto(`/e2e/fixtures/oo-gallery.html?theme=${theme}`);
|
await page.goto(`/e2e/fixtures/oo-gallery.html?theme=${theme}`);
|
||||||
const gallery = page.getByTestId("oo-gallery");
|
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);
|
await expect(gallery.locator("svg[data-oo-species]")).toHaveCount(12);
|
||||||
for (const species of ["cat", "dog", "bunny", "bear", "robot", "ghost", "frog", "penguin"]) {
|
for (const species of ["cat", "dog", "bunny", "bear", "robot", "ghost", "frog", "penguin"]) {
|
||||||
await expect(gallery.locator(`svg[data-oo-species="${species}"]`).first()).toBeVisible();
|
await expect(gallery.locator(`svg[data-oo-species="${species}"]`).first()).toBeVisible();
|
||||||
|
|||||||
@ -291,17 +291,18 @@ wait_for_url() {
|
|||||||
log "[dry-run] would wait for $label at $url"
|
log "[dry-run] would wait for $label at $url"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
# Probe before checking the clock so a slow host still gets at least one attempt.
|
||||||
while true; do
|
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
|
if curl -fsS --max-time 5 "$url" >/dev/null 2>&1; then
|
||||||
log "$label healthy"
|
log "$label healthy"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
last="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 5 "$url" 2>/dev/null || echo unreachable)"
|
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
|
sleep 2
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user