@@ -36,29 +36,32 @@ let NormalPriority;
36
36
// It also includes Scheduler-specific invariants, e.g. only one rAF callback
37
37
// can be scheduled at a time.
38
38
describe ( 'SchedulerBrowser' , ( ) => {
39
- beforeEach ( ( ) => {
40
- jest . resetModules ( ) ;
41
-
42
- // Un-mock scheduler
43
- jest . mock ( 'scheduler' , ( ) => require . requireActual ( 'scheduler' ) ) ;
44
- jest . mock ( 'scheduler/src/SchedulerHostConfig' , ( ) =>
45
- require . requireActual (
46
- 'scheduler/src/forks/SchedulerHostConfig.default.js' ,
47
- ) ,
48
- ) ;
49
-
50
- runtime = installMockBrowserRuntime ( ) ;
51
- performance = window . performance ;
52
- Scheduler = require ( 'scheduler' ) ;
53
- scheduleCallback = Scheduler . unstable_scheduleCallback ;
54
- NormalPriority = Scheduler . unstable_NormalPriority ;
55
- } ) ;
39
+ function beforeAndAfterHooks ( enableMessageLoopImplementation ) {
40
+ beforeEach ( ( ) => {
41
+ jest . resetModules ( ) ;
42
+
43
+ // Un-mock scheduler
44
+ jest . mock ( 'scheduler' , ( ) => require . requireActual ( 'scheduler' ) ) ;
45
+ jest . mock ( 'scheduler/src/SchedulerHostConfig' , ( ) =>
46
+ require . requireActual (
47
+ 'scheduler/src/forks/SchedulerHostConfig.default.js' ,
48
+ ) ,
49
+ ) ;
50
+
51
+ runtime = installMockBrowserRuntime ( ) ;
52
+ performance = window . performance ;
53
+ require ( 'scheduler/src/SchedulerFeatureFlags' ) . enableMessageLoopImplementation = enableMessageLoopImplementation ;
54
+ Scheduler = require ( 'scheduler' ) ;
55
+ scheduleCallback = Scheduler . unstable_scheduleCallback ;
56
+ NormalPriority = Scheduler . unstable_NormalPriority ;
57
+ } ) ;
56
58
57
- afterEach ( ( ) => {
58
- if ( ! runtime . isLogEmpty ( ) ) {
59
- throw Error ( 'Test exited without clearing log.' ) ;
60
- }
61
- } ) ;
59
+ afterEach ( ( ) => {
60
+ if ( ! runtime . isLogEmpty ( ) ) {
61
+ throw Error ( 'Test exited without clearing log.' ) ;
62
+ }
63
+ } ) ;
64
+ }
62
65
63
66
function installMockBrowserRuntime ( ) {
64
67
let VSYNC_INTERVAL = 33.33 ;
@@ -228,89 +231,115 @@ describe('SchedulerBrowser', () => {
228
231
} ;
229
232
}
230
233
231
- it ( 'callback with continuation' , ( ) => {
232
- scheduleCallback ( NormalPriority , ( ) => {
233
- runtime . log ( 'Task' ) ;
234
- while ( ! Scheduler . unstable_shouldYield ( ) ) {
235
- runtime . advanceTime ( 1 ) ;
236
- }
237
- runtime . log ( `Yield at ${ performance . now ( ) } ms` ) ;
238
- return ( ) => {
239
- runtime . log ( 'Continuation' ) ;
240
- } ;
234
+ describe ( 'rAF aligned frame boundaries' , ( ) => {
235
+ const enableMessageLoopImplementation = false ;
236
+ beforeAndAfterHooks ( enableMessageLoopImplementation ) ;
237
+
238
+ it ( 'callback with continuation' , ( ) => {
239
+ scheduleCallback ( NormalPriority , ( ) => {
240
+ runtime . log ( 'Task' ) ;
241
+ while ( ! Scheduler . unstable_shouldYield ( ) ) {
242
+ runtime . advanceTime ( 1 ) ;
243
+ }
244
+ runtime . log ( `Yield at ${ performance . now ( ) } ms` ) ;
245
+ return ( ) => {
246
+ runtime . log ( 'Continuation' ) ;
247
+ } ;
248
+ } ) ;
249
+ runtime . assertLog ( [ 'Request Animation Frame' ] ) ;
250
+
251
+ runtime . fireAnimationFrame ( ) ;
252
+ runtime . assertLog ( [
253
+ 'Animation Frame [0]' ,
254
+ 'Request Animation Frame [Reposted]' ,
255
+ 'Set Timer' ,
256
+ 'Post Message' ,
257
+ ] ) ;
258
+ runtime . fireMessageEvent ( ) ;
259
+ runtime . assertLog ( [ 'Message Event' , 'Task' , 'Yield at 34ms' ] ) ;
260
+
261
+ runtime . fireAnimationFrame ( ) ;
262
+ runtime . assertLog ( [
263
+ 'Animation Frame [1]' ,
264
+ 'Request Animation Frame [Reposted]' ,
265
+ 'Set Timer' ,
266
+ 'Post Message' ,
267
+ ] ) ;
268
+
269
+ runtime . fireMessageEvent ( ) ;
270
+ runtime . assertLog ( [ 'Message Event' , 'Continuation' ] ) ;
271
+
272
+ runtime . advanceTimeToNextFrame ( ) ;
273
+ runtime . fireAnimationFrame ( ) ;
274
+ runtime . assertLog ( [ 'Animation Frame [2]' ] ) ;
241
275
} ) ;
242
- runtime . assertLog ( [ 'Request Animation Frame' ] ) ;
243
-
244
- runtime . fireAnimationFrame ( ) ;
245
- runtime . assertLog ( [
246
- 'Animation Frame [0]' ,
247
- 'Request Animation Frame [Reposted]' ,
248
- 'Set Timer' ,
249
- 'Post Message' ,
250
- ] ) ;
251
- runtime . fireMessageEvent ( ) ;
252
- runtime . assertLog ( [ 'Message Event' , 'Task' , 'Yield at 34ms' ] ) ;
253
-
254
- runtime . fireAnimationFrame ( ) ;
255
- runtime . assertLog ( [
256
- 'Animation Frame [1]' ,
257
- 'Request Animation Frame [Reposted]' ,
258
- 'Set Timer' ,
259
- 'Post Message' ,
260
- ] ) ;
261
-
262
- runtime . fireMessageEvent ( ) ;
263
- runtime . assertLog ( [ 'Message Event' , 'Continuation' ] ) ;
264
-
265
- runtime . advanceTimeToNextFrame ( ) ;
266
- runtime . fireAnimationFrame ( ) ;
267
- runtime . assertLog ( [ 'Animation Frame [2]' ] ) ;
268
- } ) ;
269
276
270
- it ( 'two rAF calls in the same frame' , ( ) => {
271
- scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'A' ) ) ;
272
- runtime . assertLog ( [ 'Request Animation Frame' ] ) ;
273
- runtime . fireAnimationFrame ( ) ;
274
- runtime . assertLog ( [
275
- 'Animation Frame [0]' ,
276
- 'Request Animation Frame [Reposted]' ,
277
- 'Set Timer' ,
278
- 'Post Message' ,
279
- ] ) ;
280
- runtime . fireMessageEvent ( ) ;
281
- runtime . assertLog ( [ 'Message Event' , 'A' ] ) ;
282
-
283
- // The Scheduler queue is now empty. We're still in frame 0.
284
- expect ( runtime . getMostRecentFrameNumber ( ) ) . toBe ( 0 ) ;
285
-
286
- // Post a task to Scheduler.
287
- scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'B' ) ) ;
288
-
289
- // Did not request another animation frame, since one was already scheduled
290
- // during the previous rAF.
291
- runtime . assertLog ( [ ] ) ;
292
-
293
- // Fire the animation frame.
294
- runtime . fireAnimationFrame ( ) ;
295
- runtime . assertLog ( [
296
- 'Animation Frame [0]' ,
297
- 'Request Animation Frame [Reposted]' ,
298
- 'Set Timer' ,
299
- 'Post Message' ,
300
- ] ) ;
301
-
302
- runtime . fireMessageEvent ( ) ;
303
- runtime . assertLog ( [ 'Message Event' , 'B' ] ) ;
304
- } ) ;
277
+ it ( 'two rAF calls in the same frame' , ( ) => {
278
+ scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'A' ) ) ;
279
+ runtime . assertLog ( [ 'Request Animation Frame' ] ) ;
280
+ runtime . fireAnimationFrame ( ) ;
281
+ runtime . assertLog ( [
282
+ 'Animation Frame [0]' ,
283
+ 'Request Animation Frame [Reposted]' ,
284
+ 'Set Timer' ,
285
+ 'Post Message' ,
286
+ ] ) ;
287
+ runtime . fireMessageEvent ( ) ;
288
+ runtime . assertLog ( [ 'Message Event' , 'A' ] ) ;
289
+
290
+ // The Scheduler queue is now empty. We're still in frame 0.
291
+ expect ( runtime . getMostRecentFrameNumber ( ) ) . toBe ( 0 ) ;
305
292
306
- it ( 'adjusts frame rate by measuring inteval between rAF events' , ( ) => {
307
- runtime . setHardwareFrameRate ( 60 ) ;
293
+ // Post a task to Scheduler.
294
+ scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'B' ) ) ;
308
295
309
- scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'Tick' ) ) ;
310
- runtime . assertLog ( [ 'Request Animation Frame' ] ) ;
296
+ // Did not request another animation frame, since one was already scheduled
297
+ // during the previous rAF.
298
+ runtime . assertLog ( [ ] ) ;
311
299
312
- // Need to measure two consecutive intervals between frames.
313
- for ( let i = 0 ; i < 2 ; i ++ ) {
300
+ // Fire the animation frame.
301
+ runtime . fireAnimationFrame ( ) ;
302
+ runtime . assertLog ( [
303
+ 'Animation Frame [0]' ,
304
+ 'Request Animation Frame [Reposted]' ,
305
+ 'Set Timer' ,
306
+ 'Post Message' ,
307
+ ] ) ;
308
+
309
+ runtime . fireMessageEvent ( ) ;
310
+ runtime . assertLog ( [ 'Message Event' , 'B' ] ) ;
311
+ } ) ;
312
+
313
+ it ( 'adjusts frame rate by measuring inteval between rAF events' , ( ) => {
314
+ runtime . setHardwareFrameRate ( 60 ) ;
315
+
316
+ scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'Tick' ) ) ;
317
+ runtime . assertLog ( [ 'Request Animation Frame' ] ) ;
318
+
319
+ // Need to measure two consecutive intervals between frames.
320
+ for ( let i = 0 ; i < 2 ; i ++ ) {
321
+ runtime . fireAnimationFrame ( ) ;
322
+ runtime . assertLog ( [
323
+ `Animation Frame [${ runtime . getMostRecentFrameNumber ( ) } ]` ,
324
+ 'Request Animation Frame [Reposted]' ,
325
+ 'Set Timer' ,
326
+ 'Post Message' ,
327
+ ] ) ;
328
+ runtime . fireMessageEvent ( ) ;
329
+ runtime . assertLog ( [ 'Message Event' , 'Tick' ] ) ;
330
+ scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'Tick' ) ) ;
331
+ runtime . advanceTimeToNextFrame ( ) ;
332
+ }
333
+
334
+ // Scheduler should observe that it's receiving rAFs every 16.6 ms and
335
+ // adjust its frame rate accordingly. Test by blocking the thread until
336
+ // Scheduler tells us to yield. Then measure how much time has elapsed.
337
+ const start = performance . now ( ) ;
338
+ scheduleCallback ( NormalPriority , ( ) => {
339
+ while ( ! Scheduler . unstable_shouldYield ( ) ) {
340
+ runtime . advanceTime ( 1 ) ;
341
+ }
342
+ } ) ;
314
343
runtime . fireAnimationFrame ( ) ;
315
344
runtime . assertLog ( [
316
345
`Animation Frame [${ runtime . getMostRecentFrameNumber ( ) } ]` ,
@@ -320,31 +349,57 @@ describe('SchedulerBrowser', () => {
320
349
] ) ;
321
350
runtime . fireMessageEvent ( ) ;
322
351
runtime . assertLog ( [ 'Message Event' , 'Tick' ] ) ;
323
- scheduleCallback ( NormalPriority , ( ) => runtime . log ( 'Tick' ) ) ;
324
- runtime . advanceTimeToNextFrame ( ) ;
325
- }
352
+ const end = performance . now ( ) ;
326
353
327
- // Scheduler should observe that it's receiving rAFs every 16.6 ms and
328
- // adjust its frame rate accordingly. Test by blocking the thread until
329
- // Scheduler tells us to yield. Then measure how much time has elapsed.
330
- const start = performance . now ( ) ;
331
- scheduleCallback ( NormalPriority , ( ) => {
332
- while ( ! Scheduler . unstable_shouldYield ( ) ) {
333
- runtime . advanceTime ( 1 ) ;
334
- }
354
+ // Check how much time elapsed in the frame.
355
+ expect ( end - start ) . toEqual ( 17 ) ;
356
+ } ) ;
357
+ } ) ;
358
+
359
+ describe ( 'message event loop' , ( ) => {
360
+ const enableMessageLoopImplementation = true ;
361
+ beforeAndAfterHooks ( enableMessageLoopImplementation ) ;
362
+
363
+ it ( 'callback with continutation' , ( ) => {
364
+ scheduleCallback ( NormalPriority , ( ) => {
365
+ runtime . log ( 'Task' ) ;
366
+ while ( ! Scheduler . unstable_shouldYield ( ) ) {
367
+ runtime . advanceTime ( 1 ) ;
368
+ }
369
+ runtime . log ( `Yield at ${ performance . now ( ) } ms` ) ;
370
+ return ( ) => {
371
+ runtime . log ( 'Continuation' ) ;
372
+ } ;
373
+ } ) ;
374
+ runtime . assertLog ( [ 'Post Message' ] ) ;
375
+
376
+ runtime . fireMessageEvent ( ) ;
377
+ runtime . assertLog ( [
378
+ 'Message Event' ,
379
+ 'Task' ,
380
+ 'Yield at 5ms' ,
381
+ 'Post Message' ,
382
+ ] ) ;
383
+
384
+ runtime . fireMessageEvent ( ) ;
385
+ runtime . assertLog ( [ 'Message Event' , 'Continuation' ] ) ;
386
+ } ) ;
387
+
388
+ it ( 'task that throws' , ( ) => {
389
+ scheduleCallback ( NormalPriority , ( ) => {
390
+ runtime . log ( 'Oops!' ) ;
391
+ throw Error ( 'Oops!' ) ;
392
+ } ) ;
393
+ scheduleCallback ( NormalPriority , ( ) => {
394
+ runtime . log ( 'Yay' ) ;
395
+ } ) ;
396
+ runtime . assertLog ( [ 'Post Message' ] ) ;
397
+
398
+ expect ( ( ) => runtime . fireMessageEvent ( ) ) . toThrow ( 'Oops!' ) ;
399
+ runtime . assertLog ( [ 'Message Event' , 'Oops!' , 'Post Message' ] ) ;
400
+
401
+ runtime . fireMessageEvent ( ) ;
402
+ runtime . assertLog ( [ 'Message Event' , 'Yay' ] ) ;
335
403
} ) ;
336
- runtime . fireAnimationFrame ( ) ;
337
- runtime . assertLog ( [
338
- `Animation Frame [${ runtime . getMostRecentFrameNumber ( ) } ]` ,
339
- 'Request Animation Frame [Reposted]' ,
340
- 'Set Timer' ,
341
- 'Post Message' ,
342
- ] ) ;
343
- runtime . fireMessageEvent ( ) ;
344
- runtime . assertLog ( [ 'Message Event' , 'Tick' ] ) ;
345
- const end = performance . now ( ) ;
346
-
347
- // Check how much time elapsed in the frame.
348
- expect ( end - start ) . toEqual ( 17 ) ;
349
404
} ) ;
350
405
} ) ;
0 commit comments