// @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 { AssessorApiClient } from '../../src/api/assessor-api-client'; import { DashboardPanel } from '../../src/features/dashboard/DashboardPanel'; import { clientFactsSnapshot, clientFactsState } from '../fixtures/client-info-facts'; 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.each(['populated', 'unavailable', 'non-numeric count'])('shows each overview fact once in the existing tiles and preserves Results: %s', async mode => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); const snapshot = structuredClone(clientFactsSnapshot); if (mode === 'unavailable') { snapshot.observations = []; snapshot.sections = []; } if (mode === 'non-numeric count') { const count = snapshot.observations.find(item => item.property === 'domain.controller_count')!; count.originalValue = count.normalizedValue = 'Two reported controllers'; count.valueType = 'string'; } vi.spyOn(AssessorApiClient.prototype, 'getEnvironmentSnapshot').mockResolvedValue(snapshot); vi.spyOn(AssessorApiClient.prototype, 'listProjectGpoBackupStatus').mockResolvedValue({ records: [] } as never); vi.mocked(useApp).mockReturnValue(clientFactsState() as unknown as ReturnType); const host = document.createElement('div'); document.body.append(host); const root = createRoot(host); try { await act(async () => root.render()); const domain = host.querySelector('.client-domain-information')!; const groups = [...host.querySelectorAll('.client-env-group')]; const directory = groups.find(group => group.querySelector('h3')?.textContent === 'Directory')!; const inventory = groups.find(group => group.querySelector('h3')?.textContent === 'Inventory')!; const labels = (element: Element) => [...element.querySelectorAll('dt')].map(item => item.textContent); expect(host.querySelector('.client-posture')).not.toBeNull(); expect(host.querySelector('.client-posture-connectors')).not.toBeNull(); expect(host.querySelector('.client-priority')).not.toBeNull(); expect(host.querySelectorAll('.client-data-fact')).toHaveLength(6); expect(groups).toHaveLength(5); expect(labels(directory)).toEqual(['NetBIOS name', 'Schema version', 'Domain created', 'Entra ID']); expect(labels(domain)).toEqual(mode === 'non-numeric count' ? ['Domain', 'Forest', 'Domain controllers', 'Domain functional level', 'Forest functional level', 'DC OS'] : ['Domain', 'Forest', 'Domain functional level', 'Forest functional level', 'DC OS']); expect(labels(inventory)).toEqual(['Enabled / disabled', 'Password never expires', 'Admin groups', 'Trusts', 'Assessed host']); // Equal domain/forest and functional-level values are distinct facts, not duplicates. if (mode !== 'unavailable') { expect([...domain.querySelectorAll('dd')].filter(item => item.textContent === 'contoso.example')).toHaveLength(2); expect([...domain.querySelectorAll('dd')].filter(item => item.textContent === 'Windows Server 2016')).toHaveLength(2); } else expect([...domain.querySelectorAll('dd')].every(item => item.textContent === '—')).toBe(true); for (const [title, group, expected] of [ ['Directory', directory, ['Domain', 'Forest', 'Domains', 'Domain functional level', 'Schema version']], ['Inventory', inventory, ['User accounts', 'Computer objects', 'Domain controllers', 'Assessed host']] ] as const) { const trigger = group.querySelector('button')!; expect(trigger.getAttribute('aria-label')).toBe(`Open ${title} results`); await act(async () => trigger.click()); const popup = document.querySelector('.floating-data-window')!; for (const label of expected) expect(labels(popup)).toContain(label); if (mode !== 'unavailable') expect(popup.querySelector('table')).not.toBeNull(); await act(async () => document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))); expect(document.querySelector('.floating-data-window')).toBeNull(); } } finally { await act(async () => root.unmount()); } });