From 9535a75ea7df6b23d208aba295091f06ff8f8710 Mon Sep 17 00:00:00 2001 From: "olivier.T" Date: Sun, 7 Jun 2026 10:50:37 +0200 Subject: [PATCH] fix(@angular/build): prevent unit-test vitest runner from hanging after tests complete In non-watch mode, the vitest executor disposed the Vitest instance with `close()`, which can wait indefinitely when a worker or service keeps the event loop alive. The process then never exits even though all tests have completed and their results were reported. Use `exit()` instead when not in watch mode, mirroring the `vitest run` CLI behavior: `exit()` arms an unref'd `teardownTimeout` safety net that force-exits the process if teardown does not settle in time, while still performing a normal `close()` when teardown succeeds. Watch mode behavior is unchanged. Fixes #32832 --- .../src/builders/unit-test/runners/vitest/executor.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts index 0a7a3c7ea63b..4065b4510f00 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts @@ -205,7 +205,16 @@ export class VitestExecutor implements TestExecutor { async [Symbol.asyncDispose](): Promise { this.debugLog(DebugLogLevel.Info, 'Disposing VitestExecutor: Closing Vitest instance.'); - await this.vitest?.close(); + if (this.vitest && !this.options.watch) { + // In run (non-watch) mode, mirror the `vitest run` CLI by using `exit()`, which arms an + // unref'd `teardownTimeout` safety net (`process.exit()`) before closing. `close()` alone + // can wait indefinitely when a worker or service keeps the event loop alive, leaving the + // process hanging after all tests have completed. + // See https://github.com/angular/angular-cli/issues/32832 + await this.vitest.exit(); + } else { + await this.vitest?.close(); + } this.debugLog(DebugLogLevel.Info, 'Vitest instance closed.'); }