210 lines
5.7 KiB
TypeScript
210 lines
5.7 KiB
TypeScript
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 };
|