@@ -811,6 +811,202 @@ describe('FakeTimers', () => {
811811 } )
812812 } )
813813
814+ describe ( 'advanceTimersToNextFrame' , ( ) => {
815+ it ( 'runs scheduled animation frame callbacks in order' , ( ) => {
816+ const global = {
817+ Date,
818+ clearTimeout,
819+ process,
820+ requestAnimationFrame : ( ) => - 1 ,
821+ setTimeout,
822+ } as unknown as typeof globalThis
823+
824+ const timers = new FakeTimers ( { global } )
825+ timers . useFakeTimers ( )
826+
827+ const runOrder : Array < string > = [ ]
828+ const mock1 = vi . fn ( ( ) => runOrder . push ( 'mock1' ) )
829+ const mock2 = vi . fn ( ( ) => runOrder . push ( 'mock2' ) )
830+ const mock3 = vi . fn ( ( ) => runOrder . push ( 'mock3' ) )
831+
832+ global . requestAnimationFrame ( mock1 )
833+ global . requestAnimationFrame ( mock2 )
834+ global . requestAnimationFrame ( mock3 )
835+
836+ timers . advanceTimersToNextFrame ( )
837+
838+ expect ( runOrder ) . toEqual ( [ 'mock1' , 'mock2' , 'mock3' ] )
839+ } )
840+
841+ it ( 'should only run currently scheduled animation frame callbacks' , ( ) => {
842+ const global = {
843+ Date,
844+ clearTimeout,
845+ process,
846+ requestAnimationFrame : ( ) => - 1 ,
847+ setTimeout,
848+ } as unknown as typeof globalThis
849+
850+ const timers = new FakeTimers ( { global } )
851+ timers . useFakeTimers ( )
852+
853+ const runOrder : Array < string > = [ ]
854+ function run ( ) {
855+ runOrder . push ( 'first-frame' )
856+
857+ // scheduling another animation frame in the first frame
858+ global . requestAnimationFrame ( ( ) => runOrder . push ( 'second-frame' ) )
859+ }
860+
861+ global . requestAnimationFrame ( run )
862+
863+ // only the first frame should be executed
864+ timers . advanceTimersToNextFrame ( )
865+
866+ expect ( runOrder ) . toEqual ( [ 'first-frame' ] )
867+
868+ timers . advanceTimersToNextFrame ( )
869+
870+ expect ( runOrder ) . toEqual ( [ 'first-frame' , 'second-frame' ] )
871+ } )
872+
873+ it ( 'should allow cancelling of scheduled animation frame callbacks' , ( ) => {
874+ const global = {
875+ Date,
876+ cancelAnimationFrame : ( ) => { } ,
877+ clearTimeout,
878+ process,
879+ requestAnimationFrame : ( ) => - 1 ,
880+ setTimeout,
881+ } as unknown as typeof globalThis
882+
883+ const timers = new FakeTimers ( { global } )
884+ const callback = vi . fn ( )
885+ timers . useFakeTimers ( )
886+
887+ const timerId = global . requestAnimationFrame ( callback )
888+ global . cancelAnimationFrame ( timerId )
889+
890+ timers . advanceTimersToNextFrame ( )
891+
892+ expect ( callback ) . not . toHaveBeenCalled ( )
893+ } )
894+
895+ it ( 'should only advance as much time is needed to get to the next frame' , ( ) => {
896+ const global = {
897+ Date,
898+ cancelAnimationFrame : ( ) => { } ,
899+ clearTimeout,
900+ process,
901+ requestAnimationFrame : ( ) => - 1 ,
902+ setTimeout,
903+ } as unknown as typeof globalThis
904+
905+ const timers = new FakeTimers ( { global } )
906+ timers . useFakeTimers ( )
907+
908+ const runOrder : Array < string > = [ ]
909+ const start = global . Date . now ( )
910+
911+ const callback = ( ) => runOrder . push ( 'frame' )
912+ global . requestAnimationFrame ( callback )
913+
914+ // Advancing timers less than a frame (which is 16ms)
915+ timers . advanceTimersByTime ( 6 )
916+ expect ( global . Date . now ( ) ) . toEqual ( start + 6 )
917+
918+ // frame not yet executed
919+ expect ( runOrder ) . toEqual ( [ ] )
920+
921+ // move timers forward to execute frame
922+ timers . advanceTimersToNextFrame ( )
923+
924+ // frame has executed as time has moved forward 10ms to get to the 16ms frame time
925+ expect ( runOrder ) . toEqual ( [ 'frame' ] )
926+ expect ( global . Date . now ( ) ) . toEqual ( start + 16 )
927+ } )
928+
929+ it ( 'should execute any timers on the way to the animation frame' , ( ) => {
930+ const global = {
931+ Date,
932+ cancelAnimationFrame : ( ) => { } ,
933+ clearTimeout,
934+ process,
935+ requestAnimationFrame : ( ) => - 1 ,
936+ setTimeout,
937+ } as unknown as typeof globalThis
938+
939+ const timers = new FakeTimers ( { global } )
940+ timers . useFakeTimers ( )
941+
942+ const runOrder : Array < string > = [ ]
943+
944+ global . requestAnimationFrame ( ( ) => runOrder . push ( 'frame' ) )
945+
946+ // scheduling a timeout that will be executed on the way to the frame
947+ global . setTimeout ( ( ) => runOrder . push ( 'timeout' ) , 10 )
948+
949+ // move timers forward to execute frame
950+ timers . advanceTimersToNextFrame ( )
951+
952+ expect ( runOrder ) . toEqual ( [ 'timeout' , 'frame' ] )
953+ } )
954+
955+ it ( 'should not execute any timers scheduled inside of an animation frame callback' , ( ) => {
956+ const global = {
957+ Date,
958+ cancelAnimationFrame : ( ) => { } ,
959+ clearTimeout,
960+ process,
961+ requestAnimationFrame : ( ) => - 1 ,
962+ setTimeout,
963+ } as unknown as typeof globalThis
964+
965+ const timers = new FakeTimers ( { global } )
966+ timers . useFakeTimers ( )
967+
968+ const runOrder : Array < string > = [ ]
969+
970+ global . requestAnimationFrame ( ( ) => {
971+ runOrder . push ( 'frame' )
972+ // scheduling a timer inside of a frame
973+ global . setTimeout ( ( ) => runOrder . push ( 'timeout' ) , 1 )
974+ } )
975+
976+ timers . advanceTimersToNextFrame ( )
977+
978+ // timeout not yet executed
979+ expect ( runOrder ) . toEqual ( [ 'frame' ] )
980+
981+ // validating that the timer will still be executed
982+ timers . advanceTimersByTime ( 1 )
983+ expect ( runOrder ) . toEqual ( [ 'frame' , 'timeout' ] )
984+ } )
985+
986+ it ( 'should call animation frame callbacks with the latest system time' , ( ) => {
987+ const global = {
988+ Date,
989+ clearTimeout,
990+ performance,
991+ process,
992+ requestAnimationFrame : ( ) => - 1 ,
993+ setTimeout,
994+ } as unknown as typeof globalThis
995+
996+ const timers = new FakeTimers ( { global } )
997+ timers . useFakeTimers ( )
998+
999+ const callback = vi . fn ( )
1000+
1001+ global . requestAnimationFrame ( callback )
1002+
1003+ timers . advanceTimersToNextFrame ( )
1004+
1005+ // `requestAnimationFrame` callbacks are called with a `DOMHighResTimeStamp`
1006+ expect ( callback ) . toHaveBeenCalledWith ( global . performance . now ( ) )
1007+ } )
1008+ } )
1009+
8141010 describe ( 'reset' , ( ) => {
8151011 it ( 'resets all pending setTimeouts' , ( ) => {
8161012 const global = { Date : FakeDate , clearTimeout, process, setTimeout }
0 commit comments