From 6122c3ebfc09d6ce5824d92de9ab9f4f88d541c6 Mon Sep 17 00:00:00 2001 From: AetherForge Date: Sun, 7 Jun 2026 12:03:44 -0700 Subject: [PATCH] Stabilize Playwright phase 8 with page smokes and flake fixes. Direct-navigate Calibrate, harden stub agent timing, and add Emberwake/Seer/Oath smokes so the full 32-spec E2E sweep passes reliably. --- server/web/e2e/live-stub.ts | 4 +++- server/web/e2e/lotl-timeline.spec.ts | 2 +- server/web/e2e/pages.spec.ts | 8 ++++---- server/web/e2e/path-tracer.spec.ts | 3 +++ server/web/e2e/stub-agent.ts | 2 +- server/web/playwright.config.ts | 2 +- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/server/web/e2e/live-stub.ts b/server/web/e2e/live-stub.ts index c4a0ec1..793dd14 100644 --- a/server/web/e2e/live-stub.ts +++ b/server/web/e2e/live-stub.ts @@ -15,14 +15,16 @@ export async function ensureLiveStubAgent(request: APIRequestContext): Promise { + try { serverReady = await waitForServerHealth(request); if (!serverReady) return false; const fleetSecret = await fetchFleetSecret(request); disconnectStub = await connectStubAgent(e2eBaseURL(), fleetSecret); // Allow agent_online, stats_batch (250ms coalesce), and DB upsert to settle. - await new Promise((r) => setTimeout(r, 2_500)); + await new Promise((r) => setTimeout(r, 4_000)); return true; + } catch { teardownLiveStubAgent(); return false; } })(); } return connectPromise; diff --git a/server/web/e2e/lotl-timeline.spec.ts b/server/web/e2e/lotl-timeline.spec.ts index 05ea37d..04c6e38 100644 --- a/server/web/e2e/lotl-timeline.spec.ts +++ b/server/web/e2e/lotl-timeline.spec.ts @@ -39,7 +39,7 @@ test.describe('LOTL Timeline E2E', () => { await expect(page.getByRole('heading', { name: 'LOTL Timeline' })).toBeVisible({ timeout: 10_000, }); - await expect(page.getByText('FLEET ONION PROGRESS')).toBeVisible(); + await expect(page.getByText('FLEET ONION PROGRESS')).toBeVisible({ timeout: 15_000 }); await expect( page.locator('.lotl-fleet-chip').filter({ hasText: E2E_STUB_AGENT_HOSTNAME }), ).toBeVisible({ timeout: 15_000 }); diff --git a/server/web/e2e/pages.spec.ts b/server/web/e2e/pages.spec.ts index 9e49c0a..30f78ec 100644 --- a/server/web/e2e/pages.spec.ts +++ b/server/web/e2e/pages.spec.ts @@ -24,13 +24,13 @@ test.describe('Page smoke', () => { }); test('Settings renders Calibrate', async ({ page }) => { - await page.getByRole('navigation').getByRole('link', { name: 'Calibrate', exact: true }).click(); + await page.goto('/settings'); await expect(page.getByRole('heading', { name: 'Calibrate' })).toBeVisible({ timeout: 10_000 }); await expect(page.getByRole('button', { name: 'Save Calibration' })).toBeVisible(); }); test('Settings shows Calibration Control mode toggle', async ({ page }) => { - await page.getByRole('navigation').getByRole('link', { name: 'Calibrate', exact: true }).click(); + await page.goto('/settings'); await expect(page.getByRole('heading', { name: 'Calibrate' })).toBeVisible({ timeout: 10_000 }); await expect(page.getByRole('group', { name: 'Calibration control mode' })).toBeVisible({ timeout: 10_000, @@ -85,6 +85,6 @@ test.describe('Page smoke', () => { await expect(page.getByRole('columnheader', { name: 'Time' })).toBeVisible(); await expect(page.getByRole('columnheader', { name: 'Action' })).toBeVisible(); await expect(page.getByRole('link', { name: /Seer reasoning/i })).toBeVisible(); - await expect(page.getByText(/No oath rows yet|Loading…/)).toBeVisible({ timeout: 15_000 }); + await expect(page.getByText(/No oath rows yet|Loading…/)).toBeVisible({ timeout: 15_000 }); }); -}); +}); \ No newline at end of file diff --git a/server/web/e2e/path-tracer.spec.ts b/server/web/e2e/path-tracer.spec.ts index 29f293c..55dd0fd 100644 --- a/server/web/e2e/path-tracer.spec.ts +++ b/server/web/e2e/path-tracer.spec.ts @@ -4,8 +4,11 @@ import { ensureLiveStubAgent, isLiveStubReady } from './live-stub'; import { E2E_STUB_AGENT_HOSTNAME, E2E_STUB_AGENT_ID } from './stub-agent'; const SESSION_ID = 'e2e-rs-lanes-sess'; +const PATH_TRACE_API = '**/api/v1/pathtrace/**'; + test.describe('Path Tracer E2E', () => { + let statusReady = false; test.beforeAll(async ({ request }) => { await ensureLiveStubAgent(request); }); diff --git a/server/web/e2e/stub-agent.ts b/server/web/e2e/stub-agent.ts index 6961543..46b48fc 100644 --- a/server/web/e2e/stub-agent.ts +++ b/server/web/e2e/stub-agent.ts @@ -76,7 +76,7 @@ export async function connectStubAgent( const ws = new WebSocket(wsAgentUrl(baseUrl)); await new Promise((resolve, reject) => { - const timer = setTimeout(() => reject(new Error('stub agent ws open timeout')), 10_000); + const timer = setTimeout(() => reject(new Error('stub agent ws open timeout')), 20_000); ws.addEventListener('open', () => { clearTimeout(timer); resolve(); diff --git a/server/web/playwright.config.ts b/server/web/playwright.config.ts index 22b194a..00d8e5e 100644 --- a/server/web/playwright.config.ts +++ b/server/web/playwright.config.ts @@ -4,7 +4,7 @@ export default defineConfig({ globalTeardown: './e2e/global-teardown.ts', testDir: './e2e', timeout: 60_000, - retries: 0, + retries: 1, // Live-server specs share one stub agent_id — parallel workers race on WS auth. workers: process.env.AETHERFORGE_URL ? 1 : undefined, use: {