0
# Testing Utilities
1
2
Mock scheduler functions specifically designed for testing environments, providing deterministic time control and task execution for reliable unit tests.
3
4
These utilities are available from the `scheduler/unstable_mock` entry point and provide a controllable scheduler implementation.
5
6
## Capabilities
7
8
### Flush All
9
10
Flushes all scheduled work immediately, completing all pending tasks.
11
12
```javascript { .api }
13
/**
14
* Flush all scheduled work immediately
15
* Throws error if any tasks yield values during execution
16
*/
17
function unstable_flushAll(): void;
18
```
19
20
**Usage Examples:**
21
22
```javascript
23
import {
24
unstable_scheduleCallback,
25
unstable_NormalPriority
26
} from "scheduler/unstable_mock";
27
import { unstable_flushAll } from "scheduler/unstable_mock";
28
29
// Schedule multiple tasks
30
unstable_scheduleCallback(unstable_NormalPriority, () => {
31
console.log("Task 1");
32
});
33
34
unstable_scheduleCallback(unstable_NormalPriority, () => {
35
console.log("Task 2");
36
});
37
38
// Execute all tasks immediately
39
unstable_flushAll();
40
// Output: "Task 1", "Task 2"
41
```
42
43
### Flush Expired
44
45
Executes only tasks that have exceeded their timeout, leaving non-expired tasks in the queue.
46
47
```javascript { .api }
48
/**
49
* Flush only expired tasks based on current mock time
50
*/
51
function unstable_flushExpired(): void;
52
```
53
54
**Usage Examples:**
55
56
```javascript
57
import {
58
unstable_scheduleCallback,
59
unstable_UserBlockingPriority,
60
unstable_LowPriority,
61
unstable_advanceTime,
62
unstable_flushExpired,
63
reset
64
} from "scheduler/unstable_mock";
65
66
reset(); // Start with clean state
67
68
// Schedule tasks with different priorities
69
unstable_scheduleCallback(unstable_UserBlockingPriority, () => {
70
console.log("High priority task");
71
});
72
73
unstable_scheduleCallback(unstable_LowPriority, () => {
74
console.log("Low priority task");
75
});
76
77
// Advance time past UserBlocking timeout (250ms) but not Low timeout (10000ms)
78
unstable_advanceTime(300);
79
80
// Only the expired high-priority task will execute
81
unstable_flushExpired();
82
// Output: "High priority task"
83
84
// Low priority task is still pending
85
unstable_flushAll();
86
// Output: "Low priority task"
87
```
88
89
### Advance Time
90
91
Advances the mock time and triggers any timers that should fire.
92
93
```javascript { .api }
94
/**
95
* Advance mock time by specified milliseconds
96
* @param ms - Milliseconds to advance the mock time
97
*/
98
function unstable_advanceTime(ms: number): void;
99
```
100
101
**Usage Examples:**
102
103
```javascript
104
import {
105
unstable_scheduleCallback,
106
unstable_NormalPriority,
107
unstable_advanceTime,
108
unstable_flushExpired,
109
unstable_now,
110
reset
111
} from "scheduler/unstable_mock";
112
113
reset();
114
115
console.log("Start time:", unstable_now()); // 0
116
117
// Schedule delayed task
118
unstable_scheduleCallback(
119
unstable_NormalPriority,
120
() => console.log("Delayed task executed"),
121
{ delay: 1000 }
122
);
123
124
// Advance time but not enough to trigger task
125
unstable_advanceTime(500);
126
console.log("Time after 500ms:", unstable_now()); // 500
127
unstable_flushExpired(); // No output - task not ready
128
129
// Advance time to trigger the delayed task
130
unstable_advanceTime(500);
131
console.log("Time after 1000ms:", unstable_now()); // 1000
132
unstable_flushExpired();
133
// Output: "Delayed task executed"
134
```
135
136
### Reset
137
138
Resets the mock scheduler to its initial state, clearing all tasks and resetting time.
139
140
```javascript { .api }
141
/**
142
* Reset scheduler to initial state
143
* Clears all scheduled tasks and resets mock time to 0
144
*/
145
function reset(): void;
146
```
147
148
**Usage Examples:**
149
150
```javascript
151
import {
152
unstable_scheduleCallback,
153
unstable_NormalPriority,
154
unstable_advanceTime,
155
unstable_now,
156
unstable_hasPendingWork,
157
reset
158
} from "scheduler/unstable_mock";
159
160
// Schedule some work and advance time
161
unstable_scheduleCallback(unstable_NormalPriority, () => {
162
console.log("This task will be cleared");
163
});
164
165
unstable_advanceTime(5000);
166
console.log("Time before reset:", unstable_now()); // 5000
167
console.log("Has pending work:", unstable_hasPendingWork()); // true
168
169
// Reset everything
170
reset();
171
172
console.log("Time after reset:", unstable_now()); // 0
173
console.log("Has pending work:", unstable_hasPendingWork()); // false
174
175
// Test isolation
176
function testCase1() {
177
reset(); // Ensure clean state
178
// Test implementation
179
}
180
181
function testCase2() {
182
reset(); // Ensure clean state
183
// Test implementation
184
}
185
```
186
187
### Flush Number of Yields
188
189
Flushes work until a specific number of yields have occurred, useful for testing time-sliced operations.
190
191
```javascript { .api }
192
/**
193
* Flush work until specified number of yields
194
* @param count - Number of yields to allow before stopping
195
*/
196
function unstable_flushNumberOfYields(count: number): void;
197
```
198
199
**Usage Examples:**
200
201
```javascript
202
import {
203
unstable_scheduleCallback,
204
unstable_NormalPriority,
205
unstable_flushNumberOfYields,
206
log,
207
unstable_clearLog,
208
reset
209
} from "scheduler/unstable_mock";
210
211
reset();
212
213
// Schedule work that yields values
214
unstable_scheduleCallback(unstable_NormalPriority, () => {
215
log("Step 1");
216
return () => {
217
log("Step 2");
218
return () => {
219
log("Step 3");
220
};
221
};
222
});
223
224
// Flush only first yield
225
unstable_flushNumberOfYields(1);
226
console.log(unstable_clearLog()); // ["Step 1"]
227
228
// Flush next yield
229
unstable_flushNumberOfYields(1);
230
console.log(unstable_clearLog()); // ["Step 2"]
231
232
// Flush final yield
233
unstable_flushNumberOfYields(1);
234
console.log(unstable_clearLog()); // ["Step 3"]
235
```
236
237
### Additional Testing Utilities
238
239
#### Has Pending Work
240
241
```javascript { .api }
242
/**
243
* Check if there are pending scheduled tasks
244
* @returns true if tasks are pending, false otherwise
245
*/
246
function unstable_hasPendingWork(): boolean;
247
```
248
249
#### Clear Log
250
251
```javascript { .api }
252
/**
253
* Clear and return the current yield log
254
* @returns Array of values that were logged during task execution
255
*/
256
function unstable_clearLog(): Array<mixed>;
257
```
258
259
#### Log
260
261
```javascript { .api }
262
/**
263
* Log a value during task execution for testing purposes
264
* @param value - Value to log for later retrieval
265
*/
266
function log(value: mixed): void;
267
```
268
269
#### Flush Until Next Paint
270
271
```javascript { .api }
272
/**
273
* Flush work until a paint is requested
274
* @returns false when completed
275
*/
276
function unstable_flushUntilNextPaint(): false;
277
```
278
279
#### Flush All Without Asserting
280
281
```javascript { .api }
282
/**
283
* Flush all work without assertion checks
284
* @returns true if work was flushed, false if no work was pending
285
*/
286
function unstable_flushAllWithoutAsserting(): boolean;
287
```
288
289
#### Set Disable Yield Value
290
291
```javascript { .api }
292
/**
293
* Control whether yield values are logged
294
* @param newValue - true to disable logging, false to enable
295
*/
296
function unstable_setDisableYieldValue(newValue: boolean): void;
297
```
298
299
## Testing Patterns
300
301
### Basic Test Setup
302
303
```javascript
304
import {
305
unstable_scheduleCallback,
306
unstable_NormalPriority,
307
unstable_flushAll,
308
reset
309
} from "scheduler/unstable_mock";
310
311
describe("Scheduler tests", () => {
312
beforeEach(() => {
313
reset(); // Clean slate for each test
314
});
315
316
test("basic task execution", () => {
317
let executed = false;
318
319
unstable_scheduleCallback(unstable_NormalPriority, () => {
320
executed = true;
321
});
322
323
expect(executed).toBe(false);
324
unstable_flushAll();
325
expect(executed).toBe(true);
326
});
327
});
328
```
329
330
### Testing Time-Based Behavior
331
332
```javascript
333
import {
334
unstable_scheduleCallback,
335
unstable_UserBlockingPriority,
336
unstable_advanceTime,
337
unstable_flushExpired,
338
unstable_now,
339
reset
340
} from "scheduler/unstable_mock";
341
342
test("priority timeout behavior", () => {
343
reset();
344
345
let didTimeout = null;
346
347
unstable_scheduleCallback(unstable_UserBlockingPriority, (timeout) => {
348
didTimeout = timeout;
349
});
350
351
// Don't advance time - task shouldn't timeout
352
unstable_flushExpired();
353
expect(didTimeout).toBe(false);
354
355
reset();
356
357
unstable_scheduleCallback(unstable_UserBlockingPriority, (timeout) => {
358
didTimeout = timeout;
359
});
360
361
// Advance past UserBlocking timeout (250ms)
362
unstable_advanceTime(300);
363
unstable_flushExpired();
364
expect(didTimeout).toBe(true);
365
});
366
```
367
368
### Testing Yielding Behavior
369
370
```javascript
371
import {
372
unstable_scheduleCallback,
373
unstable_NormalPriority,
374
unstable_flushNumberOfYields,
375
log,
376
unstable_clearLog,
377
reset
378
} from "scheduler/unstable_mock";
379
380
test("task yielding", () => {
381
reset();
382
383
unstable_scheduleCallback(unstable_NormalPriority, () => {
384
log("A");
385
return () => {
386
log("B");
387
return () => {
388
log("C");
389
};
390
};
391
});
392
393
// Execute one yield at a time
394
unstable_flushNumberOfYields(1);
395
expect(unstable_clearLog()).toEqual(["A"]);
396
397
unstable_flushNumberOfYields(1);
398
expect(unstable_clearLog()).toEqual(["B"]);
399
400
unstable_flushNumberOfYields(1);
401
expect(unstable_clearLog()).toEqual(["C"]);
402
});
403
```