import { expect, test, type Page, type Route } from '@playwright/test'; import type { StubAuthSession } from '../../src/app/testing/auth-fixtures'; const releaseOperatorSession: StubAuthSession = { subjectId: 'release-e2e-user', tenant: 'tenant-default', scopes: ['admin', 'ui.read', 'release:read', 'policy:read', 'signer:read', 'vex:export'], }; const mockConfig = { authority: { issuer: '/authority', clientId: 'stella-ops-ui', authorizeEndpoint: '/authority/connect/authorize', tokenEndpoint: '/authority/connect/token', logoutEndpoint: '/authority/connect/logout', redirectUri: 'https://127.0.0.1:4400/auth/callback', postLogoutRedirectUri: 'https://127.0.0.1:4400/', scope: 'openid profile email ui.read', audience: '/gateway', dpopAlgorithms: ['ES256'], refreshLeewaySeconds: 60, }, apiBaseUrls: { authority: '/authority', scanner: '/scanner', policy: '/policy', concelier: '/concelier', attestor: '/attestor', gateway: '/gateway', }, quickstartMode: true, setup: 'complete', }; const runDetail = { runId: 'run-e2e', releaseId: 'rel-e2e', releaseName: 'Billing API', releaseSlug: 'billing-api', releaseType: 'standard', releaseVersionId: 'ver-e2e', releaseVersionNumber: 42, releaseVersionDigest: 'sha256:release-e2e', lane: 'standard', status: 'running', outcome: 'in_progress', targetEnvironment: 'prod', targetRegion: 'eu-west', scopeSummary: 'stage->prod', requestedAt: '2026-03-07T10:00:00Z', updatedAt: '2026-03-07T10:24:00Z', needsApproval: true, blockedByDataIntegrity: false, correlationKey: 'corr-e2e', statusRow: { runStatus: 'running', gateStatus: 'warn', approvalStatus: 'pending', dataTrustStatus: 'healthy', }, }; const runTimeline = { runId: 'run-e2e', events: [ { eventId: 'evt-ingest', eventClass: 'scan', phase: 'ingest', status: 'completed', occurredAt: '2026-03-07T10:02:00Z', message: 'Ingest completed successfully.', }, { eventId: 'evt-gate', eventClass: 'gate', phase: 'gate', status: 'warn', occurredAt: '2026-03-07T10:07:00Z', message: 'Gate requires operator review.', }, { eventId: 'evt-approval', eventClass: 'approval', phase: 'approval', status: 'pending', occurredAt: '2026-03-07T10:11:00Z', message: 'Awaiting manual approval.', }, { eventId: 'evt-evidence', eventClass: 'evidence', phase: 'evidence', status: 'completed', occurredAt: '2026-03-07T10:18:00Z', message: 'Evidence bundle prepared.', }, ], }; const liveGraph = { id: 'run-e2e', name: 'Billing API Run', layoutAlgorithm: 'dagre', nodes: [ { id: 'ingest', label: 'Ingest & Scan', type: 'task', status: 'succeeded', duration: 120000 }, { id: 'gate', label: 'Policy Gate', type: 'gate', status: 'running', duration: 240000 }, { id: 'approval', label: 'Approval', type: 'approval', status: 'pending', duration: 0 }, { id: 'evidence', label: 'Evidence', type: 'task', status: 'succeeded', duration: 60000 }, ], edges: [ { id: 'ingest-gate', source: 'ingest', target: 'gate', type: 'dependency' }, { id: 'gate-approval', source: 'gate', target: 'approval', type: 'dependency' }, { id: 'approval-evidence', source: 'approval', target: 'evidence', type: 'dependency' }, ], positions: [ { nodeId: 'ingest', x: 180, y: 180 }, { nodeId: 'gate', x: 420, y: 180 }, { nodeId: 'approval', x: 660, y: 180 }, { nodeId: 'evidence', x: 900, y: 180 }, ], metadata: { runId: 'run-e2e', releaseId: 'rel-e2e', }, }; async function fulfillJson(route: Route, body: unknown, status = 200): Promise { await route.fulfill({ status, contentType: 'application/json', body: JSON.stringify(body), }); } async function setupHarness(page: Page): Promise { await page.addInitScript((session) => { (window as { __stellaopsTestSession?: unknown }).__stellaopsTestSession = session; }, releaseOperatorSession); await page.route('**/api/**', (route) => fulfillJson(route, {})); await page.route('**/platform/envsettings.json', (route) => fulfillJson(route, mockConfig)); await page.route('**/platform/i18n/*.json', (route) => fulfillJson(route, {})); await page.route('**/config.json', (route) => fulfillJson(route, mockConfig)); await page.route('**/.well-known/openid-configuration', (route) => fulfillJson(route, { issuer: 'https://127.0.0.1:4400/authority', authorization_endpoint: 'https://127.0.0.1:4400/authority/connect/authorize', token_endpoint: 'https://127.0.0.1:4400/authority/connect/token', jwks_uri: 'https://127.0.0.1:4400/authority/.well-known/jwks.json', response_types_supported: ['code'], subject_types_supported: ['public'], id_token_signing_alg_values_supported: ['RS256'], }), ); await page.route('**/authority/.well-known/jwks.json', (route) => fulfillJson(route, { keys: [] })); await page.route('**/authority/console/tenants**', (route) => fulfillJson(route, { tenants: [ { tenantId: releaseOperatorSession.tenant, displayName: 'Default Tenant', isDefault: true, isActive: true, }, ], }), ); await page.route('**/console/branding**', (route) => fulfillJson(route, { tenantId: releaseOperatorSession.tenant, appName: 'Stella Ops', logoUrl: null, cssVariables: {}, }), ); await page.route('**/console/profile**', (route) => fulfillJson(route, { subjectId: releaseOperatorSession.subjectId, username: 'release-e2e', displayName: 'Release E2E', tenant: releaseOperatorSession.tenant, roles: ['release-operator'], scopes: releaseOperatorSession.scopes, }), ); await page.route('**/console/token/introspect**', (route) => fulfillJson(route, { active: true, tenant: releaseOperatorSession.tenant, subject: releaseOperatorSession.subjectId, scopes: releaseOperatorSession.scopes, }), ); await page.route('**/api/v2/context/regions**', (route) => fulfillJson(route, [{ regionId: 'eu-west', displayName: 'EU West', sortOrder: 1, enabled: true }]), ); await page.route('**/api/v2/context/environments**', (route) => fulfillJson(route, [ { environmentId: 'prod', regionId: 'eu-west', environmentType: 'prod', displayName: 'Prod', sortOrder: 1, enabled: true, }, ]), ); await page.route('**/api/v2/context/preferences**', (route) => fulfillJson(route, { tenantId: releaseOperatorSession.tenant, actorId: releaseOperatorSession.subjectId, regions: ['eu-west'], environments: ['prod'], timeWindow: '24h', stage: 'all', updatedAt: '2026-03-07T12:00:00Z', updatedBy: releaseOperatorSession.subjectId, }), ); await page.route('**/doctor/api/v1/doctor/trends**', (route) => fulfillJson(route, [])); await page.route('**/api/v1/approvals**', (route) => fulfillJson(route, [])); await page.route('**/api/v1/telemetry/ttfs', (route) => fulfillJson(route, { accepted: true }, 202)); await page.route(/\/api\/v2\/releases\/runs\/run-e2e(?:\?.*)?$/, (route) => fulfillJson(route, runDetail)); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/timeline(?:\?.*)?$/, (route) => fulfillJson(route, runTimeline)); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/gate-decision(?:\?.*)?$/, (route) => fulfillJson(route, { runId: 'run-e2e', verdict: 'warn', blockers: ['manual-review'], riskBudgetDelta: 14, }), ); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/approvals(?:\?.*)?$/, (route) => fulfillJson(route, { runId: 'run-e2e', checkpoints: [{ checkpointId: 'approve-prod', status: 'pending', approvedAt: null }], }), ); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/deployments(?:\?.*)?$/, (route) => fulfillJson(route, { runId: 'run-e2e', targets: [ { targetId: 'prod-1', targetName: 'billing-api-prod', environment: 'prod', region: 'eu-west', status: 'queued', }, ], }), ); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/security-inputs(?:\?.*)?$/, (route) => fulfillJson(route, { runId: 'run-e2e', reachabilityCoveragePercent: 94, feedFreshnessStatus: 'healthy', vexStatementsApplied: 3, exceptionsApplied: 1, }), ); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/evidence(?:\?.*)?$/, (route) => fulfillJson(route, { runId: 'run-e2e', replayDeterminismVerdict: 'match', replayMismatch: false, signatureStatus: 'verified', }), ); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/replay(?:\?.*)?$/, (route) => fulfillJson(route, { runId: 'run-e2e', verdict: 'match', }), ); await page.route(/\/api\/v2\/releases\/runs\/run-e2e\/audit(?:\?.*)?$/, (route) => fulfillJson(route, { runId: 'run-e2e', entries: [ { auditId: 'audit-001', action: 'release.run.updated', actorId: 'ops@example.com', occurredAt: '2026-03-07T10:19:00Z', correlationKey: 'corr-e2e', }, ], }), ); await page.route(/\/api\/v1\/workflows\/run-e2e\/graph(?:\?.*)?$/, (route) => fulfillJson(route, liveGraph)); await page.route(/\/api\/v1\/workflows\/run-e2e\/critical-path(?:\?.*)?$/, (route) => fulfillJson(route, { path: ['ingest', 'gate', 'approval', 'evidence'], totalDuration: 420000, }), ); } test.beforeEach(async ({ page }) => { await setupHarness(page); }); test('run workspace supports timeline drill-in and evidence replay handoff', async ({ page }) => { await page.goto('/releases/runs/run-e2e/graph?step=gate', { waitUntil: 'domcontentloaded' }); await expect(page.getByTestId('run-graph-replay-page')).toBeVisible(); await expect(page.getByTestId('run-workspace-tab-graph')).toHaveClass(/active/); await expect(page.getByRole('button', { name: 'Critical path only' })).toBeVisible(); await page.getByTestId('run-workspace-tab-timeline').click(); await expect(page).toHaveURL(/\/releases\/runs\/run-e2e\/timeline\?.*step=gate/); await page.getByTestId('run-timeline-row-evt-approval').click(); await expect(page).toHaveURL(/\/releases\/runs\/run-e2e\/timeline\?.*step=approval/); await expect(page.getByTestId('run-step-drawer')).toContainText('Approval'); await page.getByTestId('run-workspace-tab-replay').click(); await expect(page).toHaveURL(/\/releases\/runs\/run-e2e\/replay\?.*step=approval/); await expect(page.getByText('Replay verdict')).toBeVisible(); await expect(page.getByText('Debug Session')).toBeVisible(); await page.getByRole('button', { name: 'Open evidence entry' }).click(); await expect(page).toHaveURL(/\/evidence\/verify-replay\?.*releaseId=rel-e2e.*runId=run-e2e/); await expect(page.getByRole('heading', { name: 'Verdict Replay' })).toBeVisible(); await page.getByRole('button', { name: 'Open run replay workspace' }).click(); await expect(page).toHaveURL(/\/releases\/runs\/run-e2e\/replay\?.*releaseId=rel-e2e.*returnTo=/); await expect(page.getByRole('button', { name: 'Return to previous context' })).toBeVisible(); }); test('legacy workflow visualization aliases redirect into the canonical run shell', async ({ page }) => { await page.goto('/workflow-visualization/run-e2e/graph?step=evidence', { waitUntil: 'domcontentloaded' }); await expect(page).toHaveURL(/\/releases\/runs\/run-e2e\/graph\?.*step=evidence/); await expect(page.getByTestId('run-workspace-tab-graph')).toHaveClass(/active/); });