// @vitest-environment jsdom import { createElement } from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; import cisCatFixture from '../../fixtures/cis-cat/assessment.synthetic.html?raw'; import futureControlsFixture from '../../fixtures/cis-cat/assessment.future-controls.synthetic.html?raw'; import type { FindingRecord } from '../../src/domain/finding'; import { importFile } from '../../src/importers/importer'; import { makeSheet } from '../../src/importers/sheet-factory'; import { toolIdForRecord } from '../../src/importers/status-normalization'; import { genericProfile } from '../../src/profiles/generic/generic-profile'; import { FloatingResultsWindow } from '../../src/features/linked-results/FloatingResultsWindow'; import { resultSectionsFor } from '../../src/features/linked-results/result-message'; import { linkResultSheets } from '../../src/profiles/purple-knight/result-linker'; const options = { profiles: [genericProfile] }; /** * Vertrag des Results-Fensters fuer CIS-CAT, von der importierten Datei bis zur * gerenderten Ausgabe: die Belegdaten des Berichts - Assessment Evidence und * die Rahmenwerk-Zuordnungen hinter "More" - stehen im Fenster, mit der * Ueberschrift des Berichts. Das Rule Result XML gehoert nicht dorthin, * sondern bleibt ein aufklappbares Detail im Finding. */ async function resultsWindowMarkup(html: string, fileName: string) { const imported = await importFile(new File([html], fileName, { type: 'text/html' }), options); const findings = imported.sheets.find(sheet => sheet.name === 'assessmentResultTable')!; const candidate = imported.extraction!.candidates[0]; const record: FindingRecord = { id: 'cis-cat-record', index: 0, title: String(candidate.fields.find(field => field.label === 'Benchmark Item')?.decodedValue ?? ''), fields: candidate.fields.map((field, index) => ({ index, label: field.label, value: String(field.decodedValue) })), filled: [], meta: [] }; record.fields.push({ index: record.fields.length, label: 'Source: Scan', value: 'CIS-CAT Pro \u00b7 2026-08-02T00:00:00.000Z' }); return renderToStaticMarkup(createElement(FloatingResultsWindow, { id: 'cis-cat-results', title: 'Results (1) \u2013 ' + record.title, sheets: linkResultSheets(record, imported.sheets, findings.id), toolId: toolIdForRecord(record, 'generic'), sections: resultSectionsFor(record, 'cis-cat'), color: '#7c3aed', zIndex: 2100, offset: 0, search: '', onActivate: () => undefined, onClose: () => undefined, onToggleMinimize: () => undefined })); } describe('CIS-CAT Results-Fenster', () => { it('zeigt versteckte Belegtabellen und Rahmenwerk-Zuordnungen gemeinsam', async () => { const markup = await resultsWindowMarkup(cisCatFixture, 'CIS-CAT-SYNTHETIC.html'); // Hinter "Show Assessment Evidence" versteckte Tabellen. expect(markup.match(/>Assessment<\/h4>/g)).toHaveLength(1); // Hinter "More" versteckte Steuerungstabellen, je Rahmenwerk benannt. expect(markup).toContain('>CIS Controls V7.0'); expect(markup).toContain('>CIS Critical Security Controls V8.0'); // Die Zuordnungsliste wird in Tabellenueberschriften ueberfuehrt. expect(markup).not.toContain('>Control Mappings'); expect(markup).toContain('>Control 1: Synthetic Inventory'); expect(markup).toContain('>Control 2: Synthetic Assets'); expect(markup).toContain('Control 1: Synthetic Inventory'); expect(markup).not.toContain('Keine passende Ergebnisdatei automatisch gefunden.'); }); /** * Nutzerkorrektur vom 2026-07-31: Das Rule Result XML fuellte das Fenster vor * den eigentlichen Belegtabellen. Es bleibt ein aufklappbares Detail im * Finding und darf im Fenster an keiner Stelle auftauchen. */ it('markiert den Assessment-Hinweis als ausgewertete blaue Zeile', () => { const noteSheet = makeSheet( 'Assessment Evidence \u00b7 Hinweis', [['No matching system items were found.']], '', 'synthetic-cis-cat.html' ); const markup = renderToStaticMarkup(createElement(FloatingResultsWindow, { id: 'cis-cat-note', title: 'Results (1) \u2013 Synthetic assessment', sheets: [noteSheet], toolId: 'cis-cat', sections: [], color: '#7c3aed', zIndex: 2100, offset: 0, search: '', onActivate: () => undefined, onClose: () => undefined, onToggleMinimize: () => undefined })); expect(markup).toContain('