@@ -522,6 +522,68 @@ describe("openOnHover", () => {
522522 // should still be open
523523 await expectExists ( t . getContent ( ) ) ;
524524 } ) ;
525+
526+ it ( "should close on second click and not reopen immediately via hover" , async ( ) => {
527+ const t = setupHover ( { triggerProps : { openOnHover : true , openDelay : 0 , closeDelay : 0 } } ) ;
528+
529+ // hover opens
530+ await t . trigger . hover ( ) ;
531+ await expectExists ( t . getContent ( ) ) ;
532+
533+ // first click converts to click-based
534+ await t . trigger . click ( ) ;
535+ await expectExists ( t . getContent ( ) ) ;
536+
537+ // second click closes
538+ await t . trigger . click ( ) ;
539+ await expectNotExists ( t . getContent ( ) ) ;
540+
541+ // should not reopen via hover while mouse is still over trigger
542+ await new Promise ( ( r ) => setTimeout ( r , 50 ) ) ;
543+ await expectNotExists ( t . getContent ( ) ) ;
544+ } ) ;
545+
546+ it ( "should allow hover reopen after leaving and re-entering trigger" , async ( ) => {
547+ const t = setupHover ( { triggerProps : { openOnHover : true , openDelay : 0 , closeDelay : 0 } } ) ;
548+
549+ // hover opens
550+ await t . trigger . hover ( ) ;
551+ await expectExists ( t . getContent ( ) ) ;
552+
553+ // first click converts
554+ await t . trigger . click ( ) ;
555+ await expectExists ( t . getContent ( ) ) ;
556+
557+ // second click closes
558+ await t . trigger . click ( ) ;
559+ await expectNotExists ( t . getContent ( ) ) ;
560+
561+ // leave trigger
562+ await page . getByTestId ( "outside" ) . hover ( ) ;
563+
564+ // re-enter trigger - hover should work again
565+ await t . trigger . hover ( ) ;
566+ await expectExists ( t . getContent ( ) ) ;
567+ } ) ;
568+
569+ it ( "should allow click to explicitly reopen while in cooldown" , async ( ) => {
570+ const t = setupHover ( { triggerProps : { openOnHover : true , openDelay : 0 , closeDelay : 0 } } ) ;
571+
572+ // hover opens
573+ await t . trigger . hover ( ) ;
574+ await expectExists ( t . getContent ( ) ) ;
575+
576+ // first click converts
577+ await t . trigger . click ( ) ;
578+
579+ // second click closes
580+ await t . trigger . click ( ) ;
581+ await expectNotExists ( t . getContent ( ) ) ;
582+
583+ // third click should explicitly reopen
584+ await t . trigger . click ( ) ;
585+ await expectExists ( t . getContent ( ) ) ;
586+ } ) ;
525587} ) ;
526588
527589describe ( "openOnHover with forceMount" , ( ) => {
@@ -770,4 +832,72 @@ describe("openOnHover with forceMount", () => {
770832 // should still be open
771833 await expectExists ( t . getContent ( ) ) ;
772834 } ) ;
835+
836+ it ( "should close on second click and not reopen immediately via hover" , async ( ) => {
837+ const t = setupForceMountHover ( {
838+ triggerProps : { openOnHover : true , openDelay : 0 , closeDelay : 0 } ,
839+ } ) ;
840+
841+ // hover opens
842+ await t . trigger . hover ( ) ;
843+ await expectExists ( t . getContent ( ) ) ;
844+
845+ // first click converts to click-based
846+ await t . trigger . click ( ) ;
847+ await expectExists ( t . getContent ( ) ) ;
848+
849+ // second click closes
850+ await t . trigger . click ( ) ;
851+ await expectNotExists ( t . getContent ( ) ) ;
852+
853+ // should not reopen via hover while mouse is still over trigger
854+ await new Promise ( ( r ) => setTimeout ( r , 50 ) ) ;
855+ await expectNotExists ( t . getContent ( ) ) ;
856+ } ) ;
857+
858+ it ( "should allow hover reopen after leaving and re-entering trigger" , async ( ) => {
859+ const t = setupForceMountHover ( {
860+ triggerProps : { openOnHover : true , openDelay : 0 , closeDelay : 0 } ,
861+ } ) ;
862+
863+ // hover opens
864+ await t . trigger . hover ( ) ;
865+ await expectExists ( t . getContent ( ) ) ;
866+
867+ // first click converts
868+ await t . trigger . click ( ) ;
869+ await expectExists ( t . getContent ( ) ) ;
870+
871+ // second click closes
872+ await t . trigger . click ( ) ;
873+ await expectNotExists ( t . getContent ( ) ) ;
874+
875+ // leave trigger
876+ await t . getOutside ( ) . hover ( ) ;
877+
878+ // re-enter trigger - hover should work again
879+ await t . trigger . hover ( ) ;
880+ await expectExists ( t . getContent ( ) ) ;
881+ } ) ;
882+
883+ it ( "should allow click to explicitly reopen while in cooldown" , async ( ) => {
884+ const t = setupForceMountHover ( {
885+ triggerProps : { openOnHover : true , openDelay : 0 , closeDelay : 0 } ,
886+ } ) ;
887+
888+ // hover opens
889+ await t . trigger . hover ( ) ;
890+ await expectExists ( t . getContent ( ) ) ;
891+
892+ // first click converts
893+ await t . trigger . click ( ) ;
894+
895+ // second click closes
896+ await t . trigger . click ( ) ;
897+ await expectNotExists ( t . getContent ( ) ) ;
898+
899+ // third click should explicitly reopen
900+ await t . trigger . click ( ) ;
901+ await expectExists ( t . getContent ( ) ) ;
902+ } ) ;
773903} ) ;
0 commit comments