11import { afterEach , beforeEach , test } from 'node:test'
2- import { Looper } from './looper.ts'
2+ import { Looper , type LoopReason } from './looper.ts'
33import { assert } from './test/assert.ts'
44import { TestEvent } from './test/test-event.ts'
55import type { Millis } from './types/time.ts'
@@ -27,7 +27,9 @@ afterEach(() => {
2727test ( 'Looper' , async ctx => {
2828 using framer = new Looper ( )
2929 let frame = 0
30- framer . onFrame = ( ) => ++ frame
30+ framer . onFrame = ( _millis , _reason ) => {
31+ ++ frame
32+ }
3133
3234 await ctx . test ( 'init' , ( ) => assert ( frame , 0 ) )
3335
@@ -39,27 +41,27 @@ test('Looper', async ctx => {
3941
4042 await ctx . test ( 'onFrame()' , ( ) => {
4143 performance . now = ( ) => 8 as Millis
42- framer . requestFrame ( )
44+ framer . requestFrame ( 'Render' )
4345 performance . now = ( ) => 24 as Millis // millis = 24 - 8 = 16
4446 onFrame ! ( )
4547 assert ( frame , 1 )
4648 assert ( framer . age , 16 as Millis )
4749 performance . now = ( ) => 40 as Millis
48- framer . requestFrame ( )
50+ framer . requestFrame ( 'Render' )
4951 performance . now = ( ) => 56 as Millis // millis = 56 - 40 = 16
5052 onFrame ! ( )
5153 assert ( frame , 2 )
5254 assert ( framer . age , 32 as Millis )
5355 performance . now = ( ) => 72 as Millis
54- framer . requestFrame ( )
56+ framer . requestFrame ( 'Render' )
5557 performance . now = ( ) => 88 as Millis // millis = 88 - 72 = 16
5658 onFrame ! ( )
5759 assert ( frame , 3 )
5860 assert ( framer . age , 48 as Millis )
5961 } )
6062
6163 await ctx . test ( 'hidden' , ( ) => {
62- framer . requestFrame ( )
64+ framer . requestFrame ( 'Render' )
6365 doc . hidden = true
6466 doc . dispatchEvent ( TestEvent ( 'visibilitychange' ) )
6567 assert ( onFrame , undefined )
@@ -75,3 +77,82 @@ test('Looper', async ctx => {
7577 assert ( framer . age , 64 as Millis ) // 48 + 16
7678 } )
7779} )
80+
81+ test ( 'poll reason' , async ctx => {
82+ using framer = new Looper ( )
83+ let frame = 0
84+ let lastReason : LoopReason | undefined
85+ let skip : 'Skip' | undefined
86+ framer . onFrame = ( _millis , reason ) => {
87+ ++ frame
88+ lastReason = reason
89+ return skip
90+ }
91+ framer . register ( 'add' )
92+
93+ await ctx . test ( 'requestFrame(Render) passes Render reason' , ( ) => {
94+ performance . now = ( ) => 0 as Millis
95+ framer . requestFrame ( 'Render' )
96+ performance . now = ( ) => 16 as Millis
97+ onFrame ! ( )
98+ assert ( frame , 1 )
99+ assert ( lastReason , 'Render' )
100+ } )
101+
102+ await ctx . test ( 'requestFrame(Poll) passes Poll reason' , ( ) => {
103+ performance . now = ( ) => 16 as Millis
104+ framer . requestFrame ( 'Poll' )
105+ performance . now = ( ) => 32 as Millis
106+ onFrame ! ( )
107+ assert ( frame , 2 )
108+ assert ( lastReason , 'Poll' )
109+ } )
110+
111+ await ctx . test ( 'upgrade poll to render' , ( ) => {
112+ performance . now = ( ) => 32 as Millis
113+ framer . requestFrame ( 'Poll' )
114+ // non-poll call upgrades pending poll.
115+ framer . requestFrame ( 'Render' )
116+ performance . now = ( ) => 48 as Millis
117+ onFrame ! ( )
118+ assert ( frame , 3 )
119+ assert ( lastReason , 'Render' )
120+ } )
121+
122+ await ctx . test ( 'poll does not upgrade to poll' , ( ) => {
123+ performance . now = ( ) => 48 as Millis
124+ framer . requestFrame ( 'Poll' )
125+ // another poll call doesn't schedule a second rAF.
126+ framer . requestFrame ( 'Poll' )
127+ performance . now = ( ) => 64 as Millis
128+ onFrame ! ( )
129+ assert ( frame , 4 )
130+ assert ( lastReason , 'Poll' )
131+ } )
132+
133+ await ctx . test ( 'cancel clears reason' , ( ) => {
134+ performance . now = ( ) => 64 as Millis
135+ framer . requestFrame ( 'Poll' )
136+ framer . register ( 'remove' )
137+ assert ( onFrame , undefined )
138+ // re-register and request normal frame.
139+ framer . register ( 'add' )
140+ performance . now = ( ) => 80 as Millis
141+ framer . requestFrame ( 'Render' )
142+ performance . now = ( ) => 96 as Millis
143+ onFrame ! ( )
144+ assert ( frame , 5 )
145+ assert ( lastReason , 'Render' )
146+ } )
147+
148+ await ctx . test ( 'skip does not accumulate age' , ( ) => {
149+ performance . now = ( ) => 96 as Millis
150+ framer . requestFrame ( 'Poll' )
151+ const ageBefore = framer . age
152+ skip = 'Skip'
153+ performance . now = ( ) => 112 as Millis
154+ onFrame ! ( )
155+ skip = undefined
156+ assert ( framer . age , ageBefore )
157+ } )
158+ } )
0 commit comments