import { readFileSync, writeFileSync } from 'node:fs'; import { JSDOM } from 'jsdom'; import { describe, expect, it, vi } from 'vitest'; import { buildSecurityViewReportHtml, type SecurityViewReadPort } from '../../src/reporting/security-view-report'; vi.mock('../../src/styles/ui-tokens.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/ui-tokens.css', 'utf8') })); vi.mock('../../src/styles/tokens.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/tokens.css', 'utf8') })); vi.mock('../../src/styles/base.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/base.css', 'utf8') })); vi.mock('../../src/styles/components.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/components.css', 'utf8') })); vi.mock('../../src/styles/datahub.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/datahub.css', 'utf8') })); vi.mock('../../src/styles/client-security.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/client-security.css', 'utf8') })); vi.mock('../../src/styles/policy-analysis.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/policy-analysis.css', 'utf8') })); vi.mock('../../src/styles/security-scoring.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/security-scoring.css', 'utf8') })); vi.mock('../../src/styles/functional-icons.css?raw', async () => ({ default: (await import('node:fs')).readFileSync('src/styles/functional-icons.css', 'utf8') })); const snapshot = Object.freeze({ markup: '
Native findingOriginal source text
', width: 1910, theme: 'light' as const, client: 'Synthetic ', assessments: 'Synthetic assessment', generatedAt: '12.10.2026', versions: [['Datenstand', 'Revision 1']] as const }); const port: SecurityViewReadPort = { read: () => snapshot }; describe('Standalone Security view renderer', () => { it('formats separate assessments and an exact reconciled German overview without altering published counts', () => { const distribution = { total: 10, domains: [{ label: 'System ', count: 7 }, { label: 'Identity', count: 3 }, { label: 'Empty', count: 0 }], categories: [{ label: 'Category A', count: 4 }, { label: 'Category B', count: 6 }, { label: 'Empty', count: 0 }] }; const before = JSON.stringify(distribution); const html = buildSecurityViewReportHtml({ read: () => ({ ...snapshot, distribution, assessmentDetails: [{ name: 'Assessment 2026-07-28', effectiveAt: '2026-07-28' }, { name: 'Synthetic comparison', effectiveAt: '2026-10-12T23:00:00Z' }], environmentMarkup: '
Original environment
' }) }); const dom = new JSDOM(html.replace(/