// @vitest-environment jsdom import { act } from 'react'; import { createRoot } from 'react-dom/client'; import { afterEach, expect, it, vi } from 'vitest'; import { useApp } from '../../src/app/AppProvider'; import { resetEnginePreferencesForTests, setEngineEnabled } from '../../src/app/engine-preferences'; import { AssessorApiClient } from '../../src/api/assessor-api-client'; import { DashboardPanel, DashboardTopFact } from '../../src/features/dashboard/DashboardPanel'; import { makeSheet } from '../../src/importers/sheet-factory'; import { genericProfile } from '../../src/profiles/generic/generic-profile'; import type { EnvironmentSnapshot } from '../../src/domain/environment-context'; vi.mock('../../src/app/AppProvider', () => ({ useApp: vi.fn() })); vi.mock('../../src/features/search-filter/WorkTimeslotControl', () => ({ WorkTimeslotControl: () => Synthetic timeslot })); afterEach(() => { vi.restoreAllMocks(); vi.unstubAllGlobals(); document.body.replaceChildren(); }); it('opens an unknown fact without inventing a zero or source rows', async () => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); const host = document.createElement('div'); document.body.append(host); const root = createRoot(host); try { await act(async () => root.render()); const trigger = host.querySelector('button')!; expect(trigger.querySelector('strong')!.textContent).toBe('—'); await act(async () => trigger.click()); const popup = document.querySelector('.floating-data-window')!; expect(popup.querySelector('dd')!.textContent).toBe('—'); expect(popup.textContent).toContain('No retained Client Information available'); expect(popup.querySelector('table')).toBeNull(); } finally { act(() => root.unmount()); } }); it.each(['dark', 'light'])('opens the six actual Data facts with their own retained results and preserves Work in %s', async theme => { document.documentElement.dataset.theme = theme; vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); vi.stubGlobal('ResizeObserver', class { observe() {} disconnect() {} }); vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => { callback(0); return 1; }); localStorage.clear(); resetEnginePreferencesForTests(); setEngineEnabled('context', false); const sheet = makeSheet('Synthetic', [['Name', 'Status'], ['Control', 'Failed']], '', 'synthetic.csv', { isProjectSheet: true }); vi.mocked(useApp).mockReturnValue({ dataset: { fileName: 'Synthetic client', sheets: [sheet], scanTool: 'Generic' }, activeSheet: sheet, activeProfile: genericProfile, reviews: {}, targetProjectId: 'synthetic-client', activeAssessmentIds: ['slot'], activeScanRunIds: ['run'], facetFilters: {}, setStatusFilter: vi.fn(), setFacetFilter: vi.fn(), setPathFindingIds: vi.fn(), resetFilters: vi.fn(), setView: vi.fn(), setActionOnly: vi.fn(), setActiveSheet: vi.fn() } as unknown as ReturnType); const tool = { id: 'synthetic', name: 'Synthetic scanner' }; const gpoProse = 'Synthetic scanner explanation. '.repeat(40) + 'Command: auditpol.exe /get /category:*. Preserve the original https://example.invalid/reference and script.js.'; const facts: Array<[string, string | number]> = [ ['domain.count', 1], ['domain.fqdn', 'synthetic.example'], ['entra.tenant_name', 'Synthetic tenant'], ['domain.controller_count', 3], ['gpo.count', 277], ['computer.count', 341], ['user.count', 590] ]; const snapshot: EnvironmentSnapshot = { version: 1, projectId: 'synthetic-client', scanRunIds: ['run'], generatedAt: '2026-10-02T12:00:00Z', coverage: { observed: 5, explicitlyAbsent: 0, empty: 0, restricted: 0, incomplete: 0 }, observations: facts.map(([property, value]) => ({ version: 1, id: property, scanRunId: 'run', importFileId: 'file', tool, subject: { type: 'domain' }, property, label: property, originalValue: value, normalizedValue: value, valueType: typeof value === 'number' ? 'number' : 'string', state: 'observed', source: { rowIndex: 0 }, mappingVersion: '1', attributes: {} })), sections: [ ['sectionUserInformation', 'User source', 'Nb user accounts', 590, 'Synthetic users'], ['sectionComputerInformation', 'Computer source', 'Nb computer accounts', 341, 'Synthetic computers'], ['sectionDomainControllers', 'Controller source', 'DC count', 3, 'Synthetic controllers'], ['sectionGPO', 'GPO source', 'GPO count', 277, 'Synthetic policies'] ].map(([key, label, header, count, marker]) => ({ version: 1, id: String(key), scanRunId: 'run', importFileId: 'file', tool, sectionKey: String(key), label: String(label), ordinal: 1, state: 'observed', prose: key === 'sectionGPO' ? gpoProse : undefined, tables: [{ name: String(label), presentation: 'inline', headers: [String(header), 'Original evidence'], rows: [[count, marker]] }], source: { rowIndex: 0 }, extractorVersion: '1', attributes: {} })) }; const original = JSON.stringify(snapshot); const request = vi.spyOn(AssessorApiClient.prototype, 'getEnvironmentSnapshot').mockResolvedValue(snapshot); vi.spyOn(AssessorApiClient.prototype, 'listProjectGpoBackupStatus').mockResolvedValue({ records: [ { artifactId: 'backup-a', fileName: 'Synthetic backup.zip', processingStatus: 'complete', gpoCount: 277, updatedAt: '2026-10-02T12:00:00Z' } ] } as never); const host = document.createElement('div'); document.body.append(host); const root = createRoot(host); const onOpenWork = vi.fn(); try { await act(async () => root.render()); expect(host.querySelectorAll('button.client-data-fact')).toHaveLength(12); for (const [label, count, evidence] of [ ['AD Domains', '1', 'synthetic.example'], ['Entra Tenant', '1', 'Synthetic tenant'], ['User Accounts', '590', 'Synthetic users'], ['Computer Objects', '341', 'Synthetic computers'], ['Domain Controllers', '3', 'Synthetic controllers'], ['GPOs', '277', 'Synthetic backup.zip'] ]) { const triggers = [...host.querySelectorAll(`[aria-label="Open ${label} results"]`)]; expect(triggers).toHaveLength(2); for (const trigger of triggers) { expect(trigger.querySelector('strong')!.textContent).toBe(count); expect(trigger.getAttribute('aria-haspopup')).toBe('dialog'); await act(async () => trigger.click()); const popup = document.querySelector('.floating-data-window')!; expect(popup.querySelector('h2')!.textContent).toBe(label); expect(popup.textContent).toContain(evidence); if (label === 'Computer Objects' || label === 'User Accounts' || label === 'GPOs') { expect(popup.textContent).not.toContain('Original value'); if (label !== 'GPOs') expect(popup.querySelector('table.client-data-fact-evidence')).toBeNull(); expect(popup.querySelector('.client-env-evidence-table table')).not.toBeNull(); expect(popup.textContent).not.toContain('Scan run'); } if (label === 'User Accounts') expect(popup.textContent).not.toContain('Synthetic computers'); if (label === 'GPOs') expect(popup.textContent).toContain('All processed client backups'); if (label === 'GPOs') { const paragraphs = [...popup.querySelectorAll('.client-env-readable-prose p')]; expect(paragraphs.length).toBeGreaterThan(1); expect(paragraphs.map(p => p.textContent).join(' ').replace(/\s+/g, ' ').trim()).toBe(gpoProse.replace(/\s+/g, ' ').trim()); expect(popup.querySelector('.client-env-evidence-table table')!.textContent).toContain('Synthetic policies'); } expect(trigger.getAttribute('aria-expanded')).toBe('true'); await act(async () => window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))); expect(document.querySelector('.floating-data-window')).toBeNull(); expect(trigger.getAttribute('aria-expanded')).toBe('false'); expect(document.activeElement).toBe(trigger); } } expect(request).toHaveBeenCalledOnce(); expect(onOpenWork).not.toHaveBeenCalled(); expect(useApp().resetFilters).not.toHaveBeenCalled(); expect(useApp().setFacetFilter).not.toHaveBeenCalled(); expect(JSON.stringify(snapshot)).toBe(original); } finally { act(() => root.unmount()); } });