Assessor_2.0/tests/features/tile-card.test.ts

169 lines
7.9 KiB
TypeScript

import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
import type { FindingRecord } from '../../src/domain/finding';
import { compactTileBadges, tileBadges, TileCard } from '../../src/components/TileCard/TileCard';
import { policyFindingCategories } from '../../src/profiles/group-policy/categories';
const record: FindingRecord = {
id: 'tile-1',
index: 0,
title: 'Enterprise applications using SAML for SSO',
fields: [
{ index: 0, label: 'Score', value: '86' },
{ index: 1, label: 'Severity', value: 'Low' },
{ index: 2, label: 'Weight', value: '2' },
{ index: 3, label: 'Category', value: 'Entra ID' },
{ index: 4, label: 'Result', value: 'IOE Found' }
],
filled: [],
meta: []
};
describe('tileBadges', () => {
it('uses the same GPO categories as the detail view and also shows scope', () => {
const gpo: FindingRecord = { ...record, title: 'system access · minimumpasswordlength', fields: [
{ index: 0, label: 'Category', value: 'GPOs' }, { index: 1, label: 'Scope', value: 'computer' },
{ index: 2, label: 'Baseline', value: 'Windows Server 2022 Security Baseline' }, { index: 3, label: 'Status', value: 'Fail' }
] };
const badges = tileBadges(gpo, 'group-policy');
expect(badges.filter(b => b.label === 'GPO Category').map(b => b.text)).toEqual(policyFindingCategories(gpo, 'group-policy'));
expect(badges.map(b => b.text)).toEqual(['Fail', 'GPOs', 'Windows', 'Security', 'System Access', 'Password Policy', 'Scope: computer']);
const html = renderToStaticMarkup(createElement(TileCard, { record: gpo, title: gpo.title, bookmarked: false, toolId: 'group-policy', onOpen() {}, onBookmark() {} }));
for (const category of ['Windows', 'Security', 'System Access', 'Password Policy']) expect(html).toContain(`data-badge-role="category">${category}</span>`);
expect(html).toContain('data-badge-role="scope">Scope: computer</span>');
expect(html).not.toContain('tile-badge-overflow');
});
it('recognizes GPOs in a mixed-tool tile grid', () => {
const gpo: FindingRecord = { ...record, title: 'privilege rights · senetworklogonright', fields: [
{ index: 0, label: 'Source: Scan', value: 'GPOs · Synthetic' }, { index: 1, label: 'Scope', value: 'user' }
] };
expect(tileBadges(gpo, 'generic').map(b => b.text)).toEqual(['Security', 'Privilege Rights', 'Logon Rights', 'Scope: user']);
});
it('deduplicates categories but keeps an explicitly named scope', () => {
const gpo: FindingRecord = { ...record, fields: [
{ index: 0, label: 'Category', value: 'Office' }, { index: 1, label: 'Baseline', value: 'Office 2016 Security Baseline' },
{ index: 2, label: 'Scope', value: 'computer' }, { index: 3, label: 'Scope', value: 'computer' }
] };
expect(tileBadges(gpo, 'group-policy').map(b => b.text)).toEqual(['Office', 'Scope: computer']);
});
it('does not add GPO badges to other tools or invent missing scope', () => {
const other: FindingRecord = { ...record, fields: [
{ index: 0, label: 'Scope', value: 'computer' }, { index: 1, label: 'Baseline', value: 'Windows 11 Security Baseline' }
] };
expect(tileBadges(other, 'purple-knight')).toEqual([]);
expect(tileBadges({ ...other, fields: [] }, 'group-policy')).toEqual([]);
});
it('places Severity immediately after Status independently of source-column order', () => {
expect(tileBadges(record).map(badge => badge.text)).toEqual([
'IOE Found',
'Low',
'Entra ID',
'Weight: 2',
'Score: 86'
]);
});
it('only prefixes weight and score and applies severity styling to severity', () => {
const badges = tileBadges(record);
expect(badges.find(badge => badge.label === 'Category')?.text).toBe('Entra ID');
expect(badges.find(badge => badge.label === 'Severity')?.severity).toBe('low');
});
it('filters out Maester result message from status badge', () => {
const maesterRecord: FindingRecord = {
id: 'maester-1',
index: 0,
title: 'Ensure all users can complete multifactor authentication',
fields: [
{ index: 0, label: 'Severity', value: 'High' },
{ index: 1, label: 'Status', value: 'Failed' },
{ index: 2, label: 'Result', value: 'You have 52 of 78 users that aren\'t registered for MFA | --- | --- | Fail | ...' }
],
filled: [],
meta: []
};
const badges = tileBadges(maesterRecord, 'maester');
expect(badges.find(badge => badge.label === 'Status')?.text).toBe('Failed');
});
it('zeigt bei Purple Knight Status statt des SI-Verweises aus Result', () => {
const projected: FindingRecord = {
...record,
fields: [
{ index: 0, label: 'Result', value: 'SI000067' },
{ index: 1, label: 'Status', value: 'Pass' },
{ index: 2, label: 'ShortName', value: 'SI000067' }
]
};
expect(tileBadges(projected, 'purple-knight').find(badge => badge.label === 'Status')?.text).toBe('Passed');
});
it('zeigt abgeleitete CIS-Kategorien auch auf Finding-Kacheln', () => {
const cisRecord: FindingRecord = {
...record,
title: '2.2.2 Ensure a synthetic user right',
fields: [{ index: 0, label: 'Rule ID', value: '2.2.2' }]
};
expect(tileBadges(cisRecord, 'cis-cat').filter(badge => badge.label === 'CIS Category').map(badge => badge.text))
.toEqual(['CIS 2', 'CIS 2.2']);
});
it('keeps the CIS number on the tile and offers the run report section title on hover', () => {
const cisRecord: FindingRecord = {
...record,
title: '2.2.2 Ensure a synthetic user right',
fields: [{ index: 0, label: 'Rule ID', value: '2.2.2' }],
benchmarkSectionTitles: new Map([['2', 'Synthetic Local Policies'], ['2.2', 'Synthetic User Rights Assignment']])
};
expect(tileBadges(cisRecord, 'cis-cat').filter(badge => badge.label === 'CIS Category')).toEqual([
{ label: 'CIS Category', value: 'CIS 2', text: 'CIS 2', title: 'Synthetic Local Policies' },
{ label: 'CIS Category', value: 'CIS 2.2', text: 'CIS 2.2', title: 'Synthetic User Rights Assignment' }
]);
});
it('places derived categories after Status and Severity, before Weight and Score', () => {
const cisRecord: FindingRecord = { ...record, title: '2.2.2 Ensure a synthetic user right' };
expect(tileBadges(cisRecord, 'cis-cat').map(badge => badge.text)).toEqual([
'IOE Found', 'Low', 'Entra ID', 'CIS 2', 'CIS 2.2', 'Weight: 2', 'Score: 86'
]);
});
it('verdichtet ueberzaehlige Graphbadges zu einem sichtbaren Zaehler', () => {
const badges = [
{ label: 'Status', value: 'Fail', text: 'Fail' },
{ label: 'Weight', value: '1.0', text: 'Weight: 1.0' },
{ label: 'CIS Category', value: 'CIS 18', text: 'CIS 18' },
{ label: 'CIS Category', value: 'CIS 18.10', text: 'CIS 18.10' },
{ label: 'CIS Category', value: 'CIS 18.10.18', text: 'CIS 18.10.18' }
];
expect(compactTileBadges(badges, 4).map(badge => badge.text)).toEqual(['Fail', 'Weight: 1.0', 'CIS 18.10.18', '+2']);
});
it('keeps long GPO registry titles inside the tile content column', () => {
const title = 'HKEY_LOCAL_MACHINE · SOFTWARE\\Policies\\Microsoft\\Windows\\Windows Error Reporting\\Disabled';
const html = renderToStaticMarkup(createElement(TileCard, {
record: { ...record, title }, title, bookmarked: false, toolId: 'group-policy',
onOpen() {}, onBookmark() {}
}));
const css = readFileSync(new URL('../../src/styles/legacy-views.css', import.meta.url), 'utf8');
const gpoRule = css.slice(css.indexOf('.data-tile[data-tool="group-policy"]')).split('}')[0];
expect(html).toContain('data-tool="group-policy"');
expect(html).toContain('HKEY_LOCAL_MACHINE');
expect(gpoRule).toContain('overflow-wrap: anywhere');
expect(gpoRule).toContain('max-width: 100%');
expect(gpoRule).not.toMatch(/overflow:\s*hidden|text-overflow|nowrap/);
});
});