From e153dc499d9b54151455a5c2b64a0019e62337d2 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:04:06 -0400 Subject: [PATCH] fix(@angular/build): inherit preserveSymlinks option from build target in unit-test builder The unit-test builder did not pass the preserveSymlinks configuration to Vitest's custom configuration plugin and resolved it directly from buildTargetOptions in Karma executor without considering process arguments. This caused module resolution failures in unit tests for symlinked packages. This change inherits preserveSymlinks from the referenced buildTarget options, falling back to process.execArgv if not defined. The resolved value is then successfully forwarded to the underlying bundlers and executors (Karma and Vitest). --- packages/angular/build/src/builders/unit-test/builder.ts | 5 +++++ packages/angular/build/src/builders/unit-test/options.ts | 1 + .../build/src/builders/unit-test/runners/karma/executor.ts | 2 +- .../build/src/builders/unit-test/runners/vitest/executor.ts | 1 + .../build/src/builders/unit-test/runners/vitest/plugins.ts | 2 ++ 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/unit-test/builder.ts b/packages/angular/build/src/builders/unit-test/builder.ts index 542f5f978b90..c01b7b69d75e 100644 --- a/packages/angular/build/src/builders/unit-test/builder.ts +++ b/packages/angular/build/src/builders/unit-test/builder.ts @@ -286,6 +286,10 @@ export async function* execute( return; } + // Resolve final preserveSymlinks option + normalizedOptions.preserveSymlinks = + buildTargetOptions.preserveSymlinks ?? process.execArgv.includes('--preserve-symlinks'); + // Get runner-specific build options let runnerBuildOptions; let virtualFiles; @@ -327,6 +331,7 @@ export async function* execute( progress: normalizedOptions.buildProgress ?? buildTargetOptions.progress, quiet: normalizedOptions.quiet, ...(normalizedOptions.tsConfig ? { tsConfig: normalizedOptions.tsConfig } : {}), + preserveSymlinks: normalizedOptions.preserveSymlinks, } satisfies ApplicationBuilderInternalOptions; const dumpDirectory = normalizedOptions.dumpVirtualFiles diff --git a/packages/angular/build/src/builders/unit-test/options.ts b/packages/angular/build/src/builders/unit-test/options.ts index ef09958885a7..7ff4d3fa753f 100644 --- a/packages/angular/build/src/builders/unit-test/options.ts +++ b/packages/angular/build/src/builders/unit-test/options.ts @@ -134,6 +134,7 @@ export async function normalizeOptions( : [], dumpVirtualFiles: options.dumpVirtualFiles, listTests: options.listTests, + preserveSymlinks: undefined as boolean | undefined, runnerConfig: typeof runnerConfig === 'string' ? runnerConfig.length === 0 diff --git a/packages/angular/build/src/builders/unit-test/runners/karma/executor.ts b/packages/angular/build/src/builders/unit-test/runners/karma/executor.ts index 66bf203c25c7..3ef83752889a 100644 --- a/packages/angular/build/src/builders/unit-test/runners/karma/executor.ts +++ b/packages/angular/build/src/builders/unit-test/runners/karma/executor.ts @@ -91,7 +91,7 @@ export class KarmaExecutor implements TestExecutor { progress: unitTestOptions.buildProgress ?? buildTargetOptions.progress, watch: unitTestOptions.watch, poll: buildTargetOptions.poll, - preserveSymlinks: buildTargetOptions.preserveSymlinks, + preserveSymlinks: unitTestOptions.preserveSymlinks, browsers: unitTestOptions.browsers?.join(','), codeCoverage: unitTestOptions.coverage.enabled, codeCoverageExclude: unitTestOptions.coverage.exclude, 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 08a5a4dc55ff..7a9b56168d7b 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 @@ -382,6 +382,7 @@ export class VitestExecutor implements TestExecutor { include, watch, isolate: this.options.isolate, + preserveSymlinks: this.options.preserveSymlinks, }), ], }; diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts index c5e3764043bb..935518594295 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts @@ -55,6 +55,7 @@ interface VitestConfigPluginOptions { optimizeDepsInclude: string[]; watch: boolean; isolate: boolean | undefined; + preserveSymlinks?: boolean; } async function findTestEnvironment( @@ -258,6 +259,7 @@ export async function createVitestConfigPlugin( resolve: { mainFields: ['es2020', 'module', 'main'], conditions: ['es2015', 'es2020', 'module', ...(browser ? ['browser'] : [])], + preserveSymlinks: options.preserveSymlinks, }, };