@@ -333,6 +333,39 @@ test('auto-complete variant', () => {
333333 wrapper . unmount ( )
334334} )
335335
336+ test ( 'auto-complete popover class by variant' , ( ) => {
337+ const standard = mount ( AutoComplete , {
338+ props : {
339+ variant : 'standard' ,
340+ } ,
341+ } )
342+
343+ expect ( standard . findComponent ( { name : 'VarMenuSelect' } ) . props ( 'popoverClass' ) ) . toBe (
344+ 'var-auto-complete--standard-menu-margin' ,
345+ )
346+ standard . unmount ( )
347+
348+ const filled = mount ( AutoComplete , {
349+ props : {
350+ variant : 'filled' ,
351+ } ,
352+ } )
353+
354+ expect ( filled . findComponent ( { name : 'VarMenuSelect' } ) . props ( 'popoverClass' ) ) . toBe (
355+ 'var-auto-complete--filled-menu-margin' ,
356+ )
357+ filled . unmount ( )
358+
359+ const outlined = mount ( AutoComplete , {
360+ props : {
361+ variant : 'outlined' ,
362+ } ,
363+ } )
364+
365+ expect ( outlined . findComponent ( { name : 'VarMenuSelect' } ) . props ( 'popoverClass' ) ) . toBe ( '' )
366+ outlined . unmount ( )
367+ } )
368+
336369test ( 'auto-complete slots' , ( ) => {
337370 const wrapper = mount ( AutoComplete , {
338371 slots : {
@@ -347,6 +380,65 @@ test('auto-complete slots', () => {
347380 wrapper . unmount ( )
348381} )
349382
383+ test ( 'auto-complete extra-message slot renders' , async ( ) => {
384+ const wrapper = mount ( AutoComplete , {
385+ slots : {
386+ 'extra-message' : ( ) => 'extra-message' ,
387+ } ,
388+ } )
389+
390+ await nextTick ( )
391+ expect ( wrapper . vm . $slots [ 'extra-message' ] ) . toBeTruthy ( )
392+ expect ( wrapper . findComponent ( { name : 'VarInput' } ) . vm . $slots [ 'extra-message' ] ) . toBeTruthy ( )
393+ wrapper . unmount ( )
394+ } )
395+
396+ test ( 'auto-complete passes extra-message slot to input' , ( ) => {
397+ const wrapper = mount ( AutoComplete , {
398+ slots : {
399+ 'extra-message' : ( ) => 'extra-message' ,
400+ } ,
401+ global : {
402+ stubs : {
403+ VarMenuSelect : {
404+ template : '<div><slot /><slot name="options" /></div>' ,
405+ } ,
406+ VarInput : {
407+ template : '<div class="stub-input"><slot name="extra-message" /></div>' ,
408+ } ,
409+ VarFormDetails : true ,
410+ } ,
411+ } ,
412+ } )
413+
414+ expect ( wrapper . find ( '.stub-input' ) . text ( ) ) . toContain ( 'extra-message' )
415+ wrapper . unmount ( )
416+ } )
417+
418+ test ( 'auto-complete tabindex behavior' , ( ) => {
419+ const defaultTab = mount ( AutoComplete )
420+
421+ expect ( defaultTab . attributes ( 'tabindex' ) ) . toBe ( '0' )
422+ defaultTab . unmount ( )
423+
424+ const disabledTab = mount ( AutoComplete , {
425+ props : {
426+ disabled : true ,
427+ } ,
428+ } )
429+
430+ expect ( disabledTab . attributes ( 'tabindex' ) ) . toBeUndefined ( )
431+ disabledTab . unmount ( )
432+
433+ const customTab = mount ( AutoComplete , {
434+ props : {
435+ tabindex : '3' ,
436+ } ,
437+ } )
438+
439+ expect ( customTab . attributes ( 'tabindex' ) ) . toBe ( '3' )
440+ customTab . unmount ( )
441+ } )
350442test ( 'auto-complete validation' , async ( ) => {
351443 const onUpdateModelValue = vi . fn ( )
352444 const wrapper = mount ( AutoComplete , {
@@ -389,6 +481,7 @@ test('auto-complete click outside', async () => {
389481
390482 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( 'none' )
391483 await wrapper . trigger ( 'focusin' )
484+ await nextTick ( )
392485 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( '' )
393486
394487 await trigger ( document , 'click' )
@@ -397,6 +490,31 @@ test('auto-complete click outside', async () => {
397490 wrapper . unmount ( )
398491} )
399492
493+ test ( 'auto-complete ignore click outside after clear' , async ( ) => {
494+ const onBlur = vi . fn ( )
495+ const wrapper = mount ( AutoComplete , {
496+ props : {
497+ modelValue : 'a' ,
498+ clearable : true ,
499+ onBlur,
500+ options : [
501+ {
502+ value : 'Option 1' ,
503+ label : 'Option 1' ,
504+ } ,
505+ ] ,
506+ } ,
507+ } )
508+
509+ await wrapper . trigger ( 'focusin' )
510+ await wrapper . find ( '.var-icon-close-circle' ) . trigger ( 'click' )
511+ await trigger ( document , 'click' )
512+
513+ expect ( onBlur ) . not . toHaveBeenCalled ( )
514+
515+ wrapper . unmount ( )
516+ } )
517+
400518test ( 'auto-complete select option by keyboard' , async ( ) => {
401519 const onUpdateModelValue = vi . fn ( )
402520 const wrapper = mount ( AutoComplete , {
@@ -418,6 +536,7 @@ test('auto-complete select option by keyboard', async () => {
418536
419537 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( 'none' )
420538 await wrapper . trigger ( 'focusin' )
539+ await nextTick ( )
421540 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( '' )
422541
423542 await triggerKeyboard ( window , 'keydown' , { key : 'ArrowDown' } )
@@ -447,6 +566,7 @@ test('auto-complete close menu by keyboard tab', async () => {
447566
448567 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( 'none' )
449568 await wrapper . trigger ( 'focusin' )
569+ await nextTick ( )
450570 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( '' )
451571
452572 await triggerKeyboard ( window , 'keydown' , { key : 'Tab' } )
@@ -455,6 +575,81 @@ test('auto-complete close menu by keyboard tab', async () => {
455575 wrapper . unmount ( )
456576} )
457577
578+ test ( 'auto-complete keyboard ignores when menu hidden' , async ( ) => {
579+ const wrapper = mount ( AutoComplete , {
580+ props : {
581+ modelValue : 'a' ,
582+ options : [
583+ {
584+ value : 'Option 1' ,
585+ label : 'Option 1' ,
586+ } ,
587+ ] ,
588+ } ,
589+ } )
590+
591+ await triggerKeyboard ( window , 'keydown' , { key : 'ArrowDown' } )
592+ expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( 'none' )
593+
594+ wrapper . unmount ( )
595+ } )
596+
597+ test ( 'auto-complete keyboard focuses input for other keys' , async ( ) => {
598+ const wrapper = mount ( AutoComplete , {
599+ props : {
600+ modelValue : 'a' ,
601+ options : [
602+ {
603+ value : 'Option 1' ,
604+ label : 'Option 1' ,
605+ } ,
606+ ] ,
607+ } ,
608+ } )
609+
610+ const focusSpy = vi . fn ( )
611+ wrapper . vm . input . focus = focusSpy
612+
613+ await wrapper . trigger ( 'focusin' )
614+ await triggerKeyboard ( window , 'keydown' , { key : 'A' } )
615+
616+ expect ( focusSpy ) . toHaveBeenCalled ( )
617+
618+ wrapper . unmount ( )
619+ } )
620+
621+ test ( 'auto-complete blur ignored when menu open' , async ( ) => {
622+ const onBlur = vi . fn ( )
623+ const wrapper = mount ( AutoComplete , {
624+ props : {
625+ modelValue : 'a' ,
626+ options : [
627+ {
628+ value : 'Option 1' ,
629+ label : 'Option 1' ,
630+ } ,
631+ ] ,
632+ onBlur,
633+ } ,
634+ } )
635+
636+ await wrapper . trigger ( 'focusin' )
637+ await wrapper . find ( 'input' ) . trigger ( 'blur' )
638+ expect ( onBlur ) . not . toHaveBeenCalled ( )
639+
640+ wrapper . unmount ( )
641+ } )
642+
643+ test ( 'auto-complete key-escape focuses input' , ( ) => {
644+ const wrapper = mount ( AutoComplete )
645+ const focusSpy = vi . fn ( )
646+ wrapper . vm . input . focus = focusSpy
647+
648+ wrapper . vm . handleKeyEscape ( )
649+ expect ( focusSpy ) . toHaveBeenCalled ( )
650+
651+ wrapper . unmount ( )
652+ } )
458653test ( 'auto-complete handle same value by option' , async ( ) => {
459654 const onChange = vi . fn ( )
460655 const wrapper = mount ( AutoComplete , {
@@ -472,6 +667,7 @@ test('auto-complete handle same value by option', async () => {
472667
473668 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( 'none' )
474669 await wrapper . trigger ( 'focusin' )
670+ await nextTick ( )
475671 expect ( document . querySelector ( '.var-menu__menu' ) . style . display ) . toBe ( '' )
476672
477673 await trigger ( document . querySelector ( '.var-menu-option' ) , 'click' )
0 commit comments