9
10
'use strict';
11
12
+let Scheduler;
13
let runWithPriority;
14
let ImmediatePriority;
15
let UserBlockingPriority;
19
let wrapCallback;
20
let getCurrentPriorityLevel;
21
let shouldYield;
21
-let flushWork;
22
-let advanceTime;
23
-let doWork;
24
-let yieldedValues;
25
-let yieldValue;
26
-let clearYieldedValues;
22
23
describe('Scheduler', () => {
24
beforeEach(() => {
30
- jest.useFakeTimers();
25
jest.resetModules();
32
-
33
- const JestMockScheduler = require('jest-mock-scheduler');
34
- JestMockScheduler.mockRestore();
35
-
36
- let _flushWork = null;
37
- let isFlushing = false;
38
- let timeoutID = -1;
39
- let endOfFrame = -1;
40
- let hasMicrotask = false;
41
-
42
- let currentTime = 0;
43
-
44
- flushWork = frameSize => {
45
- if (isFlushing) {
46
- throw new Error('Already flushing work.');
47
- }
48
- if (frameSize === null || frameSize === undefined) {
49
- frameSize = Infinity;
50
- }
51
- if (_flushWork === null) {
52
- throw new Error('No work is scheduled.');
53
- }
54
- timeoutID = -1;
55
- endOfFrame = currentTime + frameSize;
56
- try {
57
- isFlushing = true;
58
- _flushWork(false);
59
- } finally {
60
- isFlushing = false;
61
- endOfFrame = -1;
62
- if (hasMicrotask) {
63
- onTimeout();
64
- }
65
- }
66
- const yields = yieldedValues;
67
- yieldedValues = [];
68
- return yields;
69
- };
70
-
71
- advanceTime = ms => {
72
- currentTime += ms;
73
- jest.advanceTimersByTime(ms);
74
- };
75
-
76
- doWork = (label, timeCost) => {
77
- if (typeof timeCost !== 'number') {
78
- throw new Error('Second arg must be a number.');
79
- }
80
- advanceTime(timeCost);
81
- yieldValue(label);
82
- };
83
-
84
- yieldedValues = [];
85
- yieldValue = value => {
86
- yieldedValues.push(value);
87
- };
88
-
89
- clearYieldedValues = () => {
90
- const yields = yieldedValues;
91
- yieldedValues = [];
92
- return yields;
93
- };
94
-
95
- function onTimeout() {
96
- if (_flushWork === null) {
97
- return;
98
- }
99
- if (isFlushing) {
100
- hasMicrotask = true;
101
- } else {
102
- try {
103
- isFlushing = true;
104
- _flushWork(true);
105
- } finally {
106
- hasMicrotask = false;
107
- isFlushing = false;
108
- }
109
- }
110
- }
111
-
112
- function requestHostCallback(fw, absoluteTimeout) {
113
- if (_flushWork !== null) {
114
- throw new Error('Work is already scheduled.');
115
- }
116
- _flushWork = fw;
117
- timeoutID = setTimeout(onTimeout, absoluteTimeout - currentTime);
118
- }
119
- function cancelHostCallback() {
120
- if (_flushWork === null) {
121
- throw new Error('No work is scheduled.');
122
- }
123
- _flushWork = null;
124
- clearTimeout(timeoutID);
125
- }
126
- function shouldYieldToHost() {
127
- return endOfFrame <= currentTime;
128
- }
129
- function getCurrentTime() {
130
- return currentTime;
131
- }
132
-
133
- // Override host implementation
134
- delete global.performance;
135
- global.Date.now = () => {
136
- return currentTime;
137
- };
138
-
139
- window._schedMock = [
140
- requestHostCallback,
141
- cancelHostCallback,
142
- shouldYieldToHost,
143
- getCurrentTime,
144
- ];
145
-
146
- const Schedule = require('scheduler');
147
- runWithPriority = Schedule.unstable_runWithPriority;
148
- ImmediatePriority = Schedule.unstable_ImmediatePriority;
149
- UserBlockingPriority = Schedule.unstable_UserBlockingPriority;
150
- NormalPriority = Schedule.unstable_NormalPriority;
151
- scheduleCallback = Schedule.unstable_scheduleCallback;
152
- cancelCallback = Schedule.unstable_cancelCallback;
153
- wrapCallback = Schedule.unstable_wrapCallback;
154
- getCurrentPriorityLevel = Schedule.unstable_getCurrentPriorityLevel;
155
- shouldYield = Schedule.unstable_shouldYield;
26
+ jest.mock('scheduler', () => require('scheduler/unstable_mock'));
27
+
28
+ Scheduler = require('scheduler');
29
+
30
+ runWithPriority = Scheduler.unstable_runWithPriority;
31
+ ImmediatePriority = Scheduler.unstable_ImmediatePriority;
32
+ UserBlockingPriority = Scheduler.unstable_UserBlockingPriority;
33
+ NormalPriority = Scheduler.unstable_NormalPriority;
34
+ scheduleCallback = Scheduler.unstable_scheduleCallback;
35
+ cancelCallback = Scheduler.unstable_cancelCallback;
36
+ wrapCallback = Scheduler.unstable_wrapCallback;
37
+ getCurrentPriorityLevel = Scheduler.unstable_getCurrentPriorityLevel;
38
+ shouldYield = Scheduler.unstable_shouldYield;
39
});
40
41
it('flushes work incrementally', () => {
159
- scheduleCallback(() => doWork('A', 100));
160
- scheduleCallback(() => doWork('B', 200));
161
- scheduleCallback(() => doWork('C', 300));
162
- scheduleCallback(() => doWork('D', 400));
163
-
164
- expect(flushWork(300)).toEqual(['A', 'B']);
165
- expect(flushWork(300)).toEqual(['C']);
166
- expect(flushWork(400)).toEqual(['D']);
167
- });
168
-
169
- it('flushes work until framesize reached', () => {
170
- scheduleCallback(() => doWork('A1_100', 100));
171
- scheduleCallback(() => doWork('A2_200', 200));
172
- scheduleCallback(() => doWork('B1_100', 100));
173
- scheduleCallback(() => doWork('B2_200', 200));
174
- scheduleCallback(() => doWork('C1_300', 300));
175
- scheduleCallback(() => doWork('C2_300', 300));
176
- scheduleCallback(() => doWork('D_3000', 3000));
177
- scheduleCallback(() => doWork('E1_300', 300));
178
- scheduleCallback(() => doWork('E2_200', 200));
179
- scheduleCallback(() => doWork('F1_200', 200));
180
- scheduleCallback(() => doWork('F2_200', 200));
181
- scheduleCallback(() => doWork('F3_300', 300));
182
- scheduleCallback(() => doWork('F4_500', 500));
183
- scheduleCallback(() => doWork('F5_200', 200));
184
- scheduleCallback(() => doWork('F6_20', 20));
185
-
186
- expect(Date.now()).toEqual(0);
187
- // No time left after A1_100 and A2_200 are run
188
- expect(flushWork(300)).toEqual(['A1_100', 'A2_200']);
189
- expect(Date.now()).toEqual(300);
190
- // B2_200 is started as there is still time left after B1_100
191
- expect(flushWork(101)).toEqual(['B1_100', 'B2_200']);
192
- expect(Date.now()).toEqual(600);
193
- // C1_300 is started as there is even a little frame time
194
- expect(flushWork(1)).toEqual(['C1_300']);
195
- expect(Date.now()).toEqual(900);
196
- // C2_300 is started even though there is no frame time
197
- expect(flushWork(0)).toEqual(['C2_300']);
198
- expect(Date.now()).toEqual(1200);
199
- // D_3000 is very slow, but won't affect next flushes (if no
200
- // timeouts happen)
201
- expect(flushWork(100)).toEqual(['D_3000']);
202
- expect(Date.now()).toEqual(4200);
203
- expect(flushWork(400)).toEqual(['E1_300', 'E2_200']);
204
- expect(Date.now()).toEqual(4700);
205
- // Default timeout is 5000, so during F2_200, work will timeout and are done
206
- // in reverse, including F2_200
207
- expect(flushWork(1000)).toEqual([
208
- 'F1_200',
209
- 'F2_200',
210
- 'F3_300',
211
- 'F4_500',
212
- 'F5_200',
213
- 'F6_20',
214
- ]);
215
- expect(Date.now()).toEqual(6120);
42
+ scheduleCallback(() => Scheduler.yieldValue('A'));
43
+ scheduleCallback(() => Scheduler.yieldValue('B'));
44
+ scheduleCallback(() => Scheduler.yieldValue('C'));
45
+ scheduleCallback(() => Scheduler.yieldValue('D'));
46
+
47
+ expect(Scheduler).toFlushAndYieldThrough(['A', 'B']);
48
+ expect(Scheduler).toFlushAndYieldThrough(['C']);
49
+ expect(Scheduler).toFlushAndYield(['D']);
50
});
51
52
it('cancels work', () => {
219
- scheduleCallback(() => doWork('A', 100));
220
- const callbackHandleB = scheduleCallback(() => doWork('B', 200));
221
- scheduleCallback(() => doWork('C', 300));
53
+ scheduleCallback(() => Scheduler.yieldValue('A'));
54
+ const callbackHandleB = scheduleCallback(() => Scheduler.yieldValue('B'));
55
+ scheduleCallback(() => Scheduler.yieldValue('C'));
56
57
cancelCallback(callbackHandleB);
58
225
- expect(flushWork()).toEqual([
59
+ expect(Scheduler).toFlushAndYield([
60
'A',
61
// B should have been cancelled
62
'C',
64
});
65
66
it('executes the highest priority callbacks first', () => {
233
- scheduleCallback(() => doWork('A', 100));
234
- scheduleCallback(() => doWork('B', 100));
67
+ scheduleCallback(() => Scheduler.yieldValue('A'));
68
+ scheduleCallback(() => Scheduler.yieldValue('B'));
69
70
// Yield before B is flushed
237
- expect(flushWork(100)).toEqual(['A']);
71
+ expect(Scheduler).toFlushAndYieldThrough(['A']);
72
73
runWithPriority(UserBlockingPriority, () => {
240
- scheduleCallback(() => doWork('C', 100));
241
- scheduleCallback(() => doWork('D', 100));
74
+ scheduleCallback(() => Scheduler.yieldValue('C'));
75
+ scheduleCallback(() => Scheduler.yieldValue('D'));
76
});
77
78
// C and D should come first, because they are higher priority
245
- expect(flushWork()).toEqual(['C', 'D', 'B']);
79
+ expect(Scheduler).toFlushAndYield(['C', 'D', 'B']);
80
});
81
82
it('expires work', () => {
249
- scheduleCallback(didTimeout =>
250
- doWork(`A (did timeout: ${didTimeout})`, 100),
251
- );
83
+ scheduleCallback(didTimeout => {
84
+ Scheduler.advanceTime(100);
85
+ Scheduler.yieldValue(`A (did timeout: ${didTimeout})`);
86
+ });
87
runWithPriority(UserBlockingPriority, () => {
253
- scheduleCallback(didTimeout =>
254
- doWork(`B (did timeout: ${didTimeout})`, 100),
255
- );
88
+ scheduleCallback(didTimeout => {
89
+ Scheduler.advanceTime(100);
90
+ Scheduler.yieldValue(`B (did timeout: ${didTimeout})`);
91
+ });
92
});
93
runWithPriority(UserBlockingPriority, () => {
258
- scheduleCallback(didTimeout =>
259
- doWork(`C (did timeout: ${didTimeout})`, 100),
260
- );
94
+ scheduleCallback(didTimeout => {
95
+ Scheduler.advanceTime(100);
96
+ Scheduler.yieldValue(`C (did timeout: ${didTimeout})`);
97
+ });
98
});
99
100
// Advance time, but not by enough to expire any work
264
- advanceTime(249);
265
- expect(clearYieldedValues()).toEqual([]);
101
+ Scheduler.advanceTime(249);
102
+ expect(Scheduler).toHaveYielded([]);
103
104
// Schedule a few more callbacks
268
- scheduleCallback(didTimeout =>
269
- doWork(`D (did timeout: ${didTimeout})`, 100),
270
- );
271
- scheduleCallback(didTimeout =>
272
- doWork(`E (did timeout: ${didTimeout})`, 100),
273
- );
105
+ scheduleCallback(didTimeout => {
106
+ Scheduler.advanceTime(100);
107
+ Scheduler.yieldValue(`D (did timeout: ${didTimeout})`);
108
+ });
109
+ scheduleCallback(didTimeout => {
110
+ Scheduler.advanceTime(100);
111
+ Scheduler.yieldValue(`E (did timeout: ${didTimeout})`);
112
+ });
113
114
// Advance by just a bit more to expire the user blocking callbacks
276
- advanceTime(1);
277
- expect(clearYieldedValues()).toEqual([
115
+ Scheduler.advanceTime(1);
116
+ expect(Scheduler).toHaveYielded([
117
'B (did timeout: true)',
118
'C (did timeout: true)',
119
]);
120
121
// Expire A
283
- advanceTime(4600);
284
- expect(clearYieldedValues()).toEqual(['A (did timeout: true)']);
122
+ Scheduler.advanceTime(4600);
123
+ expect(Scheduler).toHaveYielded(['A (did timeout: true)']);
124
125
// Flush the rest without expiring
287
- expect(flushWork()).toEqual([
126
+ expect(Scheduler).toFlushAndYield([
127
'D (did timeout: false)',
289
- 'E (did timeout: false)',
128
+ 'E (did timeout: true)',
129
]);
130
});
131
132
it('has a default expiration of ~5 seconds', () => {
294
- scheduleCallback(() => doWork('A', 100));
133
+ scheduleCallback(() => Scheduler.yieldValue('A'));
134
296
- advanceTime(4999);
297
- expect(clearYieldedValues()).toEqual([]);
135
+ Scheduler.advanceTime(4999);
136
+ expect(Scheduler).toHaveYielded([]);
137
299
- advanceTime(1);
300
- expect(clearYieldedValues()).toEqual(['A']);
138
+ Scheduler.advanceTime(1);
139
+ expect(Scheduler).toHaveYielded(['A']);
140
});
141
142
it('continues working on same task after yielding', () => {
304
- scheduleCallback(() => doWork('A', 100));
305
- scheduleCallback(() => doWork('B', 100));
143
+ scheduleCallback(() => {
144
+ Scheduler.advanceTime(100);
145
+ Scheduler.yieldValue('A');
146
+ });
147
+ scheduleCallback(() => {
148
+ Scheduler.advanceTime(100);
149
+ Scheduler.yieldValue('B');
150
+ });
151
152
+ let didYield = false;
153
const tasks = [['C1', 100], ['C2', 100], ['C3', 100]];
154
const C = () => {
155
while (tasks.length > 0) {
310
- doWork(...tasks.shift());
156
+ const [label, ms] = tasks.shift();
157
+ Scheduler.advanceTime(ms);
158
+ Scheduler.yieldValue(label);
159
if (shouldYield()) {
312
- yieldValue('Yield!');
160
+ didYield = true;
161
return C;
162
}
163
}
165
166
scheduleCallback(C);
167
320
- scheduleCallback(() => doWork('D', 100));
321
- scheduleCallback(() => doWork('E', 100));
168
+ scheduleCallback(() => {
169
+ Scheduler.advanceTime(100);
170
+ Scheduler.yieldValue('D');
171
+ });
172
+ scheduleCallback(() => {
173
+ Scheduler.advanceTime(100);
174
+ Scheduler.yieldValue('E');
175
+ });
176
323
- expect(flushWork(300)).toEqual(['A', 'B', 'C1', 'Yield!']);
177
+ // Flush, then yield while in the middle of C.
178
+ expect(didYield).toBe(false);
179
+ expect(Scheduler).toFlushAndYieldThrough(['A', 'B', 'C1']);
180
+ expect(didYield).toBe(true);
181
325
- expect(flushWork()).toEqual(['C2', 'C3', 'D', 'E']);
182
+ // When we resume, we should continue working on C.
183
+ expect(Scheduler).toFlushAndYield(['C2', 'C3', 'D', 'E']);
184
});
185
186
it('continuation callbacks inherit the expiration of the previous callback', () => {
187
const tasks = [['A', 125], ['B', 124], ['C', 100], ['D', 100]];
188
const work = () => {
189
while (tasks.length > 0) {
332
- doWork(...tasks.shift());
190
+ const [label, ms] = tasks.shift();
191
+ Scheduler.advanceTime(ms);
192
+ Scheduler.yieldValue(label);
193
if (shouldYield()) {
334
- yieldValue('Yield!');
194
return work;
195
}
196
}
200
runWithPriority(UserBlockingPriority, () => scheduleCallback(work));
201
202
// Flush until just before the expiration time
344
- expect(flushWork(249)).toEqual(['A', 'B', 'Yield!']);
203
+ expect(Scheduler).toFlushAndYieldThrough(['A', 'B']);
204
205
// Advance time by just a bit more. This should expire all the remaining work.
347
- advanceTime(1);
348
- expect(clearYieldedValues()).toEqual(['C', 'D']);
206
+ Scheduler.advanceTime(1);
207
+ expect(Scheduler).toHaveYielded(['C', 'D']);
208
});
209
210
it('nested callbacks inherit the priority of the currently executing callback', () => {
211
runWithPriority(UserBlockingPriority, () => {
212
scheduleCallback(() => {
354
- doWork('Parent callback', 100);
213
+ Scheduler.advanceTime(100);
214
+ Scheduler.yieldValue('Parent callback');
215
scheduleCallback(() => {
356
- doWork('Nested callback', 100);
216
+ Scheduler.advanceTime(100);
217
+ Scheduler.yieldValue('Nested callback');
218
});
219
});
220
});
221
361
- expect(flushWork(100)).toEqual(['Parent callback']);
222
+ expect(Scheduler).toFlushAndYieldThrough(['Parent callback']);
223
224
// The nested callback has user-blocking priority, so it should
225
// expire quickly.
365
- advanceTime(250 + 100);
366
- expect(clearYieldedValues()).toEqual(['Nested callback']);
226
+ Scheduler.advanceTime(250 + 100);
227
+ expect(Scheduler).toHaveYielded(['Nested callback']);
228
});
229
230
it('continuations are interrupted by higher priority work', () => {
231
const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];
232
const work = () => {
233
while (tasks.length > 0) {
373
- doWork(...tasks.shift());
234
+ const [label, ms] = tasks.shift();
235
+ Scheduler.advanceTime(ms);
236
+ Scheduler.yieldValue(label);
237
if (tasks.length > 0 && shouldYield()) {
375
- yieldValue('Yield!');
238
return work;
239
}
240
}
241
};
242
scheduleCallback(work);
381
- expect(flushWork(100)).toEqual(['A', 'Yield!']);
243
+ expect(Scheduler).toFlushAndYieldThrough(['A']);
244
245
runWithPriority(UserBlockingPriority, () => {
384
- scheduleCallback(() => doWork('High pri', 100));
246
+ scheduleCallback(() => {
247
+ Scheduler.advanceTime(100);
248
+ Scheduler.yieldValue('High pri');
249
+ });
250
});
251
387
- expect(flushWork()).toEqual(['High pri', 'B', 'C', 'D']);
252
+ expect(Scheduler).toFlushAndYield(['High pri', 'B', 'C', 'D']);
253
});
254
255
it(
260
const work = () => {
261
while (tasks.length > 0) {
262
const task = tasks.shift();
398
- doWork(...task);
263
+ const [label, ms] = task;
264
+ Scheduler.advanceTime(ms);
265
+ Scheduler.yieldValue(label);
266
if (task[0] === 'B') {
267
// Schedule high pri work from inside another callback
401
- yieldValue('Schedule high pri');
268
+ Scheduler.yieldValue('Schedule high pri');
269
runWithPriority(UserBlockingPriority, () =>
403
- scheduleCallback(() => doWork('High pri', 100)),
270
+ scheduleCallback(() => {
271
+ Scheduler.advanceTime(100);
272
+ Scheduler.yieldValue('High pri');
273
+ }),
274
);
275
}
276
if (tasks.length > 0 && shouldYield()) {
407
- yieldValue('Yield!');
277
+ Scheduler.yieldValue('Yield!');
278
return work;
279
}
280
}
281
};
282
scheduleCallback(work);
413
- expect(flushWork()).toEqual([
283
+ expect(Scheduler).toFlushAndYield([
284
'A',
285
'B',
286
'Schedule high pri',
297
298
it('immediate callbacks fire at the end of outermost event', () => {
299
runWithPriority(ImmediatePriority, () => {
430
- scheduleCallback(() => yieldValue('A'));
431
- scheduleCallback(() => yieldValue('B'));
300
+ scheduleCallback(() => Scheduler.yieldValue('A'));
301
+ scheduleCallback(() => Scheduler.yieldValue('B'));
302
// Nested event
303
runWithPriority(ImmediatePriority, () => {
434
- scheduleCallback(() => yieldValue('C'));
304
+ scheduleCallback(() => Scheduler.yieldValue('C'));
305
// Nothing should have fired yet
436
- expect(clearYieldedValues()).toEqual([]);
306
+ expect(Scheduler).toHaveYielded([]);
307
});
308
// Nothing should have fired yet
439
- expect(clearYieldedValues()).toEqual([]);
309
+ expect(Scheduler).toHaveYielded([]);
310
});
311
// The callbacks were called at the end of the outer event
442
- expect(clearYieldedValues()).toEqual(['A', 'B', 'C']);
312
+ expect(Scheduler).toHaveYielded(['A', 'B', 'C']);
313
});
314
315
it('wrapped callbacks have same signature as original callback', () => {
320
it('wrapped callbacks inherit the current priority', () => {
321
const wrappedCallback = wrapCallback(() => {
322
scheduleCallback(() => {
453
- doWork('Normal', 100);
323
+ Scheduler.advanceTime(100);
324
+ Scheduler.yieldValue('Normal');
325
});
326
});
327
const wrappedInteractiveCallback = runWithPriority(
329
() =>
330
wrapCallback(() => {
331
scheduleCallback(() => {
461
- doWork('User-blocking', 100);
332
+ Scheduler.advanceTime(100);
333
+ Scheduler.yieldValue('User-blocking');
334
});
335
}),
336
);
340
// This should schedule an user-blocking callback
341
wrappedInteractiveCallback();
342
471
- advanceTime(249);
472
- expect(clearYieldedValues()).toEqual([]);
473
- advanceTime(1);
474
- expect(clearYieldedValues()).toEqual(['User-blocking']);
343
+ Scheduler.advanceTime(249);
344
+ expect(Scheduler).toHaveYielded([]);
345
+ Scheduler.advanceTime(1);
346
+ expect(Scheduler).toHaveYielded(['User-blocking']);
347
476
- advanceTime(10000);
477
- expect(clearYieldedValues()).toEqual(['Normal']);
348
+ Scheduler.advanceTime(10000);
349
+ expect(Scheduler).toHaveYielded(['Normal']);
350
});
351
352
it('wrapped callbacks inherit the current priority even when nested', () => {
353
const wrappedCallback = wrapCallback(() => {
354
scheduleCallback(() => {
483
- doWork('Normal', 100);
355
+ Scheduler.advanceTime(100);
356
+ Scheduler.yieldValue('Normal');
357
});
358
});
359
const wrappedInteractiveCallback = runWithPriority(
361
() =>
362
wrapCallback(() => {
363
scheduleCallback(() => {
491
- doWork('User-blocking', 100);
364
+ Scheduler.advanceTime(100);
365
+ Scheduler.yieldValue('User-blocking');
366
});
367
}),
368
);
374
wrappedInteractiveCallback();
375
});
376
503
- advanceTime(249);
504
- expect(clearYieldedValues()).toEqual([]);
505
- advanceTime(1);
506
- expect(clearYieldedValues()).toEqual(['User-blocking']);
377
+ Scheduler.advanceTime(249);
378
+ expect(Scheduler).toHaveYielded([]);
379
+ Scheduler.advanceTime(1);
380
+ expect(Scheduler).toHaveYielded(['User-blocking']);
381
508
- advanceTime(10000);
509
- expect(clearYieldedValues()).toEqual(['Normal']);
382
+ Scheduler.advanceTime(10000);
383
+ expect(Scheduler).toHaveYielded(['Normal']);
384
});
385
386
it('immediate callbacks fire at the end of callback', () => {
387
const immediateCallback = runWithPriority(ImmediatePriority, () =>
388
wrapCallback(() => {
515
- scheduleCallback(() => yieldValue('callback'));
389
+ scheduleCallback(() => Scheduler.yieldValue('callback'));
390
}),
391
);
392
immediateCallback();
393
394
// The callback was called at the end of the outer event
521
- expect(clearYieldedValues()).toEqual(['callback']);
395
+ expect(Scheduler).toHaveYielded(['callback']);
396
});
397
398
it("immediate callbacks fire even if there's an error", () => {
399
expect(() => {
400
runWithPriority(ImmediatePriority, () => {
401
scheduleCallback(() => {
528
- yieldValue('A');
402
+ Scheduler.yieldValue('A');
403
throw new Error('Oops A');
404
});
405
scheduleCallback(() => {
532
- yieldValue('B');
406
+ Scheduler.yieldValue('B');
407
});
408
scheduleCallback(() => {
535
- yieldValue('C');
409
+ Scheduler.yieldValue('C');
410
throw new Error('Oops C');
411
});
412
});
413
}).toThrow('Oops A');
414
541
- expect(clearYieldedValues()).toEqual(['A']);
415
+ expect(Scheduler).toHaveYielded(['A']);
416
417
// B and C flush in a subsequent event. That way, the second error is not
418
// swallowed.
545
- expect(() => flushWork(0)).toThrow('Oops C');
546
- expect(clearYieldedValues()).toEqual(['B', 'C']);
419
+ expect(() => Scheduler.unstable_flushExpired()).toThrow('Oops C');
420
+ expect(Scheduler).toHaveYielded(['B', 'C']);
421
});
422
423
it('exposes the current priority level', () => {
550
- yieldValue(getCurrentPriorityLevel());
424
+ Scheduler.yieldValue(getCurrentPriorityLevel());
425
runWithPriority(ImmediatePriority, () => {
552
- yieldValue(getCurrentPriorityLevel());
426
+ Scheduler.yieldValue(getCurrentPriorityLevel());
427
runWithPriority(NormalPriority, () => {
554
- yieldValue(getCurrentPriorityLevel());
428
+ Scheduler.yieldValue(getCurrentPriorityLevel());
429
runWithPriority(UserBlockingPriority, () => {
556
- yieldValue(getCurrentPriorityLevel());
430
+ Scheduler.yieldValue(getCurrentPriorityLevel());
431
});
432
});
559
- yieldValue(getCurrentPriorityLevel());
433
+ Scheduler.yieldValue(getCurrentPriorityLevel());
434
});
435
562
- expect(clearYieldedValues()).toEqual([
436
+ expect(Scheduler).toHaveYielded([
437
NormalPriority,
438
ImmediatePriority,
439
NormalPriority,