Cooperative scheduler for the browser environment that provides time-slicing capabilities for JavaScript applications.
—
Mock scheduler functions specifically designed for testing environments, providing deterministic time control and task execution for reliable unit tests.
These utilities are available from the scheduler/unstable_mock entry point and provide a controllable scheduler implementation.
Flushes all scheduled work immediately, completing all pending tasks.
/**
* Flush all scheduled work immediately
* Throws error if any tasks yield values during execution
*/
function unstable_flushAll(): void;Usage Examples:
import {
unstable_scheduleCallback,
unstable_NormalPriority
} from "scheduler/unstable_mock";
import { unstable_flushAll } from "scheduler/unstable_mock";
// Schedule multiple tasks
unstable_scheduleCallback(unstable_NormalPriority, () => {
console.log("Task 1");
});
unstable_scheduleCallback(unstable_NormalPriority, () => {
console.log("Task 2");
});
// Execute all tasks immediately
unstable_flushAll();
// Output: "Task 1", "Task 2"Executes only tasks that have exceeded their timeout, leaving non-expired tasks in the queue.
/**
* Flush only expired tasks based on current mock time
*/
function unstable_flushExpired(): void;Usage Examples:
import {
unstable_scheduleCallback,
unstable_UserBlockingPriority,
unstable_LowPriority,
unstable_advanceTime,
unstable_flushExpired,
reset
} from "scheduler/unstable_mock";
reset(); // Start with clean state
// Schedule tasks with different priorities
unstable_scheduleCallback(unstable_UserBlockingPriority, () => {
console.log("High priority task");
});
unstable_scheduleCallback(unstable_LowPriority, () => {
console.log("Low priority task");
});
// Advance time past UserBlocking timeout (250ms) but not Low timeout (10000ms)
unstable_advanceTime(300);
// Only the expired high-priority task will execute
unstable_flushExpired();
// Output: "High priority task"
// Low priority task is still pending
unstable_flushAll();
// Output: "Low priority task"Advances the mock time and triggers any timers that should fire.
/**
* Advance mock time by specified milliseconds
* @param ms - Milliseconds to advance the mock time
*/
function unstable_advanceTime(ms: number): void;Usage Examples:
import {
unstable_scheduleCallback,
unstable_NormalPriority,
unstable_advanceTime,
unstable_flushExpired,
unstable_now,
reset
} from "scheduler/unstable_mock";
reset();
console.log("Start time:", unstable_now()); // 0
// Schedule delayed task
unstable_scheduleCallback(
unstable_NormalPriority,
() => console.log("Delayed task executed"),
{ delay: 1000 }
);
// Advance time but not enough to trigger task
unstable_advanceTime(500);
console.log("Time after 500ms:", unstable_now()); // 500
unstable_flushExpired(); // No output - task not ready
// Advance time to trigger the delayed task
unstable_advanceTime(500);
console.log("Time after 1000ms:", unstable_now()); // 1000
unstable_flushExpired();
// Output: "Delayed task executed"Resets the mock scheduler to its initial state, clearing all tasks and resetting time.
/**
* Reset scheduler to initial state
* Clears all scheduled tasks and resets mock time to 0
*/
function reset(): void;Usage Examples:
import {
unstable_scheduleCallback,
unstable_NormalPriority,
unstable_advanceTime,
unstable_now,
unstable_hasPendingWork,
reset
} from "scheduler/unstable_mock";
// Schedule some work and advance time
unstable_scheduleCallback(unstable_NormalPriority, () => {
console.log("This task will be cleared");
});
unstable_advanceTime(5000);
console.log("Time before reset:", unstable_now()); // 5000
console.log("Has pending work:", unstable_hasPendingWork()); // true
// Reset everything
reset();
console.log("Time after reset:", unstable_now()); // 0
console.log("Has pending work:", unstable_hasPendingWork()); // false
// Test isolation
function testCase1() {
reset(); // Ensure clean state
// Test implementation
}
function testCase2() {
reset(); // Ensure clean state
// Test implementation
}Flushes work until a specific number of yields have occurred, useful for testing time-sliced operations.
/**
* Flush work until specified number of yields
* @param count - Number of yields to allow before stopping
*/
function unstable_flushNumberOfYields(count: number): void;Usage Examples:
import {
unstable_scheduleCallback,
unstable_NormalPriority,
unstable_flushNumberOfYields,
log,
unstable_clearLog,
reset
} from "scheduler/unstable_mock";
reset();
// Schedule work that yields values
unstable_scheduleCallback(unstable_NormalPriority, () => {
log("Step 1");
return () => {
log("Step 2");
return () => {
log("Step 3");
};
};
});
// Flush only first yield
unstable_flushNumberOfYields(1);
console.log(unstable_clearLog()); // ["Step 1"]
// Flush next yield
unstable_flushNumberOfYields(1);
console.log(unstable_clearLog()); // ["Step 2"]
// Flush final yield
unstable_flushNumberOfYields(1);
console.log(unstable_clearLog()); // ["Step 3"]/**
* Check if there are pending scheduled tasks
* @returns true if tasks are pending, false otherwise
*/
function unstable_hasPendingWork(): boolean;/**
* Clear and return the current yield log
* @returns Array of values that were logged during task execution
*/
function unstable_clearLog(): Array<mixed>;/**
* Log a value during task execution for testing purposes
* @param value - Value to log for later retrieval
*/
function log(value: mixed): void;/**
* Flush work until a paint is requested
* @returns false when completed
*/
function unstable_flushUntilNextPaint(): false;/**
* Flush all work without assertion checks
* @returns true if work was flushed, false if no work was pending
*/
function unstable_flushAllWithoutAsserting(): boolean;/**
* Control whether yield values are logged
* @param newValue - true to disable logging, false to enable
*/
function unstable_setDisableYieldValue(newValue: boolean): void;import {
unstable_scheduleCallback,
unstable_NormalPriority,
unstable_flushAll,
reset
} from "scheduler/unstable_mock";
describe("Scheduler tests", () => {
beforeEach(() => {
reset(); // Clean slate for each test
});
test("basic task execution", () => {
let executed = false;
unstable_scheduleCallback(unstable_NormalPriority, () => {
executed = true;
});
expect(executed).toBe(false);
unstable_flushAll();
expect(executed).toBe(true);
});
});import {
unstable_scheduleCallback,
unstable_UserBlockingPriority,
unstable_advanceTime,
unstable_flushExpired,
unstable_now,
reset
} from "scheduler/unstable_mock";
test("priority timeout behavior", () => {
reset();
let didTimeout = null;
unstable_scheduleCallback(unstable_UserBlockingPriority, (timeout) => {
didTimeout = timeout;
});
// Don't advance time - task shouldn't timeout
unstable_flushExpired();
expect(didTimeout).toBe(false);
reset();
unstable_scheduleCallback(unstable_UserBlockingPriority, (timeout) => {
didTimeout = timeout;
});
// Advance past UserBlocking timeout (250ms)
unstable_advanceTime(300);
unstable_flushExpired();
expect(didTimeout).toBe(true);
});import {
unstable_scheduleCallback,
unstable_NormalPriority,
unstable_flushNumberOfYields,
log,
unstable_clearLog,
reset
} from "scheduler/unstable_mock";
test("task yielding", () => {
reset();
unstable_scheduleCallback(unstable_NormalPriority, () => {
log("A");
return () => {
log("B");
return () => {
log("C");
};
};
});
// Execute one yield at a time
unstable_flushNumberOfYields(1);
expect(unstable_clearLog()).toEqual(["A"]);
unstable_flushNumberOfYields(1);
expect(unstable_clearLog()).toEqual(["B"]);
unstable_flushNumberOfYields(1);
expect(unstable_clearLog()).toEqual(["C"]);
});Install with Tessl CLI
npx tessl i tessl/npm-scheduler