@@ -421,4 +421,74 @@ describe('FeaturedCustomer touch navigation', () => {
421421 expect ( touch ( 'touchend' , 250 , 200 , 1 , 0 , previousPreview ) . defaultPrevented ) . toBe ( true )
422422 expect ( currentStory ( ) ) . toBe ( '1 of 2: Rivian' )
423423 } )
424+
425+ describe ( 'wheel navigation' , ( ) => {
426+ beforeEach ( ( ) => {
427+ vi . useFakeTimers ( )
428+ Object . defineProperty ( rail , 'clientWidth' , { value : 390 } )
429+ } )
430+
431+ function wheel ( options : WheelEventInit ) {
432+ const event = new WheelEvent ( 'wheel' , { bubbles : true , cancelable : true , ...options } )
433+ act ( ( ) => rail . dispatchEvent ( event ) )
434+ return event
435+ }
436+
437+ it ( 'accumulates horizontal movement and navigates only once until the gesture ends' , ( ) => {
438+ wheel ( { deltaX : 20 , deltaY : 2 } )
439+ expect ( currentStory ( ) ) . toBe ( '1 of 2: Rivian' )
440+ act ( ( ) => vi . advanceTimersByTime ( 20 ) )
441+ expect ( wheel ( { deltaX : 35 , deltaY : 3 } ) . defaultPrevented ) . toBe ( true )
442+ expect ( currentStory ( ) ) . toBe ( '2 of 2: eXp Realty' )
443+
444+ for ( let index = 0 ; index < 5 ; index += 1 ) {
445+ act ( ( ) => vi . advanceTimersByTime ( 100 ) )
446+ wheel ( { deltaX : - 80 } )
447+ expect ( currentStory ( ) ) . toBe ( '2 of 2: eXp Realty' )
448+ }
449+
450+ act ( ( ) => vi . advanceTimersByTime ( 250 ) )
451+ wheel ( { deltaX : - 80 } )
452+ expect ( currentStory ( ) ) . toBe ( '1 of 2: Rivian' )
453+ act ( ( ) => vi . advanceTimersByTime ( 250 ) )
454+ wheel ( { deltaX : - 80 } )
455+ expect ( currentStory ( ) ) . toBe ( '1 of 2: Rivian' )
456+ } )
457+
458+ it . each ( [
459+ { deltaY : 80 , shiftKey : true } ,
460+ { deltaX : 80 , shiftKey : true } ,
461+ { deltaY : 4 , deltaMode : 1 , shiftKey : true } ,
462+ { deltaY : 1 , deltaMode : 2 , shiftKey : true } ,
463+ ] ) ( 'supports horizontal and Shift+wheel deltas: %j' , ( options ) => {
464+ expect ( wheel ( options ) . defaultPrevented ) . toBe ( true )
465+ expect ( currentStory ( ) ) . toBe ( '2 of 2: eXp Realty' )
466+ } )
467+
468+ it . each ( [
469+ { deltaY : 120 } ,
470+ { deltaX : 20 , deltaY : 120 } ,
471+ { deltaX : 120 , ctrlKey : true } ,
472+ { deltaY : 120 , ctrlKey : true , shiftKey : true } ,
473+ { deltaX : 120 , metaKey : true } ,
474+ ] ) ( 'preserves browser scrolling and zoom: %j' , ( options ) => {
475+ expect ( wheel ( options ) . defaultPrevented ) . toBe ( false )
476+ expect ( currentStory ( ) ) . toBe ( '1 of 2: Rivian' )
477+ } )
478+
479+ it ( 'discards incomplete movement after an idle gap or vertical scrolling' , ( ) => {
480+ wheel ( { deltaX : 30 } )
481+ act ( ( ) => vi . advanceTimersByTime ( 250 ) )
482+ wheel ( { deltaX : 30 } )
483+ expect ( currentStory ( ) ) . toBe ( '1 of 2: Rivian' )
484+ wheel ( { deltaY : 100 } )
485+ wheel ( { deltaX : 30 } )
486+ expect ( currentStory ( ) ) . toBe ( '1 of 2: Rivian' )
487+ } )
488+
489+ it ( 'removes the wheel listener when the carousel unmounts' , ( ) => {
490+ act ( ( ) => root . render ( null ) )
491+ expect ( wheel ( { deltaX : 120 } ) . defaultPrevented ) . toBe ( false )
492+ } )
493+ } )
424494} )
0 commit comments