CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-scheduler

Cooperative scheduler for the browser environment that provides time-slicing capabilities for JavaScript applications.

Pending
Overview
Eval results
Files

testing-utilities.mddocs/

Testing Utilities

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.

Capabilities

Flush All

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"

Flush Expired

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"

Advance Time

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"

Reset

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
}

Flush Number of Yields

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"]

Additional Testing Utilities

Has Pending Work

/**
 * Check if there are pending scheduled tasks
 * @returns true if tasks are pending, false otherwise
 */
function unstable_hasPendingWork(): boolean;

Clear Log

/**
 * Clear and return the current yield log
 * @returns Array of values that were logged during task execution
 */
function unstable_clearLog(): Array<mixed>;

Log

/**
 * Log a value during task execution for testing purposes
 * @param value - Value to log for later retrieval
 */
function log(value: mixed): void;

Flush Until Next Paint

/**
 * Flush work until a paint is requested
 * @returns false when completed
 */
function unstable_flushUntilNextPaint(): false;

Flush All Without Asserting

/**
 * Flush all work without assertion checks
 * @returns true if work was flushed, false if no work was pending
 */
function unstable_flushAllWithoutAsserting(): boolean;

Set Disable Yield Value

/**
 * Control whether yield values are logged
 * @param newValue - true to disable logging, false to enable
 */
function unstable_setDisableYieldValue(newValue: boolean): void;

Testing Patterns

Basic Test Setup

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);
  });
});

Testing Time-Based Behavior

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);
});

Testing Yielding Behavior

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

docs

core-scheduling.md

index.md

priority-management.md

profiling.md

testing-utilities.md

timing-yielding.md

tile.json