import {act, fireEvent, render, screen} from '@testing-library/react'; import {useState} from 'react'; import {Composite, CompositeItem} from '../../src'; function microtask() { return act(async () => {}); } describe('list', () => { test('controlled mode', async () => { function App() { const [activeIndex, setActiveIndex] = useState(0); return ( 1 2 3 ); } render(); act(() => screen.getByTestId('1').focus()); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); fireEvent.keyDown(screen.getByTestId('1'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('2')).toHaveAttribute('data-active'); expect(screen.getByTestId('2')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('2')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('2'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('3')).toHaveAttribute('data-active'); expect(screen.getByTestId('3')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('3')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('3'), {key: 'ArrowUp'}); await microtask(); expect(screen.getByTestId('2')).toHaveAttribute('data-active'); expect(screen.getByTestId('2')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('2')).toHaveFocus(); act(() => screen.getByTestId('1').focus()); await microtask(); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); expect(screen.getByTestId('1')).toHaveAttribute('tabindex', '0'); }); test('uncontrolled mode', async () => { render( 1 2 3 , ); act(() => screen.getByTestId('1').focus()); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); fireEvent.keyDown(screen.getByTestId('1'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('2')).toHaveAttribute('data-active'); expect(screen.getByTestId('2')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('2')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('2'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('3')).toHaveAttribute('data-active'); expect(screen.getByTestId('3')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('3')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('3'), {key: 'ArrowUp'}); await microtask(); expect(screen.getByTestId('2')).toHaveAttribute('data-active'); expect(screen.getByTestId('2')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('2')).toHaveFocus(); act(() => screen.getByTestId('1').focus()); await microtask(); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); expect(screen.getByTestId('1')).toHaveAttribute('tabindex', '0'); }); }); describe('grid', () => { test('uniform 1x1 items', async () => { function App() { return ( // 1 to 9 numpad {['1', '2', '3', '4', '5', '6', '7', '8', '9'].map((i) => ( {i} ))} ); } render(); act(() => screen.getByTestId('1').focus()); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); fireEvent.keyDown(screen.getByTestId('1'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('4')).toHaveAttribute('data-active'); expect(screen.getByTestId('4')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('4')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('4'), {key: 'ArrowRight'}); await microtask(); expect(screen.getByTestId('5')).toHaveAttribute('data-active'); expect(screen.getByTestId('5')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('5')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('5'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('8')).toHaveAttribute('data-active'); expect(screen.getByTestId('8')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('8')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('8'), {key: 'ArrowLeft'}); await microtask(); expect(screen.getByTestId('7')).toHaveAttribute('data-active'); expect(screen.getByTestId('7')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('7')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('7'), {key: 'ArrowUp'}); await microtask(); expect(screen.getByTestId('4')).toHaveAttribute('data-active'); expect(screen.getByTestId('4')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('4')).toHaveFocus(); act(() => screen.getByTestId('9').focus()); await microtask(); expect(screen.getByTestId('9')).toHaveAttribute('data-active'); expect(screen.getByTestId('9')).toHaveAttribute('tabindex', '0'); }); test('wider item', async () => { function App() { return ( // 1 to 9 numpad, but 4, 5 and 6 are one big button {['1', '2', '3', '456', '7', '8', '9'].map((i) => ( {i} ))} ); } render(); act(() => screen.getByTestId('1').focus()); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); fireEvent.keyDown(screen.getByTestId('1'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('456')).toHaveAttribute('data-active'); expect(screen.getByTestId('456')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('456')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('456'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('7')).toHaveAttribute('data-active'); expect(screen.getByTestId('7')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('7')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('7'), {key: 'ArrowRight'}); await microtask(); expect(screen.getByTestId('8')).toHaveAttribute('data-active'); expect(screen.getByTestId('8')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('8')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('8'), {key: 'ArrowUp'}); await microtask(); expect(screen.getByTestId('456')).toHaveAttribute('data-active'); expect(screen.getByTestId('456')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('456')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('456'), {key: 'ArrowUp'}); await microtask(); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); expect(screen.getByTestId('1')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('1')).toHaveFocus(); act(() => screen.getByTestId('9').focus()); await microtask(); expect(screen.getByTestId('9')).toHaveAttribute('data-active'); expect(screen.getByTestId('9')).toHaveAttribute('tabindex', '0'); }); test('wider and taller item', async () => { function App() { return ( // 1 to 9 numpad, but 4, 5, 7 and 8 are one big button {['1', '2', '3', '4578', '6', '9'].map((i) => ( {i} ))} ); } render(); act(() => screen.getByTestId('1').focus()); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); fireEvent.keyDown(screen.getByTestId('1'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('4578')).toHaveAttribute('data-active'); expect(screen.getByTestId('4578')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('4578')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('4578'), {key: 'ArrowRight'}); await microtask(); expect(screen.getByTestId('6')).toHaveAttribute('data-active'); expect(screen.getByTestId('6')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('6')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('6'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('9')).toHaveAttribute('data-active'); expect(screen.getByTestId('9')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('9')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('9'), {key: 'ArrowLeft'}); await microtask(); expect(screen.getByTestId('4578')).toHaveAttribute('data-active'); expect(screen.getByTestId('4578')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('4578')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('4578'), {key: 'ArrowUp'}); await microtask(); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); expect(screen.getByTestId('1')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('1')).toHaveFocus(); act(() => screen.getByTestId('9').focus()); await microtask(); expect(screen.getByTestId('9')).toHaveAttribute('data-active'); expect(screen.getByTestId('9')).toHaveAttribute('tabindex', '0'); }); test('grid flow', async () => { function App() { return ( // 1 to 9 numpad, but 2, 3, 5 and 6 are one big button, and so are 7 and 8. // 4 is missing {['1', '2356', '78', '9'].map((i) => ( {i} ))} ); } render(); act(() => screen.getByTestId('1').focus()); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); fireEvent.keyDown(screen.getByTestId('1'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('78')).toHaveAttribute('data-active'); expect(screen.getByTestId('78')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('78')).toHaveFocus(); }); test('grid flow: dense', async () => { function App() { return ( // 1 to 9 numpad, but 2, 3, 5 and 6 are one big button, and so are 7 and 8. // 9 is missing {['1', '2356', '78', '4'].map((i) => ( {i} ))} ); } render(); act(() => screen.getByTestId('1').focus()); expect(screen.getByTestId('1')).toHaveAttribute('data-active'); fireEvent.keyDown(screen.getByTestId('1'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('4')).toHaveAttribute('data-active'); expect(screen.getByTestId('4')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('4')).toHaveFocus(); fireEvent.keyDown(screen.getByTestId('4'), {key: 'ArrowDown'}); await microtask(); expect(screen.getByTestId('78')).toHaveAttribute('data-active'); expect(screen.getByTestId('78')).toHaveAttribute('tabindex', '0'); expect(screen.getByTestId('78')).toHaveFocus(); }); });