Assessor_2.0/tests/features/sidebar-security-domains.te...

90 lines
4.4 KiB
TypeScript

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(<DynamicFilterControls facets={[severityFacet]}
filters={{ [severityFacet.id]: { values: ['info', 'low', 'medium', 'high', 'critical'] } }}
statusFilter="deviation" onStatusFilter={() => 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(<DynamicFilterControls facets={facets} filters={{}} statusFilter="all"
onStatusFilter={() => undefined} onFilter={() => undefined}/>);
expect(facets.at(-1)?.label).toBe('Source: Scan');
expect(html).toContain('dynamic-facet-select is-source-scan');
});
});