import {act, fireEvent, render, screen} from '@testing-library/react'; import * as React from 'react'; import { FloatingList, useClick, useFloating, useInteractions, useListItem, useListNavigation, useTypeahead, } from '../../src'; const SelectContext = React.createContext(null); function Select({children}: {children: React.ReactNode}) { const [isOpen, setIsOpen] = React.useState(false); const [activeIndex, setActiveIndex] = React.useState(null); const {refs, context} = useFloating({ open: isOpen, onOpenChange: setIsOpen, }); const elementsRef = React.useRef>([]); const labelsRef = React.useRef>([]); const click = useClick(context); const listNavigation = useListNavigation(context, { listRef: elementsRef, activeIndex, onNavigate: setActiveIndex, }); const typeahead = useTypeahead(context, { listRef: labelsRef, activeIndex, onMatch: setActiveIndex, }); const {getReferenceProps, getFloatingProps, getItemProps} = useInteractions([ click, listNavigation, typeahead, ]); return ( {isOpen && (
{children}
)}
); } function Option({ children, label, }: { children: React.ReactNode; label?: string; }) { const {getItemProps, activeIndex} = React.useContext(SelectContext); const {ref, index} = useListItem({label}); const isActive = index === activeIndex && index !== null; return (
{children}
); } test('registers element ref and indexes correctly', async () => { render( , ); fireEvent.click(screen.getByRole('button')); await act(async () => {}); expect(screen.getAllByRole('option')[0]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); expect(screen.getAllByRole('option')[1]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); expect(screen.getAllByRole('option')[2]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); expect(screen.getAllByRole('option')[4]).toHaveFocus(); expect(screen.getAllByRole('option')[4].getAttribute('tabindex')).toBe('0'); }); test('registers an element ref and index correctly', async () => { render( , ); fireEvent.click(screen.getByRole('button')); await act(async () => {}); expect(screen.getAllByRole('option')[0]).toHaveFocus(); }); test('registers strings correctly (no value)', async () => { render( , ); fireEvent.click(screen.getByRole('button')); await act(async () => {}); expect(screen.getAllByRole('option')[0]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'F'}); expect(screen.getAllByRole('option')[3]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'I'}); expect(screen.getAllByRole('option')[4]).toHaveFocus(); }); test('registers strings correctly (label)', async () => { render( , ); fireEvent.click(screen.getByRole('button')); await act(async () => {}); expect(screen.getAllByRole('option')[0]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'F'}); expect(screen.getAllByRole('option')[3]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'I'}); expect(screen.getAllByRole('option')[4]).toHaveFocus(); }); test('handles re-ordering', async () => { const {rerender} = render( , ); fireEvent.click(screen.getByRole('button')); await act(async () => {}); expect(screen.getAllByRole('option')[0]).toHaveFocus(); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); expect(screen.getAllByRole('option')[1]).toHaveFocus(); rerender( , ); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); fireEvent.keyDown(screen.getByRole('listbox'), {key: 'ArrowDown'}); expect(screen.getAllByRole('option')[5]).toHaveFocus(); });