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.each(['light', 'dark'] as const)('retains native script-free category navigation and independent maximizable popups (%s)', theme => { const markup = 'Show synthetic category
Synthetic overview
Synthetic category
Original synthetic finding
Synthetic footer
'; const popups = ''; const html = buildSecurityViewReportHtml({ read: () => ({ ...snapshot, theme, markup, popups }) }); expect(html).not.toMatch(/'); expect(html).toContain('overscroll-behavior:contain'); expect(html).toContain('100vw * 2 / 3'); expect(html).not.toContain('zoom:'); expect(html).toContain('font-size:var(--type-table-body-size)'); expect(html).toContain('@container security-report (max-width:1800px)'); expect(html).toContain('.client-security-map-scroll>svg{width:1280px;max-width:none}'); expect(html).toContain('html,body{background:var(--surface-panel)}'); expect(html).toContain('grid-template-columns:repeat(5,minmax(0,1fr))'); expect(html).toContain('aria-label="Maximize popup"'); expect(html.indexOf('aria-label="Maximize popup"')).toBeLessThan(html.indexOf('aria-label="Close synthetic results"')); expect(html).toContain('Original synthetic finding'); const dom = new JSDOM(html.replace(/