angular/components · critical

Could not find ZoneJS. For test harnesses running in TestBed

Error message

Could not find ZoneJS. For test harnesses running in TestBed, ZoneJS needs to be installed.

What it means

Thrown by TaskStateZoneInterceptor.setup when the global Zone is undefined. TestBed-based harnesses rely on ZoneJS (specifically ProxyZone) to track async tasks and know when the app is stable; without ZoneJS installed the harness cannot monitor task state, so setup aborts.

Source

Thrown at src/cdk/testing/testbed/task-state-zone-interceptor.ts:73

  private _getTaskStateFromInternalZoneState(state: HasTaskState): TaskState {
    return {stable: !state.macroTask && !state.microTask};
  }

  static isInProxyZone(): boolean {
    if (typeof Zone === 'undefined') {
      return false;
    }
    return ((Zone as any)['ProxyZoneSpec'] as ProxyZoneStatic | undefined)?.get() !== undefined;
  }

  /**
   * Sets up the custom task state Zone interceptor in the  `ProxyZone`. Throws if
   * no `ProxyZone` could be found.
   * @returns an observable that emits whenever the task state changes.
   */
  static setup(): Observable<TaskState> {
    if (Zone === undefined) {
      throw Error(
        'Could not find ZoneJS. For test harnesses running in TestBed, ' +
          'ZoneJS needs to be installed.',
      );
    }

    // tslint:disable-next-line:variable-name
    const ProxyZoneSpec = (Zone as any)['ProxyZoneSpec'] as ProxyZoneStatic | undefined;

    // If there is no "ProxyZoneSpec" installed, we throw an error and recommend
    // setting up the proxy zone by pulling in the testing bundle.
    if (!ProxyZoneSpec) {
      throw Error(
        'ProxyZoneSpec is needed for the test harnesses but could not be found. ' +
          'Please make sure that your environment includes zone.js/dist/zone-testing.js',
      );
    }

    // Ensure that there is a proxy zone instance set up, and get

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Add zone.js to test polyfills (polyfills.ts or angular.json test architect polyfills list) — 'zone.js' in polyfills array or `import 'zone.js'` in test setup.
  2. Keep TestBed tests in NgZone/ProxyZone; only go zoneless for tests that do not use harnesses.
  3. If truly zoneless, use a different testing approach (e.g. raw TestElement queries) instead of component harnesses that rely on task-state interception.

Example fix

// before (test polyfills)
import 'zone.js/testing'; // zone.js never loaded
// after
import 'zone.js';
import 'zone.js/testing';
Defensive patterns

Strategy: validation

Validate before calling

if (typeof Zone === 'undefined') {
  throw new Error('Add zone.js to test polyfills before using TestBed harnesses');
}

Type guard

const zoneAvailable = (): boolean => typeof (globalThis as any).Zone !== 'undefined';

Try / catch

try { return await harness.loader().getAllHarnesses(MyHarness); } catch (e) { if ((e as Error).message.includes('Could not find ZoneJS')) throw new Error('zone.js missing from test setup', {cause: e}); throw e; }

Prevention

When it happens

Trigger: Running TestBed-based component harness tests in a zoneless setup: zone.js missing from test.ts/polyfills.ts, Angular configured with provideExperimentalZonelessChangeDetection(), or the zone.js import removed from test polyfills.

Common situations: Migrating an app to zoneless Angular while keeping harness-based tests; new test bundler configs (Vite/Jest) that don't include zone.js in the setup files; upgrading Angular where zone.js polyfill registration changed.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/dcecf8dcf3e28b51. Report an issue: GitHub.