Files
git.stella-ops.org/src/Web/StellaOps.Web/tests/e2e/smoke.spec.ts
2026-02-21 19:10:28 +02:00

182 lines
5.4 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test';
import { policyAuthorSession } from '../../src/app/testing';
const mockConfig = {
authority: {
issuer: 'https://authority.local',
clientId: 'stella-ops-ui',
authorizeEndpoint: 'https://authority.local/connect/authorize',
tokenEndpoint: 'https://authority.local/connect/token',
logoutEndpoint: 'https://authority.local/connect/logout',
redirectUri: 'http://127.0.0.1:4400/auth/callback',
postLogoutRedirectUri: 'http://127.0.0.1:4400/',
scope: 'openid profile email ui.read findings:read',
audience: 'https://scanner.local',
dpopAlgorithms: ['ES256'],
refreshLeewaySeconds: 60,
},
apiBaseUrls: {
authority: 'https://authority.local',
scanner: 'https://scanner.local',
policy: 'https://policy.local',
concelier: 'https://concelier.local',
attestor: 'https://attestor.local',
gateway: 'https://gateway.local',
},
quickstartMode: true,
setup: 'complete',
};
const oidcConfig = {
issuer: mockConfig.authority.issuer,
authorization_endpoint: mockConfig.authority.authorizeEndpoint,
token_endpoint: mockConfig.authority.tokenEndpoint,
jwks_uri: 'https://authority.local/.well-known/jwks.json',
response_types_supported: ['code'],
subject_types_supported: ['public'],
id_token_signing_alg_values_supported: ['RS256'],
};
const shellSession = {
...policyAuthorSession,
scopes: [
...new Set([
...policyAuthorSession.scopes,
'ui.read',
'admin',
'ui.admin',
'orch:read',
'orch:operate',
'orch:quota',
'findings:read',
'vuln:view',
'vuln:investigate',
'vuln:operate',
'vuln:audit',
'authority:tenants.read',
'advisory:read',
'vex:read',
'exceptions:read',
'exceptions:approve',
'aoc:verify',
'policy:read',
'policy:author',
'policy:review',
'policy:approve',
'policy:simulate',
'policy:audit',
'health:read',
'notify:viewer',
'release:read',
'release:write',
'release:publish',
'sbom:read',
'signer:read',
]),
],
};
async function setupBasicMocks(page: Page) {
page.on('console', (message) => {
if (message.type() === 'error') {
console.log('[browser:error]', message.text());
}
});
await page.route('**/config.json', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockConfig),
}),
);
await page.route('**/platform/envsettings.json', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockConfig),
}),
);
await page.route('https://authority.local/**', (route) => {
const url = route.request().url();
if (url.includes('/.well-known/openid-configuration')) {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(oidcConfig),
});
}
if (url.includes('/.well-known/jwks.json')) {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ keys: [] }),
});
}
if (url.includes('authorize')) {
return route.abort();
}
return route.fulfill({ status: 400, body: 'blocked' });
});
}
async function setupAuthenticatedSession(page: Page) {
await page.addInitScript((stubSession) => {
(window as any).__stellaopsTestSession = stubSession;
}, shellSession);
}
test.describe('Authentication smoke', () => {
test.beforeEach(async ({ page }) => {
await setupBasicMocks(page);
});
test('sign in button is visible on welcome page', async ({ page }) => {
await page.goto('/welcome');
await expect(page.getByRole('button', { name: /sign in/i })).toBeVisible();
});
test('clicking sign in starts authority authorization flow', async ({ page }) => {
await page.goto('/welcome');
const signInButton = page.getByRole('button', { name: /sign in/i });
await expect(signInButton).toBeVisible();
const [request] = await Promise.all([
page.waitForRequest('https://authority.local/connect/authorize*'),
signInButton.click({ noWaitAfter: true }),
]);
expect(request.url()).toContain('authority.local/connect/authorize');
});
});
test.describe('Authenticated shell smoke', () => {
test.beforeEach(async ({ page }) => {
await setupBasicMocks(page);
await setupAuthenticatedSession(page);
});
test('mission board renders for authenticated session', async ({ page }) => {
await page.goto('/');
await expect(page.locator('aside.sidebar')).toBeVisible({ timeout: 15000 });
await expect(page.getByRole('heading', { level: 1, name: /dashboard/i })).toBeVisible({
timeout: 15000,
});
});
test('canonical root workspaces are user-reachable', async ({ page }) => {
const routes = ['/mission-control/board', '/releases', '/security', '/evidence', '/ops', '/setup'];
for (const route of routes) {
await page.goto(route);
await expect(page.locator('aside.sidebar')).toBeVisible({ timeout: 15000 });
await expect(page.locator('main')).toBeVisible({ timeout: 15000 });
const main = page.locator('main');
const mainText = ((await main.textContent()) ?? '').trim();
const nodeCount = await main.locator('*').count();
expect(mainText.length > 0 || nodeCount > 0).toBe(true);
}
});
});