157 lines
5.9 KiB
TypeScript
157 lines
5.9 KiB
TypeScript
/**
|
|
* Extended Route Rendering Tests — Batch 2 (40 routes)
|
|
*
|
|
* Tests additional SPA routes beyond the critical set.
|
|
* Same verification pattern: navigate, check content, check for NG errors.
|
|
*/
|
|
|
|
import { test, expect } from '../fixtures/auth.fixture';
|
|
import { navigateAndWait, assertPageHasContent } from '../helpers/nav.helper';
|
|
|
|
function setupErrorCollector(page: import('@playwright/test').Page) {
|
|
const errors: string[] = [];
|
|
page.on('console', (msg) => {
|
|
const text = msg.text();
|
|
if (msg.type() === 'error' && /NG0\d{3,4}/.test(text)) {
|
|
errors.push(text);
|
|
}
|
|
});
|
|
return errors;
|
|
}
|
|
|
|
const EXTENDED_ROUTES: { path: string; name: string }[] = [
|
|
// Legacy routes
|
|
{ path: '/environments', name: 'Environments' },
|
|
{ path: '/home', name: 'Home Dashboard (legacy)' },
|
|
{ path: '/dashboard/sources', name: 'Sources Dashboard' },
|
|
{ path: '/console/status', name: 'Console Status' },
|
|
{ path: '/console/admin', name: 'Console Admin' },
|
|
{ path: '/console/configuration', name: 'Configuration' },
|
|
|
|
// JobEngine (legacy paths)
|
|
{ path: '/jobengine', name: 'JobEngine (legacy)' },
|
|
{ path: '/jobengine/jobs', name: 'JobEngine Jobs' },
|
|
{ path: '/jobengine/quotas', name: 'JobEngine Quotas' },
|
|
{ path: '/release-jobengine', name: 'Release JobEngine' },
|
|
|
|
// Policy Studio
|
|
{ path: '/policy-studio/packs', name: 'Policy Studio Packs' },
|
|
|
|
// Module-specific routes
|
|
{ path: '/concelier/trivy-db-settings', name: 'Trivy DB Settings' },
|
|
{ path: '/risk', name: 'Risk Dashboard' },
|
|
{ path: '/graph', name: 'Graph Explorer' },
|
|
{ path: '/lineage', name: 'Lineage' },
|
|
{ path: '/reachability', name: 'Reachability Center' },
|
|
{ path: '/timeline', name: 'Timeline' },
|
|
{ path: '/evidence-thread', name: 'Evidence Thread' },
|
|
|
|
// Vulnerability routes
|
|
{ path: '/vulnerabilities', name: 'Vulnerability Explorer' },
|
|
{ path: '/vulnerabilities/triage', name: 'Vulnerability Triage' },
|
|
|
|
// Triage routes
|
|
{ path: '/triage/inbox', name: 'Triage Inbox' },
|
|
{ path: '/triage/artifacts', name: 'Triage Artifacts' },
|
|
{ path: '/triage/quiet-lane', name: 'Quiet Lane' },
|
|
{ path: '/triage/ai-recommendations', name: 'AI Recommendations' },
|
|
|
|
// Notify & Admin
|
|
{ path: '/notify', name: 'Notify Panel' },
|
|
{ path: '/admin/notifications', name: 'Admin Notifications' },
|
|
|
|
// Ops routes
|
|
{ path: '/ops/feeds', name: 'Feed Mirror' },
|
|
{ path: '/ops/signals', name: 'Signals Dashboard' },
|
|
{ path: '/ops/packs', name: 'Pack Registry Browser' },
|
|
{ path: '/admin/policy/governance', name: 'Policy Governance Admin' },
|
|
{ path: '/admin/policy/simulation', name: 'Policy Simulation Admin' },
|
|
{ path: '/scheduler', name: 'Scheduler' },
|
|
{ path: '/exceptions', name: 'Exceptions' },
|
|
|
|
// More admin routes
|
|
{ path: '/admin/registries', name: 'Registry Admin' },
|
|
{ path: '/admin/issuers', name: 'Issuer Trust' },
|
|
{ path: '/ops/scanner', name: 'Scanner Ops' },
|
|
{ path: '/ops/offline-kit', name: 'Offline Kit' },
|
|
{ path: '/ops/aoc', name: 'AOC Compliance' },
|
|
{ path: '/admin/audit', name: 'Audit Log' },
|
|
|
|
// Welcome page (no auth)
|
|
{ path: '/welcome', name: 'Welcome Page' },
|
|
];
|
|
|
|
test.describe('Extended Route Rendering (Batch 2)', () => {
|
|
for (const route of EXTENDED_ROUTES) {
|
|
test(`renders ${route.name} (${route.path})`, async ({ authenticatedPage: page }) => {
|
|
const ngErrors = setupErrorCollector(page);
|
|
|
|
await navigateAndWait(page, route.path, { timeout: 30_000 });
|
|
await page.waitForTimeout(2000);
|
|
|
|
await assertPageHasContent(page);
|
|
|
|
expect(
|
|
ngErrors,
|
|
`Angular errors on ${route.path}: ${ngErrors.join('\n')}`
|
|
).toHaveLength(0);
|
|
});
|
|
}
|
|
});
|
|
|
|
test.describe('Extended Route — Deep Paths', () => {
|
|
const DEEP_PATHS: { path: string; name: string }[] = [
|
|
{ path: '/ops/quotas', name: 'Quota Dashboard' },
|
|
{ path: '/ops/jobengine/dead-letter', name: 'Dead Letter Queue' },
|
|
{ path: '/ops/jobengine/slo', name: 'SLO Burn Rate' },
|
|
{ path: '/ops/health', name: 'Platform Health' },
|
|
{ path: '/ops/doctor', name: 'Doctor Diagnostics' },
|
|
{ path: '/ops/agents', name: 'Agent Fleet' },
|
|
{ path: '/analyze/unknowns', name: 'Unknowns Tracking' },
|
|
{ path: '/analyze/patch-map', name: 'Patch Map Explorer' },
|
|
{ path: '/ops/binary-index', name: 'Binary Index Ops' },
|
|
{ path: '/settings/determinization-config', name: 'Determinization Config' },
|
|
{ path: '/sbom-sources', name: 'SBOM Sources' },
|
|
{ path: '/sbom/diff', name: 'SBOM Diff' },
|
|
{ path: '/deploy/diff', name: 'Deploy Diff' },
|
|
{ path: '/vex/timeline', name: 'VEX Timeline' },
|
|
{ path: '/workspace/dev', name: 'Developer Workspace' },
|
|
{ path: '/workspace/audit', name: 'Auditor Workspace' },
|
|
{ path: '/ai/autofix', name: 'AI Autofix' },
|
|
{ path: '/ai/chat', name: 'AI Chat' },
|
|
{ path: '/ai/chips', name: 'AI Chips Showcase' },
|
|
{ path: '/ai-runs', name: 'AI Runs' },
|
|
{ path: '/change-trace', name: 'Change Trace' },
|
|
{ path: '/aoc/verify', name: 'AOC Verification' },
|
|
{ path: '/audit/reasons', name: 'Audit Reasons' },
|
|
{ path: '/triage/audit-bundles', name: 'Triage Audit Bundles' },
|
|
];
|
|
|
|
for (const route of DEEP_PATHS) {
|
|
test(`renders ${route.name} (${route.path})`, async ({ authenticatedPage: page }) => {
|
|
const ngErrors = setupErrorCollector(page);
|
|
|
|
await navigateAndWait(page, route.path, { timeout: 30_000 });
|
|
await page.waitForTimeout(2000);
|
|
|
|
await assertPageHasContent(page);
|
|
|
|
expect(
|
|
ngErrors,
|
|
`Angular errors on ${route.path}: ${ngErrors.join('\n')}`
|
|
).toHaveLength(0);
|
|
});
|
|
}
|
|
});
|
|
|
|
test.describe('Setup Wizard Route (no auth required)', () => {
|
|
test('renders setup page', async ({ page }) => {
|
|
// Setup wizard does NOT need auth — test with bare page
|
|
await page.goto('/setup', { waitUntil: 'networkidle', timeout: 30_000 });
|
|
await page.waitForTimeout(2000);
|
|
|
|
const bodyText = await page.locator('body').innerText();
|
|
expect(bodyText.trim().length).toBeGreaterThan(10);
|
|
});
|
|
});
|