or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

browser-mocking.mdhttp-backend.mdindex.mdtesting-utilities.mdtime-control.md
tile.json

time-control.mddocs/

Time Control

Mock implementations of time-based services that provide synchronous control over asynchronous operations in tests. Angular Mocks decorates the $timeout and $interval services and provides a mock $browser.defer method for controlling timing in tests.

Capabilities

Timeout Service

Mock $timeout service that provides synchronous control over timeout operations:

/**
 * Schedule a function to be executed after a delay (works like native $timeout)
 * @param {Function} fn - Function to execute
 * @param {number} delay - Delay in milliseconds (optional, defaults to 0)
 * @param {boolean} invokeApply - Whether to invoke $apply (optional, defaults to true)
 * @param {...*} pass - Additional arguments to pass to the function
 * @returns {Promise} Promise that resolves when the timeout executes
 */
$timeout(fn?, delay?, invokeApply?, ...pass);

/**
 * Cancel a scheduled timeout
 * @param {Promise} promise - Promise returned by $timeout()
 * @returns {boolean} True if the timeout was successfully cancelled
 */
$timeout.cancel(promise);

/**
 * Flush pending timeouts
 * @param {number} delay - Specific delay to flush (optional, flushes all if not specified)
 * @throws {Error} If there are no pending timeouts to flush
 */
$timeout.flush(delay?);

/**
 * Flush the next pending timeout
 * @param {number} expectedDelay - Expected delay of the next timeout (optional)
 * @throws {Error} If there are no pending timeouts or delay doesn't match
 */
$timeout.flushNext(expectedDelay?);

/**
 * Verify that no timeouts are pending
 * @throws {Error} If there are pending timeouts
 */
$timeout.verifyNoPendingTasks();

Interval Service

Mock $interval service that provides synchronous control over interval operations:

/**
 * Create a repeating interval
 * @param {Function} fn - Function to execute repeatedly
 * @param {number} delay - Delay between executions in milliseconds
 * @param {number} count - Number of times to execute (optional, infinite if not specified)
 * @param {boolean} invokeApply - Whether to invoke $apply (optional, defaults to true)
 * @param {...*} pass - Additional arguments to pass to the function
 * @returns {Promise} Promise that resolves when the interval completes
 */
$interval(fn, delay, count?, invokeApply?, ...pass);

/**
 * Cancel an active interval
 * @param {Promise} promise - Promise returned by $interval()
 * @returns {boolean} True if the interval was successfully cancelled
 */
$interval.cancel(promise);

/**
 * Flush pending intervals
 * @param {number} millis - Number of milliseconds to advance time (optional, flushes all if not specified)
 * @returns {number} Number of interval callbacks that were executed
 */
$interval.flush(millis?);

Browser Defer

Mock browser defer method for controlling deferred execution:

/**
 * Schedule a function for deferred execution
 * @param {Function} fn - Function to execute
 * @param {number} delay - Delay in milliseconds (optional, defaults to 0)
 * @param {string} taskType - Type of task for tracking (optional)
 * @returns {number} Timeout ID for cancellation
 */
$browser.defer(fn, delay?, taskType?);

/**
 * Current mock time in milliseconds
 * @type {number}
 */
$browser.defer.now;

/**
 * Flush pending deferred functions
 * @param {number} delay - Specific delay to flush (optional, flushes all if not specified)
 */
$browser.defer.flush(delay?);

Task Management

Services for managing and verifying asynchronous tasks:

/**
 * Flush all pending tasks (timeouts, intervals, deferrals)
 */
$flushPendingTasks();

/**
 * Verify that no tasks are pending
 * @throws {Error} If there are pending tasks
 */
$verifyNoPendingTasks();

/**
 * Register callback to be notified when no requests are outstanding
 * @param {Function} callback - Function to call when no requests are pending
 */
$browser.notifyWhenNoOutstandingRequests(callback);

Usage Examples

Basic Timeout Testing:

describe('TimeoutService', function() {
  var TimeoutService, $timeout;
  
  beforeEach(module('myApp'));
  beforeEach(inject(function(_TimeoutService_, _$timeout_) {
    TimeoutService = _TimeoutService_;
    $timeout = _$timeout_;
  }));
  
  it('should execute delayed function', function() {
    var called = false;
    
    TimeoutService.delayedAction(function() {
      called = true;
    }, 1000);
    
    expect(called).toBe(false);
    
    $timeout.flush(1000);
    
    expect(called).toBe(true);
  });
  
  it('should handle timeout cancellation', function() {
    var called = false;
    
    var promise = $timeout(function() {
      called = true;
    }, 1000);
    
    $timeout.cancel(promise);
    $timeout.flush();
    
    expect(called).toBe(false);
  });
});

Interval Testing:

describe('IntervalService', function() {
  var $interval;
  
  beforeEach(inject(function(_$interval_) {
    $interval = _$interval_;
  }));
  
  it('should execute interval multiple times', function() {
    var count = 0;
    
    $interval(function() {
      count++;
    }, 100, 3);
    
    expect(count).toBe(0);
    
    $interval.flush(100);
    expect(count).toBe(1);
    
    $interval.flush(200);
    expect(count).toBe(3);
  });
  
  it('should handle interval cancellation', function() {
    var count = 0;
    
    var promise = $interval(function() {
      count++;
    }, 100);
    
    $interval.flush(200);
    expect(count).toBe(2);
    
    $interval.cancel(promise);
    $interval.flush(100);
    expect(count).toBe(2); // Should not increment after cancellation
  });
});

Complex Timing Scenarios:

it('should handle mixed timeout and interval operations', function() {
  var timeoutCalled = false;
  var intervalCount = 0;
  
  // Set up timeout
  $timeout(function() {
    timeoutCalled = true;
  }, 500);
  
  // Set up interval
  $interval(function() {
    intervalCount++;
  }, 200, 3);
  
  // Flush intervals first
  $interval.flush(400); // Should execute interval twice
  expect(intervalCount).toBe(2);
  expect(timeoutCalled).toBe(false);
  
  // Flush timeout
  $timeout.flush(500);
  expect(timeoutCalled).toBe(true);
  
  // Complete remaining interval
  $interval.flush(200);
  expect(intervalCount).toBe(3);
  
  // Verify nothing is pending
  $timeout.verifyNoPendingTasks();
});

Task Verification:

describe('Task Management', function() {
  var $flushPendingTasks, $verifyNoPendingTasks;
  
  beforeEach(inject(function(_$flushPendingTasks_, _$verifyNoPendingTasks_) {
    $flushPendingTasks = _$flushPendingTasks_;
    $verifyNoPendingTasks = _$verifyNoPendingTasks_;
  }));
  
  it('should flush all pending tasks', function() {
    var results = [];
    
    $timeout(function() { results.push('timeout1'); }, 100);
    $timeout(function() { results.push('timeout2'); }, 200);
    $interval(function() { results.push('interval'); }, 50, 2);
    
    $flushPendingTasks();
    
    expect(results).toContain('timeout1');
    expect(results).toContain('timeout2');
    expect(results).toContain('interval');
    
    $verifyNoPendingTasks(); // Should not throw
  });
});

Types

// Timeout Promise Interface
interface TimeoutPromise extends Promise {
  $$timeoutId: number;
}

// Interval Promise Interface  
interface IntervalPromise extends Promise {
  $$intervalId: number;
}

// Task Types
type TaskType = 'timeout' | 'interval' | 'defer' | string;