From fa115b8203b6b972ee07b2e3dac6cc193b31ec47 Mon Sep 17 00:00:00 2001 From: sahal Date: Tue, 28 Apr 2026 11:21:21 -0700 Subject: [PATCH] fix(e2e): stabilize chromium specs after RepoLanding rework --- gitnexus-web/e2e/onboarding.spec.ts | 20 +++++++++--------- gitnexus-web/e2e/repo-switching.spec.ts | 27 +++++++++++++++++-------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/gitnexus-web/e2e/onboarding.spec.ts b/gitnexus-web/e2e/onboarding.spec.ts index 5b70899c6..335c5437f 100644 --- a/gitnexus-web/e2e/onboarding.spec.ts +++ b/gitnexus-web/e2e/onboarding.spec.ts @@ -269,15 +269,18 @@ test.describe('Flow 4: Repo dropdown in exploring view', () => { } }); + // The project badge is the only header button containing the pulsing + // status-dot span (`bg-node-function` + `animate-pulse`). Selecting by this + // distinguishing child is more robust than `.first()` on `header button:has(svg)`, + // which silently drifts whenever a new icon-bearing button is added to the header. + const PROJECT_BADGE = 'header button:has(span.bg-node-function.animate-pulse)'; + test('project badge opens repo dropdown', async ({ page }, testInfo) => { await enterExploringView(page); await page.screenshot({ path: testInfo.outputPath('exploring-loaded.png') }); - // Click the project badge (has a chevron) - const badge = page - .locator('header button') - .filter({ has: page.locator('svg') }) - .first(); + const badge = page.locator(PROJECT_BADGE); + await expect(badge).toBeVisible(); await badge.click(); // Repo dropdown should be visible @@ -289,11 +292,8 @@ test.describe('Flow 4: Repo dropdown in exploring view', () => { test('analyze option opens inline form', async ({ page }, testInfo) => { await enterExploringView(page); - // Open repo dropdown - const badge = page - .locator('header button') - .filter({ has: page.locator('svg') }) - .first(); + const badge = page.locator(PROJECT_BADGE); + await expect(badge).toBeVisible(); await badge.click(); // Click "Analyze a new repository..." diff --git a/gitnexus-web/e2e/repo-switching.spec.ts b/gitnexus-web/e2e/repo-switching.spec.ts index 802f44e78..49392158d 100644 --- a/gitnexus-web/e2e/repo-switching.spec.ts +++ b/gitnexus-web/e2e/repo-switching.spec.ts @@ -122,8 +122,12 @@ test.describe('?project= URL persistence', () => { timeout: READY_TIMEOUT_MS, }); - const url = new URL(page.url()); - expect(url.searchParams.get('project')).toBeTruthy(); + // Poll the URL — under parallel CI workers, history.replaceState() can + // briefly trail the status-ready render. A single read may observe the + // pre-replaceState URL, even though the state update is in flight. + await expect + .poll(() => new URL(page.url()).searchParams.get('project'), { timeout: 5_000 }) + .toBeTruthy(); }); }); @@ -157,8 +161,13 @@ test.describe('Windows path normalization', () => { test('project name uses basename when /api/repo returns a Windows-style repoPath', async ({ page, }) => { - const repoName = firstRepoName || 'test-repo'; - const windowsPath = `C:\\Users\\LENOVO\\.gitnexus\\repos\\${repoName}`; + // Use the last `/`-separated segment so the path's tail is a single segment + // even if the live backend's first repo name happens to contain a `/`. The + // production code splits on both `\` and `/`, so a slashed name would otherwise + // make `expect(project).toBe(repoName)` compare against a multi-segment name + // while the URL only carries the final segment. + const baseName = (firstRepoName || 'test-repo').split('/').pop() || 'test-repo'; + const windowsPath = `C:\\Users\\LENOVO\\.gitnexus\\repos\\${baseName}`; // Mock /api/repo to return a Windows backslash path while keeping name correct await page.route(/\/api\/repo(?!s)(\?.*)?$/, (route) => @@ -179,11 +188,13 @@ test.describe('Windows path normalization', () => { }); // URL ?project= must be the short basename, NOT the full Windows path - const url = new URL(page.url()); - const project = url.searchParams.get('project'); - expect(project).toBeTruthy(); + await expect + .poll(() => new URL(page.url()).searchParams.get('project'), { timeout: 5_000 }) + .toBeTruthy(); + + const project = new URL(page.url()).searchParams.get('project'); expect(project).not.toContain('\\'); expect(project).not.toContain('LENOVO'); - expect(project).toBe(repoName); + expect(project).toBe(baseName); }); });