Current behavior
When running Angular Component Testing for multiple libraries in parallel (e.g. in an Nx monorepo with nx run-many --target=component-test --parallel=5), specs can randomly fail with missing / mismatched specPattern, missing spec files, or "No specs found" style errors. Retries (retries: { runMode: 1 }) do not help — the same project often fails again on retry, and other runs at the same concurrency silently pick up the wrong config.
The cause is in @cypress/webpack-dev-server's Angular handler:
https://github.com/cypress-io/cypress/blob/develop/npm/webpack-dev-server/src/helpers/angularHandler.ts#L114-L168
const tsConfigPath = path.join(await getTempDir(path.basename(projectRoot)), 'tsconfig.json')
// ...
export async function getTempDir (projectName: string): Promise<string> {
const cypressTempDir = path.join(tmpdir(), 'cypress-angular-ct', projectName)
await fs.ensureDir(cypressTempDir)
return cypressTempDir
}
The temp directory that holds Cypress' generated tsconfig.json is keyed only on path.basename(projectRoot). In a monorepo it is common to have multiple Cypress component-test projects whose project roots share the same basename but live at different paths, for example:
libs/feature-a/feat-shell/
libs/feature-b/feat-shell/
libs/feature-c/feat-shell/
All three resolve to the same temp path:
/tmp/cypress-angular-ct/feat-shell/tsconfig.json
When two such projects run component-test in parallel, generateTsConfig races on that single file. Whichever project writes last wins, so the other project's webpack build loads the wrong include / specPattern / supportFile paths and the spec fails. Because projectRoot / tmp dir resolution is deterministic, Cypress retries reproduce the same collision.
Desired behavior
The temp tsconfig path should be unique per projectRoot, not just per its basename, so that parallel component-test runs of libraries with colliding basenames never share a config file.
A simple, backwards-compatible fix is to suffix the directory name with a short hash of the absolute projectRoot, e.g.:
export async function getTempDir (projectName: string, projectRoot?: string): Promise<string> {
const uniqueName = projectRoot
? `${projectName}-${createHash('sha1').update(projectRoot).digest('hex').slice(0, 8)}`
: projectName
const cypressTempDir = path.join(tmpdir(), 'cypress-angular-ct', uniqueName)
await fs.ensureDir(cypressTempDir)
return cypressTempDir
}
Keeping projectRoot optional preserves the current public signature for any external callers.
Test code to reproduce
Minimal Nx-style repro:
- Create two Angular component-testing projects whose directories share a basename, e.g.
libs/feature-a/feat-shell and libs/feature-b/feat-shell, each with its own cypress.config.ts using framework: 'angular', bundler: 'webpack' and a single spec.
- Run them in parallel:
nx run-many --target=component-test --projects=feature-a-feat-shell,feature-b-feat-shell --parallel=2
- Re-run the command several times. Some runs will fail for one of the two projects with spec-resolution errors while the other passes. Inspecting
/tmp/cypress-angular-ct/feat-shell/tsconfig.json during the run shows the include paths alternate between the two projects.
In a real monorepo with ~20 Angular CT projects and --parallel=5, we observed failure rates up to ~16% on individual projects that share a basename (confirmed via Nx Cloud analytics over 2 weeks), while projects with unique basenames had 100% pass rates.
Cypress Version
15.x (@cypress/webpack-dev-server@5.2.1); the bug exists on develop as well.
Node version
20.x
Operating System
Linux (reproduced on CI runners) and macOS.
Debug Logs
# observable in /tmp/cypress-angular-ct/<basename>/tsconfig.json
# which flips between siblings during a parallel run
Other
Happy to send a PR with the hash-based fix + a unit test covering two distinct projectRoots that share a basename.
Current behavior
When running Angular Component Testing for multiple libraries in parallel (e.g. in an Nx monorepo with
nx run-many --target=component-test --parallel=5), specs can randomly fail with missing / mismatchedspecPattern, missing spec files, or "No specs found" style errors. Retries (retries: { runMode: 1 }) do not help — the same project often fails again on retry, and other runs at the same concurrency silently pick up the wrong config.The cause is in
@cypress/webpack-dev-server's Angular handler:https://github.com/cypress-io/cypress/blob/develop/npm/webpack-dev-server/src/helpers/angularHandler.ts#L114-L168
The temp directory that holds Cypress' generated
tsconfig.jsonis keyed only onpath.basename(projectRoot). In a monorepo it is common to have multiple Cypress component-test projects whose project roots share the same basename but live at different paths, for example:All three resolve to the same temp path:
When two such projects run
component-testin parallel,generateTsConfigraces on that single file. Whichever project writes last wins, so the other project's webpack build loads the wronginclude/specPattern/supportFilepaths and the spec fails. BecauseprojectRoot/ tmp dir resolution is deterministic, Cypressretriesreproduce the same collision.Desired behavior
The temp tsconfig path should be unique per
projectRoot, not just per its basename, so that parallel component-test runs of libraries with colliding basenames never share a config file.A simple, backwards-compatible fix is to suffix the directory name with a short hash of the absolute
projectRoot, e.g.:Keeping
projectRootoptional preserves the current public signature for any external callers.Test code to reproduce
Minimal Nx-style repro:
libs/feature-a/feat-shellandlibs/feature-b/feat-shell, each with its owncypress.config.tsusingframework: 'angular', bundler: 'webpack'and a single spec./tmp/cypress-angular-ct/feat-shell/tsconfig.jsonduring the run shows theincludepaths alternate between the two projects.In a real monorepo with ~20 Angular CT projects and
--parallel=5, we observed failure rates up to ~16% on individual projects that share a basename (confirmed via Nx Cloud analytics over 2 weeks), while projects with unique basenames had 100% pass rates.Cypress Version
15.x (
@cypress/webpack-dev-server@5.2.1); the bug exists ondevelopas well.Node version
20.x
Operating System
Linux (reproduced on CI runners) and macOS.
Debug Logs
Other
Happy to send a PR with the hash-based fix + a unit test covering two distinct
projectRoots that share a basename.