Assessor_2.0/tests/features/finding-work-package-alignm...

69 lines
4.8 KiB
TypeScript

// @vitest-environment jsdom
import { readFileSync } from 'node:fs';
import { act } from 'react';
import { createRoot } from 'react-dom/client';
import { describe, expect, it, vi } from 'vitest';
import { useContextClusterIndex } from '../../src/features/context-layer/use-context-cluster-index';
import { FindingReader } from '../../src/features/finding-reader/FindingReader';
import { makeSheet } from '../../src/importers/sheet-factory';
import { useWorkPackages } from '../../src/remediation/use-work-packages';
import { workRecordKey } from '../../src/remediation/work-package-index';
vi.mock('../../src/features/context-layer/use-context-cluster-index', () => ({ useContextClusterIndex: vi.fn(() => undefined) }));
vi.mock('../../src/remediation/use-work-packages', () => ({ useWorkPackages: vi.fn() }));
describe.each(['dark', 'light'])('Reader Work Package alignment (%s)', theme => {
it('keeps packages and task details right aligned with or without Source Rule ID, including unavailable and unassigned states', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
document.documentElement.dataset.theme = theme;
const style = document.createElement('style');
style.textContent = readFileSync('src/styles/components.css', 'utf8'); document.head.append(style);
const host = document.createElement('div'); document.body.append(host);
const root = createRoot(host);
try {
for (const withSource of [true, false]) {
const record = makeSheet('Synthetic', [withSource ? ['Name', 'Status', 'Source Rule ID'] : ['Name', 'Status'],
withSource ? ['Synthetic deviation', 'Failed', 'RULE-01'] : ['Synthetic deviation', 'Failed']], '', 'synthetic.csv').analysis.records[0];
const original = JSON.stringify(record);
const workPackage = { id: 'synthetic', code: 'WP-01', title: 'Synthetic package', reason: 'Synthetic',
clusterId: 'synthetic-cluster', clusterLabel: 'Synthetic long cluster name for wrapping', facts: { tasks: 6, findings: 6 },
tasks: Array.from({ length: 6 }, (_, i) => ({ id: `task-${i}`, findingKeys: i ? [] : [workRecordKey(record)] })) };
for (const state of [
{ status: 'ready', index: { packageFor: () => workPackage } },
{ status: 'loading' },
{ status: 'ready', index: { packageFor: () => undefined, unassigned: () => true } }
]) {
vi.mocked(useWorkPackages).mockReturnValue(state as never);
await act(async () => root.render(<FindingReader record={record} title={record.title}
linkedSheets={[]} resultReferences={[]} search="" position={0} recordCount={1}
onPrevious={vi.fn()} onNext={vi.fn()} onReview={vi.fn()}/>));
const row = host.querySelector('.reader-source-rule')!;
const packageItem = row.querySelector<HTMLElement>('.finding-work-package__group, .finding-work-package')!;
for (const width of [1200, 620, 320]) {
host.style.width = `${width}px`;
expect(getComputedStyle(packageItem).textAlign).toBe('right');
expect(getComputedStyle(packageItem).overflowWrap).toBe('anywhere');
expect(getComputedStyle(packageItem).flex).toBe('1 1 0px');
}
expect(Boolean(row.querySelector('code'))).toBe(withSource);
if (row.querySelector('[data-work-package-id]')) {
expect(packageItem.textContent).toContain('One of 6 tasks');
for (const severity of ['critical', 'high', 'medium', 'undetermined']) {
vi.mocked(useContextClusterIndex).mockReturnValue({ publication: { clusters: [{ id: 'synthetic-cluster', label: workPackage.clusterLabel, hasEvidence: severity !== 'undetermined', severity }] } } as never);
await act(async () => root.render(<FindingReader record={record} title={record.title} linkedSheets={[]} resultReferences={[]} search="" position={0} recordCount={1} onPrevious={vi.fn()} onNext={vi.fn()} onReview={vi.fn()}/>));
const square = row.querySelector('[data-finding-work-package-colour]')!;
expect(square.getAttribute('data-finding-work-package-colour')).toBe(severity);
expect(square.classList.contains('severity-' + severity)).toBe(true);
expect(square.parentElement?.getAttribute('data-work-package-id')).toBe('synthetic');
expect(getComputedStyle(square).display).toBe('inline-block');
expect(row.textContent).toContain('One of 6 tasks');
}
await act(async () => row.querySelector<HTMLAnchorElement>('a')!.click());
}
expect(JSON.stringify(record)).toBe(original);
}
}
} finally { vi.mocked(useContextClusterIndex).mockReturnValue(undefined); await act(async () => root.unmount()); host.remove(); style.remove(); vi.unstubAllGlobals(); }
});
});