70 lines
3.4 KiB
TypeScript
70 lines
3.4 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { act } from 'react';
|
|
import { createRoot } from 'react-dom/client';
|
|
import { afterEach, expect, it, vi } from 'vitest';
|
|
import { DashboardOverallRing, DashboardPostureConnectors } from '../../src/features/dashboard/DashboardPanel';
|
|
|
|
afterEach(() => { vi.restoreAllMocks(); vi.unstubAllGlobals(); });
|
|
|
|
it('retains the ring-to-domain fan after resize, domain changes and unmount', () => {
|
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
|
let width = 1000;
|
|
let resized: () => void = () => {};
|
|
const disconnect = vi.fn();
|
|
vi.stubGlobal('ResizeObserver', class {
|
|
constructor(callback: () => void) { resized = callback; }
|
|
observe = vi.fn();
|
|
disconnect = disconnect;
|
|
});
|
|
const rect = (x: number, y: number, w: number, h: number) => ({ x, y, left: x, top: y,
|
|
right: x + w, bottom: y + h, width: w, height: h, toJSON() {} });
|
|
vi.spyOn(Element.prototype, 'getBoundingClientRect').mockImplementation(function (this: Element) {
|
|
if (this.matches('.client-posture')) return rect(20, 30, width, 600);
|
|
if (this.matches('.client-overall-ring')) return rect(60, 80, 280, 280);
|
|
if (this.matches('.client-domain-score')) return rect(width - 200, 70 + Number(this.getAttribute('data-index')) * 70, 46, 46);
|
|
return rect(0, 0, 0, 0);
|
|
});
|
|
const container = document.createElement('div');
|
|
const root = createRoot(container);
|
|
const render = (count: number) => act(() => root.render(<section className="client-posture">
|
|
<DashboardPostureConnectors nodeCount={count}/>
|
|
<section className="client-overall"><DashboardOverallRing score={37}/></section>
|
|
<section className="client-domains">{Array.from({ length: count }, (_, index) =>
|
|
<span key={index} className="client-domain-score" data-index={index}>{index}</span>)}</section>
|
|
</section>));
|
|
try {
|
|
render(8);
|
|
const paths = () => [...container.querySelectorAll('.client-posture-connectors path')].map(path => path.getAttribute('d'));
|
|
expect(paths()).toHaveLength(8);
|
|
expect(paths()[0]).toBe('M320.0 169.0 C527.0 169.0, 573.0 63.0, 780.0 63.0');
|
|
expect(paths()[7]).toMatch(/780\.0 553\.0$/);
|
|
width = 1200;
|
|
act(() => window.dispatchEvent(new Event('resize')));
|
|
expect(paths()[0]).toMatch(/980\.0 63\.0$/);
|
|
width = 950;
|
|
act(() => resized());
|
|
expect(paths()[0]).toMatch(/730\.0 63\.0$/);
|
|
render(3);
|
|
expect(paths()).toHaveLength(3);
|
|
expect(paths()[0]).toMatch(/^M320\.0 184\.0/);
|
|
expect(container.querySelector('.client-overall-ring')?.getAttribute('aria-label')).toBe('Overall Score: 37');
|
|
} finally { act(() => root.unmount()); }
|
|
expect(disconnect).toHaveBeenCalled();
|
|
});
|
|
|
|
it('makes the Overall Score an accessible Work remediation entry point', () => {
|
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
|
const onClick = vi.fn();
|
|
const container = document.createElement('div');
|
|
const root = createRoot(container);
|
|
try {
|
|
act(() => root.render(<DashboardOverallRing score={37} onClick={onClick}/>));
|
|
const ring = container.querySelector<HTMLButtonElement>('button.client-overall-ring')!;
|
|
expect(ring.getAttribute('aria-label')).toBe('Open remediation overview in Work. Overall Score: 37');
|
|
expect(ring.textContent).toBe('37/100ASSESSOR');
|
|
expect(ring.querySelector('.client-overall-ring-title')).toBeNull();
|
|
act(() => ring.click());
|
|
expect(onClick).toHaveBeenCalledOnce();
|
|
} finally { act(() => root.unmount()); }
|
|
});
|