feat: add BreadcrumbProvider and e2e test suite
All checks were successful
Build & Publish / publish (push) Successful in 53s

Add BreadcrumbProvider context so pages can override TopBar breadcrumbs
dynamically. Add Playwright e2e tests for dashboard, agents, routes,
exchanges, and admin pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-26 11:33:55 +01:00
parent 19303eefad
commit 2a020c1e15
11 changed files with 547 additions and 7 deletions

90
e2e/dashboard.spec.ts Normal file
View File

@@ -0,0 +1,90 @@
import { test, expect } from '@playwright/test'
/** Click the 7d time range preset so hardcoded mock data (March 18) is visible. */
async function widenTimeRange(page: import('@playwright/test').Page) {
await page.getByRole('tab', { name: '7d' }).click()
}
test.describe('Dashboard (/apps)', () => {
test('renders KPI stat cards and exchange table', async ({ page }) => {
await page.goto('/apps')
await widenTimeRange(page)
// KPI health strip renders
await expect(page.getByText('Recent Exchanges')).toBeVisible()
// Table headers
await expect(page.getByRole('columnheader', { name: 'Status' })).toBeVisible()
await expect(page.getByRole('columnheader', { name: 'Route' })).toBeVisible()
await expect(page.getByRole('columnheader', { name: 'Application' })).toBeVisible()
await expect(page.getByRole('columnheader', { name: 'Exchange ID' })).toBeVisible()
// Table has data rows
const rows = page.locator('table tbody tr')
await expect(rows.first()).toBeVisible()
expect(await rows.count()).toBeGreaterThan(0)
// Sidebar renders with app names
await expect(page.getByText('order-service').first()).toBeVisible()
await expect(page.getByText('payment-svc').first()).toBeVisible()
// TopBar renders
await expect(page.getByLabel('Breadcrumb').getByText('Applications')).toBeVisible()
await expect(page.getByText('PRODUCTION')).toBeVisible()
// Shortcuts bar
await expect(page.getByText('Ctrl+K').first()).toBeVisible()
})
test('clicking a table row opens the detail panel', async ({ page }) => {
await page.goto('/apps')
await widenTimeRange(page)
// Click the first data row
const firstRow = page.locator('table tbody tr').first()
await expect(firstRow).toBeVisible()
await firstRow.click()
// Detail panel should open — look for "Open full details" link
await expect(page.getByText('Open full details')).toBeVisible()
// Overview section
await expect(page.getByText('Correlation').first()).toBeVisible()
})
test('navigating to app-scoped dashboard filters exchanges', async ({ page }) => {
await page.goto('/apps/order-service')
// Breadcrumb shows app scope
await expect(page.getByLabel('Breadcrumb').getByText('order-service')).toBeVisible()
// Table should still render
await expect(page.getByText('Recent Exchanges')).toBeVisible()
})
test('sidebar navigation works', async ({ page }) => {
await page.goto('/apps')
// Click on an app in the sidebar
const sidebarApp = page.getByText('order-service').first()
await sidebarApp.click()
// URL should change to the app scope
await expect(page).toHaveURL(/\/apps\/order-service/)
})
test('inspect button navigates to exchange detail', async ({ page }) => {
await page.goto('/apps')
await widenTimeRange(page)
// Wait for table rows to appear
const firstRow = page.locator('table tbody tr').first()
await expect(firstRow).toBeVisible()
// Click the inspect button (↗) on first row
const inspectBtn = firstRow.locator('button[title="Inspect exchange"]')
await inspectBtn.click()
// Should navigate to exchange detail page
await expect(page).toHaveURL(/\/exchanges\//)
})
})