import { describe, it, expect, afterEach } from 'vitest'; const { radioGroupNav } = await import('./radioGroupNav'); describe('radioGroupNav action', () => { const nodes: HTMLElement[] = []; function makeGroup(count: number): { container: HTMLElement; buttons: HTMLElement[] } { const container = document.createElement('div'); container.setAttribute('role', 'radiogroup'); const buttons: HTMLElement[] = []; for (let i = 0; i < count; i++) { const btn = document.createElement('button'); btn.setAttribute('role', 'radio'); btn.setAttribute('aria-checked', i === 0 ? 'true' : 'false'); btn.setAttribute('tabindex', i === 0 ? '0' : '-1'); container.appendChild(btn); buttons.push(btn); } document.body.appendChild(container); nodes.push(container); return { container, buttons }; } afterEach(() => { nodes.forEach((n) => n.remove()); nodes.length = 0; }); it('ArrowRight moves focus to next button', () => { const { container, buttons } = makeGroup(4); radioGroupNav(container); buttons[0].focus(); buttons[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true })); expect(document.activeElement).toBe(buttons[1]); }); it('ArrowRight wraps from last to first', () => { const { container, buttons } = makeGroup(4); radioGroupNav(container); buttons[3].focus(); buttons[3].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true })); expect(document.activeElement).toBe(buttons[0]); }); it('ArrowLeft moves focus to previous button', () => { const { container, buttons } = makeGroup(4); radioGroupNav(container); buttons[2].focus(); buttons[2].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true })); expect(document.activeElement).toBe(buttons[1]); }); it('ArrowLeft wraps from first to last', () => { const { container, buttons } = makeGroup(4); radioGroupNav(container); buttons[0].focus(); buttons[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true })); expect(document.activeElement).toBe(buttons[3]); }); it('ArrowRight updates aria-checked on new button and removes it from old', () => { const { container, buttons } = makeGroup(4); radioGroupNav(container); buttons[0].focus(); buttons[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true })); expect(buttons[1].getAttribute('aria-checked')).toBe('true'); expect(buttons[0].getAttribute('aria-checked')).toBe('false'); }); it('destroy removes keydown listener', () => { const { container, buttons } = makeGroup(4); const { destroy } = radioGroupNav(container); destroy(); buttons[0].focus(); buttons[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true })); expect(document.activeElement).toBe(buttons[0]); }); it('ignores non-arrow keys', () => { const { container, buttons } = makeGroup(4); radioGroupNav(container); buttons[0].focus(); buttons[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })); expect(document.activeElement).toBe(buttons[0]); }); });