@angular/build:unit-test (vitest): zoneless project fails to compile with "Top-level await is not available" when zone.js is a transitive dep
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
- Domaine
- build-system, testing, tooling
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
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
- Generate a zoneless Angular 22 app (or upgrade an existing zoneless app).
- Confirm main.ts uses provideZonelessChangeDetection() and polyfills in angular.json does not include 'zone.js' or 'zone.js/testing'.
- Configure test to use @angular/build:unit-test with the vitest runner.
- 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
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de angular/angular-cli
-
Can't use an array of hostnames in --allowedHosts cli parameter in @angular/build:dev-server Ouvertearea: @angular/build gemini-triaged
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
angular/angular-cli#33955 ·
-
area: @angular/cli gemini-triaged
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
angular/angular-cli#33055 · 1 commentaire · 3 réactions ·
-
unit-test: with --coverage, a setup file's hooks reach only the first spec file of each worker Ouvertearea: @angular/build gemini-triaged
Difficulté 4/5 3-5 jours Accessibilité débutants 72/100
angular/angular-cli#34137 ·
-
angular/build:library area: @angular/build gemini-triaged
angular/angular-cli#34131 · 1 personne assignée ·
-
angular/build:library area: @angular/build gemini-triaged
angular/angular-cli#34130 · 1 personne assignée ·
Toutes les issues de angular/angular-cli
Issues similaires
-
Browser Waiting for: Product Owner
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
getsentry/sentry-javascript#24577 · 1 commentaire ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
agilepathway/label-checker#640 ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
copse-dev/agent-pane#2953 ·
-
[aw] Upgrade available Ouverteagentic-workflows
Difficulté 1/5 Moins d'une heure Accessibilité débutants 85/100
githubnext/rig#534 ·
-
automation missing-model model-sync provider:pioneer
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
anomalyco/models.dev#7701 ·