0
0
AngularHow-ToBeginner · 4 min read

How to Use fakeAsync in Angular Test for Async Code

Use fakeAsync to wrap your Angular test function to simulate asynchronous passage of time synchronously. Inside it, use tick() to advance virtual time and trigger async operations like timers or promises immediately.
📐

Syntax

The fakeAsync function wraps a test function to run it in a special fake asynchronous zone. Inside this zone, asynchronous tasks like setTimeout or Promise are controlled synchronously.

The tick() function moves the virtual clock forward by a specified number of milliseconds, causing any pending timers or async tasks scheduled for that time to execute immediately.

typescript
import { fakeAsync, tick } from '@angular/core/testing';

describe('Test Suite', () => {
  it('should test async code synchronously', fakeAsync(() => {
    let done = false;
    setTimeout(() => {
      done = true;
    }, 1000);

    expect(done).toBe(false);
    tick(1000); // Move time forward by 1000ms
    expect(done).toBe(true);
  }));
});
💻

Example

This example shows how fakeAsync and tick() let you test code with setTimeout without waiting in real time. The test checks a flag before and after advancing time.

typescript
import { fakeAsync, tick } from '@angular/core/testing';

describe('fakeAsync Example', () => {
  it('should update value after timeout', fakeAsync(() => {
    let value = 0;
    setTimeout(() => {
      value = 42;
    }, 500);

    expect(value).toBe(0); // Before tick
    tick(500); // Advance time by 500ms
    expect(value).toBe(42); // After tick
  }));
});
Output
Test passes with value updated after tick
⚠️

Common Pitfalls

  • Not wrapping the test function with fakeAsync causes tick() to fail.
  • Forgetting to call tick() means async code inside setTimeout or Promise won’t run during the test.
  • Using fakeAsync with real asynchronous operations like HTTP requests won’t work; use async and whenStable() instead.
typescript
/* Wrong way: tick() used outside fakeAsync */
it('wrong test', () => {
  let done = false;
  setTimeout(() => done = true, 1000);
  tick(1000); // Error: tick() can only be called in fakeAsync zone
});

/* Right way: */
it('right test', fakeAsync(() => {
  let done = false;
  setTimeout(() => done = true, 1000);
  tick(1000);
  expect(done).toBe(true);
}));
📊

Quick Reference

FunctionPurpose
fakeAsync(() => {...})Wraps test to run async code synchronously
tick(milliseconds?)Advances virtual time by given ms, runs timers
flush()Runs all pending timers until none remain
discardPeriodicTasks()Clears any periodic timers like setInterval

Key Takeaways

Wrap your test function with fakeAsync to control async code synchronously.
Use tick() to simulate the passage of time and trigger timers immediately.
Do not use fakeAsync for real HTTP calls; prefer async and whenStable instead.
Always call tick() after scheduling async tasks to test their effects.
Remember to discard periodic timers to avoid test leaks.