@@ -427,6 +427,97 @@ describe('Autocomplete', () => {
427427 expect ( input ) . not . toHaveAttribute ( 'data-focused' ) ;
428428 } ) ;
429429
430+ it ( 'should restore focus visible styles back to the input when typing forward results in only disabled items' , async function ( ) {
431+ let { getByRole} = render (
432+ < AutocompleteWrapper >
433+ < StaticMenu disabledKeys = { [ '2' ] } />
434+ </ AutocompleteWrapper >
435+ ) ;
436+
437+ let input = getByRole ( 'searchbox' ) ;
438+ await user . tab ( ) ;
439+ expect ( document . activeElement ) . toBe ( input ) ;
440+ expect ( input ) . toHaveAttribute ( 'data-focused' ) ;
441+ expect ( input ) . toHaveAttribute ( 'data-focus-visible' ) ;
442+
443+ await user . keyboard ( 'Ba' ) ;
444+ act ( ( ) => jest . runAllTimers ( ) ) ;
445+ let menu = getByRole ( 'menu' ) ;
446+ let options = within ( menu ) . getAllByRole ( 'menuitem' ) ;
447+ let baz = options [ 1 ] ;
448+ expect ( baz ) . toHaveTextContent ( 'Baz' ) ;
449+ expect ( input ) . toHaveAttribute ( 'aria-activedescendant' , baz . id ) ;
450+ expect ( baz ) . toHaveAttribute ( 'data-focus-visible' ) ;
451+ expect ( input ) . not . toHaveAttribute ( 'data-focused' ) ;
452+ expect ( input ) . not . toHaveAttribute ( 'data-focus-visible' ) ;
453+
454+ await user . keyboard ( 'r' ) ;
455+ act ( ( ) => jest . runAllTimers ( ) ) ;
456+ options = within ( menu ) . getAllByRole ( 'menuitem' ) ;
457+ let bar = options [ 0 ] ;
458+ expect ( bar ) . toHaveTextContent ( 'Bar' ) ;
459+ expect ( input ) . not . toHaveAttribute ( 'aria-activedescendant' ) ;
460+ expect ( bar ) . not . toHaveAttribute ( 'data-focus-visible' ) ;
461+ expect ( input ) . toHaveAttribute ( 'data-focused' ) ;
462+ expect ( input ) . toHaveAttribute ( 'data-focus-visible' ) ;
463+ } ) ;
464+
465+ it ( 'should maintain focus styles on the input if typing forward results in an completely empty collection' , async function ( ) {
466+ let { getByRole} = render (
467+ < AutocompleteWrapper >
468+ < StaticMenu />
469+ </ AutocompleteWrapper >
470+ ) ;
471+
472+ let input = getByRole ( 'searchbox' ) ;
473+ await user . tab ( ) ;
474+ expect ( document . activeElement ) . toBe ( input ) ;
475+ expect ( input ) . toHaveAttribute ( 'data-focused' ) ;
476+ expect ( input ) . toHaveAttribute ( 'data-focus-visible' ) ;
477+
478+ await user . keyboard ( 'Q' ) ;
479+ act ( ( ) => jest . runAllTimers ( ) ) ;
480+ let menu = getByRole ( 'menu' ) ;
481+ let options = within ( menu ) . queryAllByRole ( 'menuitem' ) ;
482+ expect ( options ) . toHaveLength ( 0 ) ;
483+ expect ( input ) . toHaveAttribute ( 'data-focused' ) ;
484+ expect ( input ) . toHaveAttribute ( 'data-focus-visible' ) ;
485+ expect ( input ) . not . toHaveAttribute ( 'aria-activedescendant' ) ;
486+ } ) ;
487+
488+ it ( 'should restore focus visible styles back to the input if the user types forward and backspaces in quick succession' , async function ( ) {
489+ let { getByRole} = render (
490+ < AutocompleteWrapper >
491+ < StaticMenu />
492+ </ AutocompleteWrapper >
493+ ) ;
494+
495+ let input = getByRole ( 'searchbox' ) ;
496+ await user . tab ( ) ;
497+ expect ( document . activeElement ) . toBe ( input ) ;
498+ expect ( input ) . toHaveAttribute ( 'data-focused' ) ;
499+ expect ( input ) . toHaveAttribute ( 'data-focus-visible' ) ;
500+
501+ await user . keyboard ( 'F' ) ;
502+ // If 500ms hasn't elapsed the aria-activedecendant hasn't been updated
503+ act ( ( ) => jest . advanceTimersByTime ( 300 ) ) ;
504+ let menu = getByRole ( 'menu' ) ;
505+ let options = within ( menu ) . getAllByRole ( 'menuitem' ) ;
506+ let foo = options [ 0 ] ;
507+ expect ( foo ) . toHaveTextContent ( 'Foo' ) ;
508+ expect ( input ) . not . toHaveAttribute ( 'aria-activedescendant' ) ;
509+ expect ( foo ) . toHaveAttribute ( 'data-focus-visible' ) ;
510+ expect ( input ) . not . toHaveAttribute ( 'data-focused' ) ;
511+ expect ( input ) . not . toHaveAttribute ( 'data-focus-visible' ) ;
512+
513+ await user . keyboard ( '{Backspace}' ) ;
514+ act ( ( ) => jest . runAllTimers ( ) ) ;
515+ expect ( input ) . toHaveAttribute ( 'data-focused' ) ;
516+ expect ( input ) . toHaveAttribute ( 'data-focus-visible' ) ;
517+ expect ( input ) . not . toHaveAttribute ( 'aria-activedescendant' ) ;
518+ expect ( foo ) . not . toHaveAttribute ( 'data-focus-visible' ) ;
519+ } ) ;
520+
430521 it ( 'should work inside a Select' , async function ( ) {
431522 let { getByRole} = render (
432523 < Select >
0 commit comments