import { describe, expect, it } from 'vitest'; import { makeSheet } from '../../src/importers/sheet-factory'; import { deriveDynamicFacets, matchesDynamicFacets } from '../../src/features/search-filter/dynamic-facets'; import { genericProfile } from '../../src/profiles/generic/generic-profile'; /** * Synthetisch, aber in der Schreibweise absichtlich so uneinheitlich wie die * echten Quellen: dieselbe Stufe erscheint als "info" und als "Informational", * und die Gross-/Kleinschreibung wechselt je Werkzeug. */ const rows = [ ['Title', 'Severity', 'Result'], ['Fund 1', 'Critical', 'Failed'], ['Fund 2', 'High', 'Failed'], ['Fund 3', 'high', 'Failed'], ['Fund 4', 'medium', 'Failed'], ['Fund 5', 'medium', 'Failed'], ['Fund 6', 'medium', 'Failed'], ['Fund 7', 'low', 'Failed'], ['Fund 8', 'info', 'Failed'], ['Fund 9', 'Informational', 'Failed'], ['Fund 10', 'Informational', 'Failed'] ]; /** * Ohne Dataset bleibt die Feldrolle unbestimmt - genau der Fall, der in der * Projektaggregation eines Mandanten auftritt. Die Facette muss trotzdem als * Severity-Skala erkannt werden, sonst greift die Zusammenfassung nie. */ function severityFacet() { const sheet = makeSheet('blatt', rows, '', 'datei.csv'); const facets = deriveDynamicFacets(sheet, null, genericProfile, {}); const facet = facets.find(item => item.severityScale); if (!facet) throw new Error('Schweregrad-Facette fehlt'); expect(facet.role).toBeUndefined(); return { sheet, facet }; } describe('Schweregrad-Facette', () => { it('ordnet nach fachlicher Rangfolge, nicht nach Haeufigkeit oder Alphabet', () => { const { facet } = severityFacet(); expect(facet.values.map(value => value.value)).toEqual(['critical', 'high', 'medium', 'low', 'info']); }); /** * Regression: "info" und "Informational" standen als zwei Eintraege * nebeneinander, obwohl sie dieselbe kanonische Stufe meinen. */ it('fasst abweichende Schreibweisen derselben Stufe zusammen', () => { const { facet } = severityFacet(); const info = facet.values.filter(value => value.value === 'info'); expect(info).toHaveLength(1); expect(info[0].count).toBe(3); expect(facet.values.find(value => value.value === 'high')?.count).toBe(2); }); it('zeigt je Stufe genau einen Anzeigenamen', () => { const { facet } = severityFacet(); expect(facet.values.map(value => value.label)).toEqual(['Critical', 'High', 'Medium', 'Low', 'Info']); }); it('filtert ueber die kanonische Stufe und trifft damit jede Schreibweise', () => { const { sheet, facet } = severityFacet(); const selected = sheet.analysis.records.filter(record => matchesDynamicFacets(record, [facet], { [facet.id]: { values: ['info'] } }, {})); expect(selected).toHaveLength(3); const highs = sheet.analysis.records.filter(record => matchesDynamicFacets(record, [facet], { [facet.id]: { values: ['high'] } }, {})); expect(highs).toHaveLength(2); }); });