import { test as base, expect, Page } from '@playwright/test'; /** * StubAuthSession shape matches src/app/testing/auth-fixtures.ts. * The Angular APP_INITIALIZER in app.config.ts reads * `window.__stellaopsTestSession` and calls seedAuthSession() to * populate the AuthSessionStore before guards execute. */ interface StubAuthSession { subjectId: string; tenant: string; scopes: string[]; } /** Admin session with all major scopes for unrestricted route access. */ const adminTestSession: StubAuthSession = { subjectId: 'e2e-admin-user', tenant: 'tenant-default', scopes: [ 'admin', 'ui.read', 'ui.admin', 'orch:read', 'orch:operate', 'orch:quota', 'orch:backfill', 'policy:read', 'policy:write', 'policy:author', 'policy:review', 'policy:approve', 'policy:operate', 'policy:simulate', 'policy:audit', 'exception:read', 'exception:write', 'exception:approve', 'release:read', 'release:write', 'release:publish', 'analytics.read', 'graph:read', 'graph:write', 'graph:admin', 'sbom:read', 'sbom:write', 'scanner:read', 'vex:read', 'vex:export', 'advisory:read', 'scheduler:read', 'scheduler:operate', 'findings:read', 'exceptions:read', ], }; /** Minimal runtime config for deterministic SPA bootstrap in E2E. */ const e2eRuntimeConfig = { setup: 'complete', authority: { issuer: 'https://127.0.0.1', clientId: 'stellaops-web-e2e', authorizeEndpoint: 'https://127.0.0.1/connect/authorize', tokenEndpoint: 'https://127.0.0.1/connect/token', logoutEndpoint: 'https://127.0.0.1/connect/logout', redirectUri: 'https://127.0.0.1/auth/callback', postLogoutRedirectUri: 'https://127.0.0.1/', scope: 'openid profile ui.read', audience: 'stellaops', dpopAlgorithms: ['ES256'], refreshLeewaySeconds: 60, }, apiBaseUrls: { authority: '', gateway: '', policy: '', scanner: '', concelier: '', attestor: '', }, telemetry: { sampleRate: 0, }, }; export const test = base.extend<{ authenticatedPage: Page }>({ authenticatedPage: async ({ page }, use) => { // Ensure APP_INITIALIZER config resolution does not hang on missing backend proxy targets. await page.route('**/platform/envsettings.json', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(e2eRuntimeConfig), }); }); await page.route('**/config.json', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(e2eRuntimeConfig), }); }); // Keep backend probe guard reachable in isolated E2E runs. await page.route('https://127.0.0.1/.well-known/openid-configuration', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ issuer: 'https://127.0.0.1', authorization_endpoint: 'https://127.0.0.1/connect/authorize', }), }); }); // Prevent background health polling from failing the shell bootstrap path. await page.route('**/health', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok' }), }); }); // Intercept branding endpoint that can return 500 in dev/Docker await page.route('**/console/branding**', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tenantId: 'tenant-default', productName: 'Stella Ops', logoUrl: null, theme: 'default', }), }); }); // Intercept OIDC authorize to prevent redirect loops await page.route('**/connect/authorize**', (route) => { route.fulfill({ status: 200, body: '' }); }); // Intercept console profile/introspect calls that fire after session seed await page.route('**/console/profile**', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ subjectId: adminTestSession.subjectId, username: 'qa-tester', displayName: 'QA Test User', tenant: adminTestSession.tenant, roles: ['admin'], scopes: adminTestSession.scopes, audiences: ['stellaops'], authenticationMethods: ['pwd'], }), }); }); await page.route('**/console/token/introspect**', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ active: true, tenant: adminTestSession.tenant, subject: adminTestSession.subjectId, clientId: 'stellaops-console', scopes: adminTestSession.scopes, audiences: ['stellaops'], }), }); }); await page.route('**/console/tenants**', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tenants: [ { id: adminTestSession.tenant, displayName: 'Default Tenant', status: 'active', isolationMode: 'shared', defaultRoles: ['admin'], }, ], }), }); }); // Inject test session via addInitScript so it is available // before any Angular code runs (APP_INITIALIZER reads it). await page.addInitScript((session: StubAuthSession) => { (window as any).__stellaopsTestSession = session; }, adminTestSession); await use(page); }, }); export { expect } from '@playwright/test'; export { adminTestSession }; export type { StubAuthSession };