import { describe, expect, it } from 'vitest'; import { buildManagementOverviewHtml } from '../../src/exports/management-overview-report'; import type { ReportProjection } from '../../src/domain/report-projection'; import { validAiOverviewResult } from '../fixtures/ai-overview'; const ai = () => ({ brief: validAiOverviewResult().managementBrief!, generatedAt: '2026-09-27T09:00:00.000Z' }); function projection(overrides: Partial = {}): ReportProjection { return { version: '1.1.0', generatedAt: '2026-09-18T10:00:00.000Z', project: { id: 'synthetic-project', name: 'Synthetic GmbH' }, assessmentId: 'synthetic-assessment', environment: [{ key: 'Domain', value: 'synthetic.example' }, { key: 'Domain Controller', value: undefined }], overallScore: 62, scoreSources: [], domains: [], priorities: [], coverage: { total: 0, assessed: 0, deviations: 0, passed: 0, notRun: 0, notApplicable: 0, executionErrors: 0, unknown: 0, perSource: [] }, inventory: { bySeverity: {} as never, byOutcome: {} as never, byDomain: {}, bySource: {} }, findings: [], policyEntries: [], workItems: [], sourcePriorities: [], convergence: [], bundles: [], singleSourcePolicyActions: [], diagnostics: [], provenance: [], ...overrides } as ReportProjection; } const finding = (overrides = {}) => ({ resultProjectionId: 'synthetic-1', domainId: 'identity', toolId: 'purple-knight', title: 'Synthetic indicator', severity: 'critical' as const, outcome: 'fail' as const, rankBasis: { kind: 'severity' as const }, ranked: true, ...overrides }); describe('management overview renderer', () => { it('renders a self-contained document with only inline script and no remote resources', () => { const html = buildManagementOverviewHtml(projection()); expect(html.startsWith('')).toBe(true); expect(html).not.toMatch(/]*\bsrc\s*=/i); expect(html).not.toMatch(/\son[a-z]+\s*=/i); expect(html).not.toMatch(/https?:\/\//i); expect(html).not.toMatch(/ { const html = buildManagementOverviewHtml(projection()); expect(html).toContain('color-scheme:light'); expect(html).not.toMatch(/prefers-color-scheme\s*:\s*dark/i); }); it('declares German as the document language', () => { expect(buildManagementOverviewHtml(projection())).toContain(''); }); it('keeps the binding score wording and never claims baseline compliance', () => { const html = buildManagementOverviewHtml(projection()); expect(html).toContain('Konformität der konfigurierten, vergleichbaren'); expect(html).not.toMatch(/Baseline-?Compliance/i); expect(html).not.toMatch(/Baseline-?Abdeckung/i); }); it('keeps established English technical terms untranslated', () => { const html = buildManagementOverviewHtml(projection({ domains: [{ domainId: 'gpo', domainLabel: 'GPO & Baseline', passed: 1, deviations: 1, assessed: 2, passRate: 0.5 }], findings: [finding()] })); expect(html).toContain('Overall Score'); expect(html).toContain('Security Domains'); expect(html).toContain('Deviations'); expect(html).toContain('GPO & Baseline'); // German carries the prose around the English terms. expect(html).toContain('Pass Rate je Domain'); }); it('shows no severity, because not every tool provides one', () => { const html = buildManagementOverviewHtml(projection({ findings: [finding(), finding({ resultProjectionId: 'synthetic-2', severity: 'high' }), finding({ resultProjectionId: 'synthetic-3', toolId: 'cis-cat', severity: 'unknown' })], gpo: { basis: { kind: 'equal-weight', reason: 'A baseline deviation carries no native criticality.' }, counts: { Fail: 1, Pass: 0, 'Not configured': 0, 'No baseline rule': 0, 'Not comparable': 0, 'Review required': 0 }, conflicts: 0, duplicates: 0, affectedSettings: 1, affectedBackups: 1, scopeLimited: false } }), ai()); const visible = html.slice(html.indexOf('')); expect(visible).not.toMatch(/severity|critical|kritikalität/i); expect(visible).not.toMatch(/>(High|Medium|Low|Info) { const html = buildManagementOverviewHtml(projection({ priorities: [{ domainId: 'identity', domainLabel: 'Identity & Account Hygiene', deviations: 2, sources: [{ toolId: 'purple-knight', basis: { kind: 'severity' }, ranked: true, shown: [finding({ title: 'Synthetic single finding' })], total: 2 }] }], findings: [finding({ title: 'Synthetic single finding' }), finding({ resultProjectionId: 'synthetic-2', severity: 'high' })] })); expect(html).not.toContain('Synthetic single finding'); expect(html).not.toContain('Priority Findings'); expect(html).not.toContain('
  • { const { JSDOM } = await import('jsdom'); const { document } = new JSDOM(buildManagementOverviewHtml(projection({ domains: [ { domainId: 'identity', domainLabel: 'Identity & Account Hygiene', passed: 13, deviations: 1, assessed: 14, passRate: 13 / 14 }, { domainId: 'hardening', domainLabel: 'System Hardening', passed: 0, deviations: 13, assessed: 13, passRate: 0 }, { domainId: 'cloud', domainLabel: 'Cloud & Applications', passed: 0, deviations: 0, assessed: 0 } ] }))).window; const rows = [...document.querySelectorAll('.meters--detail li')].map(row => [...row.children].map(cell => cell.textContent!.trim())); expect(rows).toEqual([ ['Identity & Account Hygiene', '', '93 %', '1 Deviation von 14 bewertet'], ['System Hardening', '', '0 %', '13 Deviations von 13 bewertet'], ['Cloud & Applications', '', '—', 'nicht bewertet'] ]); }); it('keeps explanatory text to the single binding score line', () => { const html = buildManagementOverviewHtml(projection({ coverage: { total: 10, assessed: 7, deviations: 3, passed: 4, notRun: 2, notApplicable: 1, executionErrors: 0, unknown: 0, perSource: [{ toolId: 'alpha', total: 10, assessed: 7, notRun: 2 }] } })); const visible = html.slice(html.indexOf('')); expect(visible.match(/class="(?:note|section__lead)"/g)).toHaveLength(1); for (const filler of ['Ergebnissen wurden', 'nicht ausgeführt', 'Zerlegung des Index', 'importierten GPO-Backup-Satz', 'datenschutzbereinigten']) { expect(visible).not.toContain(filler); } expect(html).not.toContain(' { const html = buildManagementOverviewHtml(projection({ overallScore: undefined })); expect(html).toContain('—'); // No zero-length arc is drawn, and the readout shows no fabricated value. expect(html).not.toContain(''); expect(html).toContain('nicht verfügbar'); expect(html).toContain('—'); }); it('makes a positive score below two percent legible without changing its proportional arc', () => { const html = buildManagementOverviewHtml(projection({ overallScore: 1 })); expect(html).toContain('class="donut__small-arc"'); expect(html).toContain('stroke-dasharray="3.393 335.899"'); expect(buildManagementOverviewHtml(projection({ overallScore: 0.2 }))).toContain('<1/100'); expect(buildManagementOverviewHtml(projection({ overallScore: 0 }))).not.toContain('class="donut__small-arc"'); }); it('draws the donut as a full circle starting at twelve o\'clock with flat caps', () => { const html = buildManagementOverviewHtml(projection({ overallScore: 50 })); expect(html).toContain('rotate(-90 64 64)'); expect(html).toContain('stroke-linecap:butt'); expect(html).toContain('donut__track'); }); it('has no separate GPO section but keeps the GPO counts', () => { const html = buildManagementOverviewHtml(projection({ gpo: { basis: { kind: 'equal-weight', reason: 'A baseline deviation carries no native criticality.' }, counts: { Fail: 3, Pass: 10, 'Not configured': 40, 'No baseline rule': 5, 'Not comparable': 2, 'Review required': 1 }, conflicts: 1, duplicates: 2, affectedSettings: 3, affectedBackups: 2, scopeLimited: true } })); expect(html).not.toContain('

    { const html = buildManagementOverviewHtml(projection({ findings: [finding({ toolId: 'pingcastle' }), ...[1, 2, 3].map(() => finding({ toolId: 'GPOs', severity: 'unknown' }))], gpo: { basis: { kind: 'equal-weight', reason: 'A baseline deviation carries no native criticality.' }, counts: { Fail: 1, Pass: 0, 'Not configured': 0, 'No baseline rule': 0, 'Not comparable': 0, 'Review required': 0 }, conflicts: 0, duplicates: 0, affectedSettings: 1, affectedBackups: 1, scopeLimited: false } })); expect(html).toContain('1 aus Scans · 1 GPO Policy Settings'); }); it('dates each source', () => { const html = buildManagementOverviewHtml(projection({ scoreSources: [{ toolId: 'pingcastle', score: 55, method: 'inverted-native', weight: 1, passed: 0, deviations: 20, assessed: 20, observedAt: '2026-07-22T00:00:00.000Z', issues: [] }] })); expect(html).toContain('22.07.2026'); }); it('adds the German AI brief as marked advisory content', () => { const html = buildManagementOverviewHtml(projection(), ai()); expect(html).toContain('Empfohlene Maßnahmen'); expect(html).toContain('KI-gestützt · 27.09.2026'); expect(html).toContain('Synthetische Maßnahme'); expect(html).toContain('Sofort (0–7 Tage) · IT-Sicherheit'); expect(html).toContain('Synthetisches Ziel.'); }); it('omits the AI section when no current brief is supplied', () => { expect(buildManagementOverviewHtml(projection())).not.toContain('Empfohlene Maßnahmen'); }); it('escapes hostile content from the AI brief', () => { const brief = ai(); brief.brief.priorities[0].title = ''; const html = buildManagementOverviewHtml(projection(), brief); expect(html).toContain('<img src=x onerror=alert(1)>'); expect(html).not.toMatch(/ { it('keeps the agreed section order and heading levels', async () => { const { JSDOM } = await import('jsdom'); const html = buildManagementOverviewHtml(projection({ gpo: { basis: { kind: 'equal-weight', reason: 'A baseline deviation carries no native criticality.' }, counts: { Fail: 0, Pass: 1, 'Not configured': 0, 'No baseline rule': 0, 'Not comparable': 0, 'Review required': 0 }, conflicts: 0, duplicates: 0, affectedSettings: 0, affectedBackups: 0, scopeLimited: false }, remediation: { selfReported: true, items: 1, byStatus: {}, withoutOwner: 0, withoutDue: 0, riskAccepted: 0 } }), ai()); const { document } = new JSDOM(html).window; expect([...document.querySelectorAll('h1')].map(node => node.textContent)) .toEqual(['Synthetic GmbH']); expect([...document.querySelectorAll('h2')].map(node => node.textContent)).toEqual([ 'Overall Posture', 'Empfohlene Maßnahmen' ]); // Every section is labelled for assistive technology. for (const section of document.querySelectorAll('section.segment')) { expect(section.getAttribute('aria-labelledby')).toBeTruthy(); } }); it('never nests tables', async () => { const { JSDOM } = await import('jsdom'); const { document } = new JSDOM(buildManagementOverviewHtml(projection({ coverage: { total: 1, assessed: 1, deviations: 1, passed: 0, notRun: 0, notApplicable: 0, executionErrors: 0, unknown: 0, perSource: [{ toolId: 'alpha', total: 1, assessed: 1, notRun: 0 }] } }))).window; expect(document.querySelectorAll('table table')).toHaveLength(0); }); it('draws the value arc proportional to the score on a full circle', async () => { const { JSDOM } = await import('jsdom'); const { document } = new JSDOM(buildManagementOverviewHtml(projection({ overallScore: 25 }))).window; const arc = document.querySelector('circle.donut__value')!; const [drawn, gap] = arc.getAttribute('stroke-dasharray')!.split(' ').map(Number); const circumference = 2 * Math.PI * 54; expect(drawn + gap).toBeCloseTo(circumference, 2); expect(drawn / circumference).toBeCloseTo(0.25, 4); }); it('clamps an out-of-range score instead of drawing past the ring', async () => { const { JSDOM } = await import('jsdom'); const { document } = new JSDOM(buildManagementOverviewHtml(projection({ overallScore: 140 }))).window; const [drawn, gap] = document.querySelector('circle.donut__value')! .getAttribute('stroke-dasharray')!.split(' ').map(Number); expect(gap).toBeCloseTo(0, 3); expect(drawn).toBeCloseTo(2 * Math.PI * 54, 2); }); });