Command
test
Is this a regression?
The previous version in which this bug was not present was
No response
Description
On Windows, the drive-letter casing of process.cwd() is whatever the user typed:
cmd.exe preserves it literally, so cd c:\projects\my-app yields a cwd of
c:\projects\my-app while the canonical on-disk path is C:\projects\my-app.
The unit-test builder derives workspaceRoot from the cwd and passes it verbatim to
Vitest as root (packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts,
the startVitest(...) call). Vitest's module runner then executes test files and the
builder-generated init module (angular:test-bed-init) under file:///c:/... URLs,
while the init module's externalized import 'vitest' is resolved by Node to the real
on-disk casing, file:///C:/....
Node's ESM cache is keyed by URL string, so file:///c:/... and file:///C:/...
load the vitest package twice. The second copy has no worker state, and its entry
guard throws — for every test file in the project:
Error: Vitest failed to find the runner. One of the following is possible:
- "vitest" is imported directly without running "vitest" command
- "vitest" is imported inside "globalSetup" (to fix this, use "setupFiles" instead, because "globalSetup" runs in a different context)
- "vitest" is imported inside Vite / Vitest config file
- Otherwise, it might be a Vitest bug. Please report it to https://github.com/vitest-dev/vitest/issues
❯ angular:test-bed-init:angular:test-bed-init:16:5
Test Files 194 failed (194)
The run banner shows which spelling a run used, making the difference easy to see:
RUN v4.1.10 c:/projects/my-app ← fails (cwd typed lowercase)
RUN v4.1.10 C:/projects/my-app ← works
This is easy to hit unknowingly: any cmd session entered via a lowercase cd, or an
IDE whose workspace was registered with a lowercase path (its integrated terminals
inherit the lowercase cwd).
Minimal Reproduction
Reproduced (by human me)
On Windows, in cmd.exe:
ng new repro --defaults
cd /d c:\<path-to>\repro REM note: lowercase drive letter
ng test --watch=false
Every spec fails with the error above. Re-entering with the canonical casing makes the
same command pass:
cd /d C:\<path-to>\repro
ng test --watch=false
Suggested fix (AI generated)
Canonicalize the workspace root before handing it to Vitest, e.g. with
fs.realpathSync.native(workspaceRoot) in the Vitest executor (or once at CLI
workspace-resolution level, which would cover all builders). realpathSync.native
returns the true on-disk casing and would also normalize two related path-identity
variants that can cause the same double-load: junction/symlink paths and 8.3 short
names.
Note the same casing must be used consistently by the in-memory test-file provider
(its resolveId/load compare paths against workspaceRoot), so normalizing at the
point where workspaceRoot is first established seems safest.
Workaround
Enter the project with the canonical drive-letter casing (cd /d C:\...), or wrap
ng test in a script that re-spawns it with cwd: fs.realpathSync.native(process.cwd()).
Exception or Error
Your Environment
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI : 22.0.5
Angular : 22.0.6
Node.js : 24.15.0
Package Manager : npm 11.17.0
Operating System : win32 x64
┌─────────────────────────────────┬───────────────────┬───────────────────┐
│ Package │ Installed Version │ Requested Version │
├─────────────────────────────────┼───────────────────┼───────────────────┤
│ @angular/build │ 22.0.5 │ ^22.0.5 │
│ @angular/cdk │ 22.0.4 │ ^22.0.4 │
│ @angular/cli │ 22.0.5 │ ^22.0.5 │
│ @angular/common │ 22.0.6 │ ^22.0.6 │
│ @angular/compiler │ 22.0.6 │ ^22.0.6 │
│ @angular/compiler-cli │ 22.0.6 │ ^22.0.6 │
│ @angular/core │ 22.0.6 │ ^22.0.6 │
│ @angular/forms │ 22.0.6 │ ^22.0.6 │
│ @angular/google-maps │ 22.0.4 │ ^22.0.4 │
│ @angular/localize │ 22.0.6 │ ^22.0.6 │
│ @angular/material │ 22.0.4 │ ^22.0.4 │
│ @angular/material-luxon-adapter │ 22.0.4 │ ^22.0.4 │
│ @angular/platform-browser │ 22.0.6 │ ^22.0.6 │
│ @angular/router │ 22.0.6 │ ^22.0.6 │
│ @angular/upgrade │ 22.0.6 │ ^22.0.6 │
│ rxjs │ 7.8.2 │ ^7.8.2 │
│ typescript │ 6.0.3 │ ^6.0.3 │
│ vitest │ 4.1.10 │ ^4.1.10 │
│ zone.js │ 0.16.2 │ ^0.16.2 │
└─────────────────────────────────┴───────────────────┴───────────────────┘
Anything else relevant?
No response
Command
test
Is this a regression?
New project tests fail #32087
and farer away build-related similar problems
build fails on windows if drive letter is lowercase #26519
ng serve / ng build does not work with windows junctions #32306
The previous version in which this bug was not present was
No response
Description
On Windows, the drive-letter casing of
process.cwd()is whatever the user typed:cmd.exepreserves it literally, socd c:\projects\my-appyields a cwd ofc:\projects\my-appwhile the canonical on-disk path isC:\projects\my-app.The unit-test builder derives
workspaceRootfrom the cwd and passes it verbatim toVitest as
root(packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts,the
startVitest(...)call). Vitest's module runner then executes test files and thebuilder-generated init module (
angular:test-bed-init) underfile:///c:/...URLs,while the init module's externalized
import 'vitest'is resolved by Node to the realon-disk casing,
file:///C:/....Node's ESM cache is keyed by URL string, so
file:///c:/...andfile:///C:/...load the
vitestpackage twice. The second copy has no worker state, and its entryguard throws — for every test file in the project:
The run banner shows which spelling a run used, making the difference easy to see:
This is easy to hit unknowingly: any
cmdsession entered via a lowercasecd, or anIDE whose workspace was registered with a lowercase path (its integrated terminals
inherit the lowercase cwd).
Minimal Reproduction
Reproduced (by human me)
On Windows, in
cmd.exe:Every spec fails with the error above. Re-entering with the canonical casing makes the
same command pass:
Suggested fix (AI generated)
Canonicalize the workspace root before handing it to Vitest, e.g. with
fs.realpathSync.native(workspaceRoot)in the Vitest executor (or once at CLIworkspace-resolution level, which would cover all builders).
realpathSync.nativereturns the true on-disk casing and would also normalize two related path-identity
variants that can cause the same double-load: junction/symlink paths and 8.3 short
names.
Note the same casing must be used consistently by the in-memory test-file provider
(its
resolveId/loadcompare paths againstworkspaceRoot), so normalizing at thepoint where
workspaceRootis first established seems safest.Workaround
Enter the project with the canonical drive-letter casing (
cd /d C:\...), or wrapng testin a script that re-spawns it withcwd: fs.realpathSync.native(process.cwd()).Exception or Error
Your Environment
Anything else relevant?
No response