import { describe, expect, it } from 'vitest'; import type { EnvironmentSnapshot } from '../../src/domain/environment-context'; import { clientInfoOverview, cloudInformationTileFacts, operatingSystemOverview } from '../../src/features/dashboard/client-info-facts'; import { reportGpoBackupCount, reportHeaderFacts } from '../../src/reporting/report-header-facts'; const observation = (property: string, value: unknown, label = property) => ({ property, label, state: 'observed', normalizedValue: value, originalValue: value, subject: { type: 'domain' }, tool: { id: 'synthetic' }, sectionKey: 'synthetic' }); const snapshot = { version: 1, projectId: 'synthetic-project', scanRunIds: ['synthetic-run'], generatedAt: '2026-10-08T00:00:00Z', coverage: { observed: 0, explicitlyAbsent: 0, empty: 0, restricted: 0, incomplete: 0 }, observations: [ observation('domain.fqdn', 'synthetic.example', 'Domain'), observation('forest.name', 'synthetic.example'), observation('domain.controller_count', 2, 'DC count'), observation('domain.recycle_bin_enabled', false, 'Recycle Bin enabled') ], sections: [{ sectionKey: 'sectionUserInformation', label: 'Users', state: 'observed', tables: [{ name: 'User information', headers: ['Nb User Accounts', 'Nb Enabled', 'Nb Disabled'], rows: [[12, 10, 2]] }] }] } as unknown as EnvironmentSnapshot; describe('Technical Report Information facts', () => { it('states exactly the Client Info overview facts of the same snapshot', () => { const facts = reportHeaderFacts(snapshot, { gpoCount: 3 })!; const overview = clientInfoOverview(snapshot, { gpoCount: 3 }); expect(facts.data).toEqual([ { label: 'AD Domains', value: '1' }, { label: 'Entra Tenant', value: '—' }, { label: 'User Accounts', value: '12' }, { label: 'Computer Objects', value: '—' }, { label: 'Domain Controllers', value: '2' }, { label: 'GPOs', value: '3' }]); expect(facts.data.map(item => item.label)).toEqual(overview.data.map(item => item.label)); // Domain Information without the counts Data already shows, as in Client Info. expect(facts.domainInformation).toEqual(overview.domainInformation); expect(facts.domainInformation.some(item => item.label === 'Domain controllers')).toBe(false); const group = (title: string) => facts.groups.find(item => item.title === title)!.facts; expect(facts.groups.map(item => item.title)).toEqual( ['Resilience', 'Inventory', 'Password policy', 'Certificates & PKI', 'Operating systems', 'Cloud Information']); expect(group('Resilience')).toEqual(overview.detail.resilience.slice(0, 4)); expect(group('Inventory')).toEqual(overview.inventory.slice(0, 4)); expect(group('Operating systems')).toEqual(operatingSystemOverview(overview.detail.operatingSystems)); expect(group('Cloud Information').map(item => item.label)).toEqual(cloudInformationTileFacts(snapshot).map(item => item.label)); // Unknown facts stay an em dash, never zero. expect(group('Password policy').every(item => item.value === '—')).toBe(true); }); it('infers one Entra tenant only from loaded Maester results, as Client Info does', () => { expect(reportHeaderFacts(snapshot, { inferredEntraTenant: true })!.data[1]).toEqual({ label: 'Entra Tenant', value: '1' }); expect(reportHeaderFacts(undefined, {})).toBeUndefined(); }); it('counts GPOs like the GPO backup list: instances of the latest processed run per backup source', () => { const artifacts = [ { id: 'backup-a', kind: 'source-file', relativePath: 'gpo-backups/a.zip' }, { id: 'backup-b', kind: 'source-file', relativePath: 'gpo-backups/b.zip' }, { id: 'scan', kind: 'source-file', relativePath: 'scans/report.html' } ] as never; const runs = [ { id: 'run-a-old', artifactId: 'backup-a', status: 'complete', completedAt: '2026-10-01T00:00:00Z' }, { id: 'run-a-new', artifactId: 'backup-a', status: 'complete', completedAt: '2026-10-02T00:00:00Z' } ] as never; const instances = [ { processingRunId: 'run-a-old' }, { processingRunId: 'run-a-new' }, { processingRunId: 'run-a-new' } ] as never; expect(reportGpoBackupCount(artifacts, runs, instances)).toBe(2); expect(reportGpoBackupCount(artifacts, [], instances)).toBeUndefined(); }); });