From 018e0e6b1476437dcffe136a8549330be1c74dbd Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 10:15:28 +0100 Subject: [PATCH] test(web-e2e): raise status-ready timeout to 45s for parallel-worker stability (#908) * Initial plan * plan: stabilize web e2e tests timing out under parallel workers Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/49d09e67-5a8e-4eee-adcd-3d5416675a6b Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * test(web-e2e): bump status-ready timeout to 45s for parallel-worker stability Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/49d09e67-5a8e-4eee-adcd-3d5416675a6b Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> --- gitnexus-web/e2e/multi-repo-scoping.spec.ts | 27 +++++++++++++++--- gitnexus-web/e2e/onboarding.spec.ts | 9 +++++- gitnexus-web/e2e/repo-switching.spec.ts | 31 +++++++++++++++++---- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/gitnexus-web/e2e/multi-repo-scoping.spec.ts b/gitnexus-web/e2e/multi-repo-scoping.spec.ts index 67ee06b08..a60c847d2 100644 --- a/gitnexus-web/e2e/multi-repo-scoping.spec.ts +++ b/gitnexus-web/e2e/multi-repo-scoping.spec.ts @@ -61,13 +61,22 @@ test.beforeAll(async () => { } }); +// Auto-connect downloads the full graph from the backend; under parallel +// workers in CI the same backend serves multiple downloads concurrently, so +// reaching the "Ready" state can take noticeably longer than a single-worker +// run. Match the 45s budget used by waitForGraphLoaded() in +// server-connect.spec.ts which has been stable on the same backend. +const READY_TIMEOUT_MS = 45_000; + test.describe('Multi-Repo Scoping', () => { test('auto-connect via ?server= sets ?project= in URL', async ({ page }) => { // Navigate with ?server= param (the bookmarkable shortcut) await page.goto(`/?server=${encodeURIComponent(BACKEND_URL)}`); // Wait for graph to load - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); // URL should now contain ?project= with the repo name const url = new URL(page.url()); @@ -77,8 +86,14 @@ test.describe('Multi-Repo Scoping', () => { }); test('?server= is preserved in URL for F5 recovery', async ({ page }) => { + // Two sequential auto-connects (initial + reload), each up to READY_TIMEOUT_MS, + // can exceed the default 60s test timeout under parallel workers. + test.slow(); + await page.goto(`/?server=${encodeURIComponent(BACKEND_URL)}`); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); // URL should still have ?server= const url = new URL(page.url()); @@ -86,12 +101,16 @@ test.describe('Multi-Repo Scoping', () => { // F5 should reconnect (not show onboarding) await page.reload(); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); }); test('node count in status bar matches backend data', async ({ page }) => { await page.goto(`/?server=${encodeURIComponent(BACKEND_URL)}`); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); // Fetch expected node count from backend const res = await fetch(`${BACKEND_URL}/api/repo?repo=${encodeURIComponent(firstRepoName)}`); diff --git a/gitnexus-web/e2e/onboarding.spec.ts b/gitnexus-web/e2e/onboarding.spec.ts index da92ffb70..5b70899c6 100644 --- a/gitnexus-web/e2e/onboarding.spec.ts +++ b/gitnexus-web/e2e/onboarding.spec.ts @@ -26,7 +26,10 @@ async function enterExploringView(page: import('@playwright/test').Page) { // Landing screen may not appear (e.g. ?server auto-connect) } - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + // Match the 45s budget used by waitForGraphLoaded() in + // server-connect.spec.ts; under parallel CI workers, downloading the full + // graph can occasionally exceed 30s. + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 45_000 }); } // ── Flow 1: Onboarding (no server running) ───────────────────────────────── @@ -244,6 +247,10 @@ test.describe('Flow 3: Analyze form', () => { test.describe('Flow 4: Repo dropdown in exploring view', () => { const SKIP_MSG = 'Requires running gitnexus server with indexed repos'; + // enterExploringView() can take up to ~45s under parallel CI workers; combined + // with the dropdown interactions this can exceed the default 60s test budget. + test.slow(); + test.beforeAll(async () => { if (process.env.E2E) return; try { diff --git a/gitnexus-web/e2e/repo-switching.spec.ts b/gitnexus-web/e2e/repo-switching.spec.ts index 4cf6bf8c8..802f44e78 100644 --- a/gitnexus-web/e2e/repo-switching.spec.ts +++ b/gitnexus-web/e2e/repo-switching.spec.ts @@ -84,11 +84,20 @@ test.describe('Hold-queue timeout error', () => { // ── 2. ?project= URL persistence ───────────────────────────────────────────── +// Auto-connect downloads the full graph from the backend; under parallel +// workers in CI the same backend serves multiple downloads concurrently, so +// reaching the "Ready" state can take noticeably longer than a single-worker +// run. Match the 45s budget used by waitForGraphLoaded() in +// server-connect.spec.ts which has been stable on the same backend. +const READY_TIMEOUT_MS = 45_000; + test.describe('?project= URL persistence', () => { test('?project= is set in URL after connecting via ?server=', async ({ page }) => { await page.goto(`/?server=${encodeURIComponent(BACKEND_URL)}`); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); const url = new URL(page.url()); const project = url.searchParams.get('project'); @@ -98,12 +107,20 @@ test.describe('?project= URL persistence', () => { }); test('?project= is still present after F5 reload', async ({ page }) => { + // Two sequential auto-connects (initial + reload), each up to READY_TIMEOUT_MS, + // can exceed the default 60s test timeout under parallel workers. + test.slow(); + await page.goto(`/?server=${encodeURIComponent(BACKEND_URL)}`); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); // After connect, URL has ?server=&project= — F5 re-uses both params await page.reload(); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); const url = new URL(page.url()); expect(url.searchParams.get('project')).toBeTruthy(); @@ -122,7 +139,9 @@ test.describe('?project= auto-connect', () => { `/?server=${encodeURIComponent(BACKEND_URL)}&project=${encodeURIComponent(firstRepoName)}`, ); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); // ?project= in URL should match what we passed in const url = new URL(page.url()); @@ -155,7 +174,9 @@ test.describe('Windows path normalization', () => { await page.goto(`/?server=${encodeURIComponent(BACKEND_URL)}`); - await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ timeout: 30_000 }); + await expect(page.locator('[data-testid="status-ready"]')).toBeVisible({ + timeout: READY_TIMEOUT_MS, + }); // URL ?project= must be the short basename, NOT the full Windows path const url = new URL(page.url());