import { renderToStaticMarkup } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; import { makeSheet } from '../../src/importers/sheet-factory'; import { genericProfile } from '../../src/profiles/generic/generic-profile'; import { securityDomainCatalog } from '../../src/features/dashboard/security-domains'; import { summarizeSecurityDomains, toggleSecurityDomainSelection } from '../../src/features/sidebar/SidebarSecurityDomains'; import { deriveDynamicFacets } from '../../src/features/search-filter/dynamic-facets'; import { compactSeveritySelection, DynamicFilterControls } from '../../src/features/search-filter/DynamicFilterControls'; const rows = [ ['Title', 'Severity', 'Result'], ['Inactive account', 'Critical', 'Failed'], ['Privileged administrator', 'High', 'Failed'], ['MFA disabled', 'High', 'Failed'], ['Certificate expired', 'Medium', 'Failed'], ['Firewall disabled', 'Low', 'Failed'], ['GPO baseline deviation', 'High', 'Failed'], ['Cloud application exposed', 'High', 'Failed'], ['Backup unavailable', 'Low', 'Failed'], ['Unmatched finding', 'Info', 'Failed'], ['Account passed', 'Medium', 'Passed'] ]; function options(statusFilter = 'deviation', facetFilters = {}) { return { sheet: makeSheet('Synthetic findings', rows, '', 'synthetic.csv'), dataset: null, activeProfile: genericProfile, reviews: {}, statusFilter, facetFilters, search: '', actionOnly: false }; } describe('sidebar security domains', () => { it('uses the exact Client Info catalog order and adds Unclassified only when present', () => { const summary = summarizeSecurityDomains(options()); expect(summary?.domains.map(domain => domain.label)).toEqual([ ...securityDomainCatalog.map(domain => domain.label), 'Unclassified' ]); expect(summary?.domains.map(domain => domain.count)).toEqual([1, 1, 1, 1, 1, 1, 1, 1, 1]); }); it('keeps all eight catalog domains selectable at zero hits and follows active filters', () => { const summary = summarizeSecurityDomains(options('passed')); expect(summary?.domains.slice(0, 8).map(domain => domain.id)).toEqual(securityDomainCatalog.map(domain => domain.id)); expect(summary?.domains.find(domain => domain.id === 'identity')?.count).toBe(1); expect(summary?.domains.filter(domain => domain.id !== 'identity').every(domain => domain.count === 0)).toBe(true); }); it('uses single selection and clears the active domain on a second click', () => { expect(toggleSecurityDomainSelection([], 'identity')).toEqual(['identity']); expect(toggleSecurityDomainSelection(['identity'], 'gpo')).toEqual(['gpo']); expect(toggleSecurityDomainSelection(['gpo'], 'gpo')).toEqual([]); }); it('does not render a rack without an active sheet', () => { expect(summarizeSecurityDomains({ ...options(), sheet: undefined })).toBeUndefined(); }); }); describe('Work filter controls retained beside the sidebar domain filter', () => { it('renders a compact multi-severity label in the filter control', () => { const base = options(); const severityFacet = deriveDynamicFacets(base.sheet, null, genericProfile, {}) .find(facet => facet.severityScale); if (!severityFacet) throw new Error('Synthetic severity facet missing'); const html = renderToStaticMarkup( undefined} onFilter={() => undefined}/>); expect(compactSeveritySelection(['info', 'critical', 'medium'])).toBe('Crit-Med-Inf'); expect(html).toContain('Crit-High-Med-Low-Inf'); expect(html).toContain('value="__severity_multi__" selected=""'); }); it('keeps Source: Scan as the final right-edge filter control', () => { const scanSheet = makeSheet('Synthetic findings', [ ['Title', 'Severity', 'Source: Scan'], ['One', 'High', 'Scanner A'], ['Two', 'Low', 'Scanner B'] ], '', 'synthetic.csv'); const facets = deriveDynamicFacets(scanSheet, null, genericProfile, {}); const html = renderToStaticMarkup( undefined} onFilter={() => undefined}/>); expect(facets.at(-1)?.label).toBe('Source: Scan'); expect(html).toContain('dynamic-facet-select is-source-scan'); }); });