@angular/build:unit-test (vitest): zoneless project fails to compile with "Top-level await is not available" when zone.js is a transitive dep
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Anfängerfreundlichkeit
- 70/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- angular, typescript
- Bereich
- build-system, testing, tooling
Rechercherichtung
Lies @angular/build/src/builders/unit-test/runners/vitest/build-options.js und konzentriere dich auf getZoneTestingStrategy() und das virtuelle Modul angular:test-bed-init. Reproduziere den Fehler mit ng test in einem zoneless-Projekt und überprüfe anschließend, dass die Strategie keinen zone-init-Code ausgibt und das Unit-Test-Bundle ohne den top-level-await-Fehler kompiliert.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
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
- Vorherrschende Sprache
- TypeScript
- Sterne
- 27k
- Forks
- 11.8k
- Ø Merge
- 16 Std. 35 Min.
- Gemergte PRs (30 T.)
- 176
Beitragsleitfaden
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus angular/angular-cli
-
area: @angular/build gemini-triaged
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 74/100
angular/angular-cli#33955 ·
-
area: @angular/cli gemini-triaged
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
angular/angular-cli#33055 · 1 Kommentar · 3 Reaktionen ·
-
unit-test: with --coverage, a setup file's hooks reach only the first spec file of each worker Offenarea: @angular/build gemini-triaged
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 72/100
angular/angular-cli#34137 ·
-
angular/build:library area: @angular/build gemini-triaged
angular/angular-cli#34131 · 1 zugewiesene Person ·
-
angular/build:library area: @angular/build gemini-triaged
angular/angular-cli#34130 · 1 zugewiesene Person ·
Alle Issues in angular/angular-cli
Ähnliche Issues
-
Browser Waiting for: Product Owner
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
getsentry/sentry-javascript#24577 · 1 Kommentar ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
agilepathway/label-checker#640 ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
copse-dev/agent-pane#2953 ·
-
[aw] Upgrade available Offenagentic-workflows
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 85/100
githubnext/rig#534 ·
-
automation missing-model model-sync provider:pioneer
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
anomalyco/models.dev#7701 ·