// @vitest-environment jsdom import { act, useState } from 'react'; import { createRoot } from 'react-dom/client'; import { afterEach, describe, expect, it, vi } from 'vitest'; import type { FindingRecord } from '../../src/domain/finding'; import { TileCard } from '../../src/components/TileCard/TileCard'; import { FindingReader } from '../../src/features/finding-reader/FindingReader'; afterEach(() => { vi.unstubAllGlobals(); document.body.replaceChildren(); }); describe.each(['light', 'dark'])('Finding badge order (%s)', theme => { it.each([ ['pingcastle', 'Severity'], ['purple-knight', 'Severity'], ['maester', 'Severity'], ['cis-cat', 'Severity'], ['group-policy', 'Severity'], ['generic', 'Criticality'], ['generic', 'Priority'] ])('keeps Outcome then %s severity (%s) ahead of native/derived categories and numeric metadata when opening a compact tile', async (toolId, severityLabel) => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); document.documentElement.dataset.theme = theme; const record: FindingRecord = { id: 'synthetic-badge-order', index: 0, title: '2.2.2 Ensure a synthetic setting', filled: [], meta: [], fields: [['Domain Risk Level', '100'], ['Points', '20'], ['Category', 'Synthetic category'], ['Weight', '8'], ['Score', '73'], ['Status', 'Fail'], [severityLabel, 'Medium'], ['Rule ID', '2.2.2'], ['Baseline', 'Windows Server 2022 Security Baseline'], ['Scope', 'computer']] .map(([label, value], index) => ({ label, value, index })) }; const original = JSON.stringify(record); function Reading() { const [open, setOpen] = useState(false); return open ? {}} onNext={() => {}} onReview={() => {}}/> : setOpen(true)} onBookmark={() => {}}/>; } const host = document.createElement('div'); document.body.append(host); const root = createRoot(host); try { await act(async () => root.render()); const tileBadges = [...host.querySelector('.data-tile-badges')!.children]; expect(tileBadges[0].getAttribute('data-badge-role')).toBe('status'); expect(tileBadges[1].getAttribute('data-badge-role')).toBe('severity'); expect(tileBadges[1].textContent).toBe('Medium'); expect(tileBadges[2].getAttribute('data-badge-role')).toBe('category'); await act(async () => host.querySelector('.data-tile')!.click()); const readerBadges = [...host.querySelector('.finding-badges')!.children]; expect(readerBadges[0].classList.contains('outcome-mark')).toBe(true); expect(readerBadges[1].classList.contains('severity-medium')).toBe(true); expect(readerBadges[1].textContent).toBe('Medium'); expect(readerBadges.filter(badge => badge.classList.contains('severity-badge'))).toHaveLength(1); expect(readerBadges.slice(2).some(badge => badge.textContent === 'Domain Risk Level: 100 / 100')).toBe(true); expect(readerBadges.slice(2).some(badge => badge.textContent === 'Points: 20')).toBe(true); expect(JSON.stringify(record)).toBe(original); } finally { await act(async () => root.unmount()); host.remove(); } }); it('omits unavailable Severity without creating a placeholder or hiding the category', async () => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); document.documentElement.dataset.theme = theme; const record: FindingRecord = { id: 'synthetic-no-severity', index: 0, title: 'Synthetic finding', filled: [], meta: [], fields: [{ label: 'Status', value: 'Failed', index: 0 }, { label: 'Category', value: 'Synthetic category', index: 1 }] }; const host = document.createElement('div'); document.body.append(host); const root = createRoot(host); try { await act(async () => root.render(<> {}} onBookmark={() => {}}/> {}} onNext={() => {}} onReview={() => {}}/>)); expect([...host.querySelector('.data-tile-badges')!.children].map(b => b.textContent)).toEqual(['Failed', 'Synthetic category']); expect([...host.querySelector('.finding-badges')!.children].map(b => b.textContent)).toEqual(['Failed', 'Category: Synthetic category']); } finally { await act(async () => root.unmount()); host.remove(); } }); });