From 134f58e466c9b8451428d4614e264fc340a423f0 Mon Sep 17 00:00:00 2001 From: Karan Mistry Date: Sat, 10 Jan 2026 16:25:52 +0530 Subject: [PATCH] build: add 'update' option for Vitest runner and corresponding tests Fixes #32218 --- .../build/src/builders/unit-test/options.ts | 7 +- .../unit-test/runners/vitest/executor.ts | 1 + .../build/src/builders/unit-test/schema.json | 5 ++ .../unit-test/tests/options/update_spec.ts | 74 +++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 packages/angular/build/src/builders/unit-test/tests/options/update_spec.ts diff --git a/packages/angular/build/src/builders/unit-test/options.ts b/packages/angular/build/src/builders/unit-test/options.ts index 7f8f8db182fe..8f711c2a7a6a 100644 --- a/packages/angular/build/src/builders/unit-test/options.ts +++ b/packages/angular/build/src/builders/unit-test/options.ts @@ -54,12 +54,16 @@ export async function normalizeOptions( const buildTargetSpecifier = options.buildTarget ?? `::development`; const buildTarget = targetFromTargetString(buildTargetSpecifier, projectName, 'build'); - const { runner, browsers, progress, filter, browserViewport, ui, runnerConfig } = options; + const { runner, browsers, progress, filter, browserViewport, ui, runnerConfig, update } = options; if (ui && runner !== Runner.Vitest) { throw new Error('The "ui" option is only available for the "vitest" runner.'); } + if (update && runner !== Runner.Vitest) { + throw new Error('The "update" option is only available for the "vitest" runner.'); + } + const [width, height] = browserViewport?.split('x').map(Number) ?? []; let tsConfig = options.tsConfig; @@ -132,6 +136,7 @@ export async function normalizeOptions( ? true : path.resolve(workspaceRoot, runnerConfig) : runnerConfig, + update: update ?? false, }; } 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 ed754d9f9c30..5bbcd3b6f431 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 @@ -238,6 +238,7 @@ export class VitestExecutor implements TestExecutor { watch, ...(typeof ui === 'boolean' ? { ui } : {}), ...debugOptions, + update: this.options.update, }, { // Note `.vitest` is auto appended to the path. diff --git a/packages/angular/build/src/builders/unit-test/schema.json b/packages/angular/build/src/builders/unit-test/schema.json index 2a3cf27719e8..c1118738ffc3 100644 --- a/packages/angular/build/src/builders/unit-test/schema.json +++ b/packages/angular/build/src/builders/unit-test/schema.json @@ -269,6 +269,11 @@ "description": "Dumps build output files to the `.angular/cache` directory for debugging purposes.", "default": false, "visible": false + }, + "update": { + "type": "boolean", + "description": "Updates test snapshots to match the current test output. This option is only available for the Vitest runner.", + "default": false } }, "additionalProperties": false, diff --git a/packages/angular/build/src/builders/unit-test/tests/options/update_spec.ts b/packages/angular/build/src/builders/unit-test/tests/options/update_spec.ts new file mode 100644 index 000000000000..710f59cd8f89 --- /dev/null +++ b/packages/angular/build/src/builders/unit-test/tests/options/update_spec.ts @@ -0,0 +1,74 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { execute } from '../../index'; +import { + BASE_OPTIONS, + describeBuilder, + UNIT_TEST_BUILDER_INFO, + setupApplicationTarget, +} from '../setup'; + +describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => { + describe('Option: "update"', () => { + beforeEach(() => { + setupApplicationTarget(harness); + }); + + describe('Vitest Runner', () => { + it('should work with update flag enabled', async () => { + harness.useTarget('test', { + ...BASE_OPTIONS, + update: true, + }); + + const { result } = await harness.executeOnce(); + + expect(result?.success).toBeTrue(); + }); + + it('should work with update flag disabled', async () => { + harness.useTarget('test', { + ...BASE_OPTIONS, + update: false, + }); + + const { result } = await harness.executeOnce(); + + expect(result?.success).toBeTrue(); + }); + + it('should work without update flag (default)', async () => { + harness.useTarget('test', { + ...BASE_OPTIONS, + }); + + const { result } = await harness.executeOnce(); + + expect(result?.success).toBeTrue(); + }); + }); + + describe('Karma Runner', () => { + it('should throw an error when update is used with karma', async () => { + harness.useTarget('test', { + ...BASE_OPTIONS, + runner: 'karma', + update: true, + }); + + const { result, error } = await harness.executeOnce({ outputLogsOnException: false }); + + expect(result).toBeUndefined(); + expect(error?.message).toContain( + 'The "update" option is only available for the "vitest" runner.', + ); + }); + }); + }); +});