@angular/build:unit-test (vitest): zoneless project fails to compile with "Top-level await is not available" when zone.js is a transitive dep

Ouverte
#33,324 3 commentaires 2 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
3/5
Temps estimé
1-2 jours
Accessibilité débutants
70/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
angular, typescript

Piste de recherche

Lisez @angular/build/src/builders/unit-test/runners/vitest/build-options.js, en vous concentrant sur getZoneTestingStrategy() et le module virtuel angular:test-bed-init. Reproduisez l’échec avec ng test dans un projet zoneless, puis vérifiez que la stratégie n’émet aucun code d’initialisation de zone et que le bundle de unit-test se compile sans l’erreur top-level-await.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

area: @angular/build gemini-triaged
Command

test

Is this a regression?
  • Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was

21.2.13

Description

Description

A zoneless Angular project (provideZonelessChangeDetection() in main.ts, no zone.js in the polyfills array) fails to compile its unit-test bundle with:
X [ERROR] Top-level await is not available in the configured target environment ("chrome145.0", "ios17.0", "safari17.0" + 2 overrides)

Root cause

In @angular/build/src/builders/unit-test/runners/vitest/build-options.js, getZoneTestingStrategy() decides what to emit into the virtual angular:test-bed-init module:

function getZoneTestingStrategy(buildOptions, projectSourceRoot) {
  if (buildOptions.polyfills?.includes('zone.js/testing')) return 'none';
  if (buildOptions.polyfills?.includes('zone.js'))         return 'static';
  try {
    projectRequire.resolve('zone.js');
    return 'dynamic';                       // ← falls through to here for zoneless projects
  } catch { return 'none'; }
}

For a zoneless app, polyfills correctly contains neither 'zone.js' nor 'zone.js/testing' — but zone.js is still resolvable on disk because it's an optional/peer dep of @angular/core (and several Angular test utilities like fakeAsync / tick still reference it). The strategy therefore resolves to 'dynamic', which emits this into the virtual module:

if (typeof Zone !== 'undefined') {
  // 'zone.js/testing' is used to initialize the ZoneJS testing environment.
  // It must be imported dynamically to avoid a static dependency on 'zone.js'.
  await import('zone.js/testing');
}

The runtime guard typeof Zone !== 'undefined' would correctly skip the import on a zoneless app, but esbuild evaluates the top-level await at compile time and rejects the syntax — regardless of whether the branch can actually run. The build fails before the guard ever executes.

Expected

A zoneless project should resolve the strategy to 'none' and emit no zone-init code. The unit-test bundle should compile cleanly.

Actual

Strategy resolves to 'dynamic' because zone.js is transitively installed. The virtual angular:test-bed-init module contains a top-level await, which esbuild rejects against the configured browser targets — even though those targets (Chrome 145, iOS 17, Safari 17) actually do support TLA. The compile-time rejection appears to be tied to the output format guarantees rather than the targets themselves, so tightening browserslist does not help.

Minimal Reproduction
  1. Generate a zoneless Angular 22 app (or upgrade an existing zoneless app).
  2. Confirm main.ts uses provideZonelessChangeDetection() and polyfills in angular.json does not include 'zone.js' or 'zone.js/testing'.
  3. Configure test to use @angular/build:unit-test with the vitest runner.
  4. Run ng test.
Exception or Error
Top-level await is not available
Your Environment
_                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI       : 22.0.0
Angular           : 22.0.0
Node.js           : 24.16.0
Package Manager   : npm 11.13.0
Operating System  : win32 x64

┌────────────────────────────────────┬───────────────────┬───────────────────┐
│ Package                            │ Installed Version │ Requested Version │
├────────────────────────────────────┼───────────────────┼───────────────────┤
│ @angular-devkit/build-angular      │ 22.0.0            │ 22.0.0            │
│ @angular/animations                │ 22.0.0            │ 22.0.0            │
│ @angular/build                     │ 22.0.0            │ 22.0.0            │
│ @angular/cdk                       │ 21.2.13           │ 21.2.13           │
│ @angular/cli                       │ 22.0.0            │ 22.0.0            │
│ @angular/common                    │ 22.0.0            │ 22.0.0            │
│ @angular/compiler                  │ 22.0.0            │ 22.0.0            │
│ @angular/compiler-cli              │ 22.0.0            │ 22.0.0            │
│ @angular/core                      │ 22.0.0            │ 22.0.0            │
│ @angular/forms                     │ 22.0.0            │ 22.0.0            │
│ @angular/google-maps               │ 21.2.13           │ 21.2.13           │
│ @angular/language-service          │ 22.0.0            │ 22.0.0            │
│ @angular/material                  │ 21.2.13           │ 21.2.13           │
│ @angular/material-date-fns-adapter │ 21.2.13           │ 21.2.13           │
│ @angular/platform-browser          │ 22.0.0            │ 22.0.0            │
│ @angular/platform-browser-dynamic  │ 22.0.0            │ 22.0.0            │
│ @angular/platform-server           │ 22.0.0            │ 22.0.0            │
│ @angular/router                    │ 22.0.0            │ 22.0.0            │
│ @angular/service-worker            │ 22.0.0            │ 22.0.0            │
│ @angular/ssr                       │ 22.0.0            │ 22.0.0            │
│ rxjs                               │ 7.8.2             │ 7.8.2             │
│ typescript                         │ 6.0.3             │ 6.0.3             │
│ vitest                             │ 4.1.7             │ 4.1.7             │
Anything else relevant?

No response

Langage dominant
TypeScript
Étoiles
27k
Forks
11.8k
Merge moyen
16 h 35 min
PR mergées (30 j)
176

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de angular/angular-cli

Toutes les issues de angular/angular-cli

Issues similaires

Plus d'issues TypeScript

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.