From 17198bf073ac26ecefb5937f4206c8ded0b994a8 Mon Sep 17 00:00:00 2001 From: Sergey Kozyrenko Date: Sat, 25 Jul 2026 23:56:04 +0700 Subject: [PATCH] fix(e2e): sweep the panels the manifest claims to cover, and own the shared provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three holes in the route manifest, one class: a gate that reports green on a surface it never mounts. - FLOW_DETAIL_TABS listed 8 of the flow detail's 10 desktop panels. Terminal is the default and gets scanned anyway, but Automation was mounted by nothing — no axe scan, no palette scan — so a regression confined to it stayed invisible. - /dashboard declared no tabs at all although it is a two-tab Radix Tabs, and Radix unmounts the inactive panel: Overview, four Cards and two usage tables, was never scanned. The same regression in Analytics would have been caught. - Its `ready` was a ChartCard heading rendered above the component's own loading branch, which is exactly what the tabs contract forbids: the sweep could start against spinners. Gate on a data row instead. - templates-provider.tsx was owned by /templates alone while flow-form.tsx consumes it from /flows/5, so affected-routes scoped a provider change away from the route that renders the consumer. All four panels pass axe and palette in both themes as-is. The ownership case is pinned against the real manifest, not the fake one, and fails before the fix. Co-Authored-By: Claude Opus 4.8 --- frontend/e2e/affected-routes.unit.test.ts | 9 +++++++++ frontend/e2e/routes.ts | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/frontend/e2e/affected-routes.unit.test.ts b/frontend/e2e/affected-routes.unit.test.ts index 53e73d66..c8fbed50 100644 --- a/frontend/e2e/affected-routes.unit.test.ts +++ b/frontend/e2e/affected-routes.unit.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest'; import type { RouteSource } from './affected-routes.ts'; import { affectedRoutes } from './affected-routes.ts'; +import { ROUTE_MANIFEST } from './routes.ts'; const MANIFEST: RouteSource[] = [ { @@ -58,4 +59,12 @@ describe('affectedRoutes', () => { expect(result.map((route) => route.path)).toEqual(['/flows']); }); + + // The fake manifest above cannot catch ownership drift in the real one: a shared provider claimed + // by a single route silently scopes a run away from the other routes that mount its consumers. + it('scopes a shared provider to every route that mounts a consumer', () => { + const result = affectedRoutes(['frontend/src/providers/templates-provider.tsx'], ROUTE_MANIFEST); + + expect(result.map((route) => route.path).sort()).toEqual(['/flows/5', '/templates']); + }); }); diff --git a/frontend/e2e/routes.ts b/frontend/e2e/routes.ts index b177c2f2..c6427754 100644 --- a/frontend/e2e/routes.ts +++ b/frontend/e2e/routes.ts @@ -43,6 +43,7 @@ export interface RouteTab { export const FLOW_DETAIL_TABS: RouteTab[] = [ { name: 'Dashboard', ready: (page) => page.getByText('Usage by Model & Provider') }, { name: 'Assistant', ready: (page) => page.getByText('New assistant', { exact: true }) }, + { name: 'Automation', ready: (page) => page.getByText('No active tasks') }, { name: 'Tasks', ready: (page) => page.getByText('E2E Task Alpha') }, { name: 'Agents', ready: (page) => page.getByText('E2E agent reconnaissance') }, { name: 'Searches', ready: (page) => page.getByText('E2E search for the CVE') }, @@ -97,6 +98,8 @@ export const ROUTE_MANIFEST: RouteManifestEntry[] = [ 'src/components/shared/file-manager', 'src/components/dashboard', 'src/features/resources', + // Assistant-tab FlowForm reads useTemplates, so a provider change reaches this route too. + 'src/providers/templates-provider.tsx', ], tabs: FLOW_DETAIL_TABS, }, @@ -130,8 +133,9 @@ export const ROUTE_MANIFEST: RouteManifestEntry[] = [ a11yWaivers: [{ rule: 'aria-valid-attr-value', target: /radix-.*-trigger-/ }], cassette: dashboardCassette, path: routes.dashboard, - ready: (page) => page.getByRole('heading', { name: 'Flows Activity Over Time' }), + ready: (page) => page.getByText('E2E Alpha'), sources: ['src/pages/dashboard', 'src/components/dashboard'], + tabs: [{ name: 'Overview', ready: (page) => page.getByRole('cell', { exact: true, name: 'e2e-provider' }) }], }, { cassette: settingsPromptsCassette,