import { afterEach, beforeEach, describe, expect, test } from 'vitest'; import { act } from 'react'; import { createRoot, type Root } from 'react-dom/client'; import { Icon } from './Icon'; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; let container: HTMLDivElement; let root: Root; beforeEach(() => { container = document.createElement('div'); document.body.appendChild(container); root = createRoot(container); }); afterEach(() => { act(() => root.unmount()); container.remove(); }); function render(node: React.ReactNode) { act(() => root.render(node)); const svg = container.querySelector('svg'); if (!svg) throw new Error('no rendered'); return svg; } describe('Icon', () => { test('renders an SVG on the Carbon 32-grid, decorative and unfocusable', () => { const svg = render(); expect(svg.getAttribute('viewBox')).toBe('0 0 32 32'); // Decorative by default: the enclosing control carries the accessible name. expect(svg.getAttribute('aria-hidden')).toBe('true'); expect(svg.getAttribute('focusable')).toBe('false'); }); test('each name draws a distinct glyph from the registry', () => { // close is a single polygon; delete (TrashCan) is rects + a path; dataset // (DataTable) is six cells + a path. Distinct geometry ⇒ distinct meaning. expect(render().querySelector('polygon')).not.toBeNull(); const del = render(); expect(del.querySelectorAll('rect').length).toBe(3); expect(del.querySelector('path')).not.toBeNull(); expect(render().querySelectorAll('rect').length).toBe(6); }); test('size maps to a single, changeable class token', () => { const sm = render(); // default const smClass = sm.getAttribute('class') ?? ''; const md = render(); const mdClass = md.getAttribute('class') ?? ''; // Whatever the CSS-module hashing, the two sizes must resolve to different // class strings so the 16/20/24/32 scale is actually applied, not ignored. expect(smClass).not.toBe(mdClass); }); });