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 aa201e24c578..b5c7841c799b 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 @@ -398,11 +398,6 @@ export class VitestExecutor implements TestExecutor { const vitestServerConfig = { // Note `.vitest` is auto appended to the path. cacheDir: cacheOptions.path, - server: { - // Disable the actual file watcher. The boolean watch option above should still - // be enabled as it controls other internal behavior related to rerunning tests. - watch: null, - }, plugins: [ await createVitestConfigPlugin({ browser: browserOptions.browser, 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 ec0cd0a8f269..0a8a2c8990b4 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 @@ -164,6 +164,16 @@ export async function createVitestConfigPlugin( return { name: 'angular:vitest-configuration', + enforce: 'post', + configResolved: { + order: 'post', + handler(config: Vite.ResolvedConfig) { + // Vitest's internal post-configResolved hook resets `server.watch` to `{}` when + // `watch` is enabled (`server.watch ??= {}`). Force it back to `null` so Vite uses + // a no-op watcher and relies solely on the Angular CLI build watcher. + config.server.watch = null; + }, + }, async config(config: UserWorkspaceConfig & Vite.UserConfig) { const testConfig = config.test; diff --git a/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts b/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts index d1840beb4a96..79e25ca84b27 100644 --- a/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts +++ b/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts @@ -55,5 +55,38 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => { }, ]); }); + + it('should disable the Vite server file watcher when watch is true', async () => { + harness.useTarget('test', { + ...BASE_OPTIONS, + watch: true, + runnerConfig: 'vitest.config.mts', + }); + + await harness.writeFile( + 'vitest.config.mts', + ` + import { defineConfig } from 'vitest/config'; + export default defineConfig({ + plugins: [ + { + name: 'assert-watch-disabled', + configureVitest({ vitest, project }) { + if (vitest.vite.config.server.watch !== null || project.vite.config.server.watch !== null) { + throw new Error('Expected Vite server.watch to be null'); + } + }, + }, + ], + }); + `, + ); + + await harness.executeWithCases([ + ({ result }) => { + expect(result?.success).toBeTrue(); + }, + ]); + }); }); });