From e0ebd23a5a29a80fb0a479bd44cc19d457194bbd Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 28 May 2026 22:29:20 -0700 Subject: [PATCH] [eric] e2e: create a dashboard before the toolbar/canvas specs so a clean CI profile does not fail - combinatorial Add-note and deep-coverage Dashboard-canvas both clicked surfaces that only mount once a dashboard is active, which a freshly-wiped CI profile lacks --- e2e/tests/combinatorial-flows.spec.ts | 14 ++++++++++++++ e2e/tests/deep-coverage.spec.ts | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/e2e/tests/combinatorial-flows.spec.ts b/e2e/tests/combinatorial-flows.spec.ts index f9d4f580..7b720b01 100644 --- a/e2e/tests/combinatorial-flows.spec.ts +++ b/e2e/tests/combinatorial-flows.spec.ts @@ -55,6 +55,19 @@ test.describe('combinatorial user flows', () => { await el.click({ timeout: 8_000 }); return el; }; + // The bottom dashboard toolbar (New Agent / Add note / Add App / Browser) only + // mounts when a dashboard is active; a clean CI profile has none, so create one + // via the sidebar "+". Idempotent: returns early if the toolbar is already up. + const ensureDashboardActive = async () => { + const toggle = page.locator('[data-onboarding="sidebar-toggle"]'); + if ((await toggle.getAttribute('aria-expanded')) === 'false') await toggle.click({ timeout: 5_000 }).catch(() => {}); + await clickMust(page.locator('[data-onboarding="sidebar-dashboards"]'), 'sidebar dashboards'); + if (await page.getByRole('button', { name: 'Add note' }).isVisible().catch(() => false)) return; + const createBtn = page.locator('[data-onboarding="sidebar-dashboards"] button').first(); + if (await createBtn.count()) await createBtn.click({ timeout: 5_000 }).catch(() => {}); + await expect.poll(() => page.url(), { timeout: 8_000 }).toMatch(/\/dashboard\//); + await expect(page.getByRole('button', { name: 'Add note' }), 'dashboard toolbar never mounted').toBeVisible({ timeout: 10_000 }); + }; const errorsSince = (mark: number) => errors.slice(mark).filter((e) => !CONSOLE_WHITELIST.some((rx) => rx.test(e.text))); const assertNoNew = (mark: number, label: string) => { const now = rendererCrashes(); @@ -290,6 +303,7 @@ test.describe('combinatorial user flows', () => { test('dashboard toolbar: Add note + Add App + History each mount their surfaces', async () => { const mark = errors.length; + await ensureDashboardActive(); await clickMust(page.getByRole('button', { name: 'Add note' }), 'toolbar Add note'); assertNoNew(mark, 'Add note mount'); diff --git a/e2e/tests/deep-coverage.spec.ts b/e2e/tests/deep-coverage.spec.ts index fedb12ab..92bb6bef 100644 --- a/e2e/tests/deep-coverage.spec.ts +++ b/e2e/tests/deep-coverage.spec.ts @@ -139,7 +139,20 @@ test.describe('deep interactive coverage', () => { }); test('Dashboard canvas opens', async ({}, info) => { - await safeClick(page.getByText('Getting Started', { exact: true }), 'Getting Started dashboard'); + // A clean CI profile has no "Getting Started" (or any) dashboard, so open an + // existing one if present, else create one via the sidebar "+" so the canvas + // actually mounts instead of failing on a missing seed dashboard. + const seed = page.getByText('Getting Started', { exact: true }); + if (await seed.count()) { + await seed.first().click({ timeout: 5000 }); + } else { + const toggle = page.locator('[data-onboarding="sidebar-toggle"]'); + if ((await toggle.getAttribute('aria-expanded')) === 'false') await toggle.click({ timeout: 5000 }).catch(() => {}); + await page.locator('[data-onboarding="sidebar-dashboards"]').click({ timeout: 5000 }).catch(() => {}); + const createBtn = page.locator('[data-onboarding="sidebar-dashboards"] button').first(); + if (await createBtn.count()) await createBtn.click({ timeout: 5000 }).catch(() => {}); + await expect.poll(() => page.url(), { timeout: 8000 }).toMatch(/\/dashboard\//); + } await page.waitForTimeout(2000); await page.screenshot({ path: info.outputPath('dashboard-canvas.png') }); noNewCrashes('dashboard canvas open');