@@ -33,6 +33,7 @@ describe('Scheduler', () => {
3333 let isFlushing = false ;
3434 let timeoutID = - 1 ;
3535 let endOfFrame = - 1 ;
36+ let hasMicrotask = false ;
3637
3738 let currentTime = 0 ;
3839
@@ -54,6 +55,9 @@ describe('Scheduler', () => {
5455 } finally {
5556 isFlushing = false ;
5657 endOfFrame = - 1 ;
58+ if ( hasMicrotask ) {
59+ onTimeout ( ) ;
60+ }
5761 }
5862 const yields = yieldedValues ;
5963 yieldedValues = [ ] ;
@@ -89,14 +93,13 @@ describe('Scheduler', () => {
8993 return ;
9094 }
9195 if ( isFlushing ) {
92- // Jest fires timers synchronously when jest.advanceTimersByTime is
93- // called. Use setImmediate to prevent re-entrancy.
94- setImmediate ( onTimeout ) ;
96+ hasMicrotask = true ;
9597 } else {
9698 try {
9799 isFlushing = true ;
98100 _flushWork ( true ) ;
99101 } finally {
102+ hasMicrotask = false ;
100103 isFlushing = false ;
101104 }
102105 }
@@ -153,6 +156,55 @@ describe('Scheduler', () => {
153156 expect ( flushWork ( 400 ) ) . toEqual ( [ 'D' ] ) ;
154157 } ) ;
155158
159+ it ( 'flushes work until framesize reached' , ( ) => {
160+ scheduleCallback ( ( ) => doWork ( 'A1_100' , 100 ) ) ;
161+ scheduleCallback ( ( ) => doWork ( 'A2_200' , 200 ) ) ;
162+ scheduleCallback ( ( ) => doWork ( 'B1_100' , 100 ) ) ;
163+ scheduleCallback ( ( ) => doWork ( 'B2_200' , 200 ) ) ;
164+ scheduleCallback ( ( ) => doWork ( 'C1_300' , 300 ) ) ;
165+ scheduleCallback ( ( ) => doWork ( 'C2_300' , 300 ) ) ;
166+ scheduleCallback ( ( ) => doWork ( 'D_3000' , 3000 ) ) ;
167+ scheduleCallback ( ( ) => doWork ( 'E1_300' , 300 ) ) ;
168+ scheduleCallback ( ( ) => doWork ( 'E2_200' , 200 ) ) ;
169+ scheduleCallback ( ( ) => doWork ( 'F1_200' , 200 ) ) ;
170+ scheduleCallback ( ( ) => doWork ( 'F2_200' , 200 ) ) ;
171+ scheduleCallback ( ( ) => doWork ( 'F3_300' , 300 ) ) ;
172+ scheduleCallback ( ( ) => doWork ( 'F4_500' , 500 ) ) ;
173+ scheduleCallback ( ( ) => doWork ( 'F5_200' , 200 ) ) ;
174+ scheduleCallback ( ( ) => doWork ( 'F6_20' , 20 ) ) ;
175+
176+ expect ( Date . now ( ) ) . toEqual ( 0 ) ;
177+ // No time left after A1_100 and A2_200 are run
178+ expect ( flushWork ( 300 ) ) . toEqual ( [ 'A1_100' , 'A2_200' ] ) ;
179+ expect ( Date . now ( ) ) . toEqual ( 300 ) ;
180+ // B2_200 is started as there is still time left after B1_100
181+ expect ( flushWork ( 101 ) ) . toEqual ( [ 'B1_100' , 'B2_200' ] ) ;
182+ expect ( Date . now ( ) ) . toEqual ( 600 ) ;
183+ // C1_300 is started as there is even a little frame time
184+ expect ( flushWork ( 1 ) ) . toEqual ( [ 'C1_300' ] ) ;
185+ expect ( Date . now ( ) ) . toEqual ( 900 ) ;
186+ // C2_300 is started even though there is no frame time
187+ expect ( flushWork ( 0 ) ) . toEqual ( [ 'C2_300' ] ) ;
188+ expect ( Date . now ( ) ) . toEqual ( 1200 ) ;
189+ // D_3000 is very slow, but won't affect next flushes (if no
190+ // timeouts happen)
191+ expect ( flushWork ( 100 ) ) . toEqual ( [ 'D_3000' ] ) ;
192+ expect ( Date . now ( ) ) . toEqual ( 4200 ) ;
193+ expect ( flushWork ( 400 ) ) . toEqual ( [ 'E1_300' , 'E2_200' ] ) ;
194+ expect ( Date . now ( ) ) . toEqual ( 4700 ) ;
195+ // Default timeout is 5000, so during F2_200, work will timeout and are done
196+ // in reverse, including F2_200
197+ expect ( flushWork ( 1000 ) ) . toEqual ( [
198+ 'F1_200' ,
199+ 'F2_200' ,
200+ 'F3_300' ,
201+ 'F4_500' ,
202+ 'F5_200' ,
203+ 'F6_20' ,
204+ ] ) ;
205+ expect ( Date . now ( ) ) . toEqual ( 6120 ) ;
206+ } ) ;
207+
156208 it ( 'cancels work' , ( ) => {
157209 scheduleCallback ( ( ) => doWork ( 'A' , 100 ) ) ;
158210 const callbackHandleB = scheduleCallback ( ( ) => doWork ( 'B' , 200 ) ) ;
@@ -246,7 +298,7 @@ describe('Scheduler', () => {
246298 } ) ;
247299
248300 it ( 'continuation callbacks inherit the expiration of the previous callback' , ( ) => {
249- const tasks = [ [ 'A' , 125 ] , [ 'B' , 125 ] , [ 'C' , 125 ] , [ 'D' , 125 ] ] ;
301+ const tasks = [ [ 'A' , 125 ] , [ 'B' , 124 ] , [ 'C' , 100 ] , [ 'D' , 100 ] ] ;
250302 const work = deadline => {
251303 while ( tasks . length > 0 ) {
252304 doWork ( ...tasks . shift ( ) ) ;
0 commit comments