From b71b59f033dafc0f7ecfb1e6d9f9109971d11e27 Mon Sep 17 00:00:00 2001
From: Charles Lyding <19598772+clydin@users.noreply.github.com>
Date: Mon, 30 Mar 2026 18:15:34 -0400
Subject: [PATCH] test(@angular/build): verify coverage ignore comments are
preserved during compilation
The underlying Vitest coverage engine depends on specific developer comments like `/* istanbul ignore next */` or `/* v8 ignore next */` being present in the executing code to accurately isolate unmeasured blocks.
This commit adds strict behavioral tests to assert that the Angular CLI's in-memory compilation pipeline (via esbuild) properly preserves these structural comments and forwards them reliably to Vitest's coverage processing engine.
---
.../behavior/coverage-ignore-comments_spec.ts | 143 ++++++++++++++++++
1 file changed, 143 insertions(+)
create mode 100644 packages/angular/build/src/builders/unit-test/tests/behavior/coverage-ignore-comments_spec.ts
diff --git a/packages/angular/build/src/builders/unit-test/tests/behavior/coverage-ignore-comments_spec.ts b/packages/angular/build/src/builders/unit-test/tests/behavior/coverage-ignore-comments_spec.ts
new file mode 100644
index 000000000000..d04c9aa7e690
--- /dev/null
+++ b/packages/angular/build/src/builders/unit-test/tests/behavior/coverage-ignore-comments_spec.ts
@@ -0,0 +1,143 @@
+/**
+ * @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('Behavior: "coverage ignore comments"', () => {
+ beforeEach(async () => {
+ setupApplicationTarget(harness);
+ });
+
+ it('should respect istanbul ignore next comments when computing coverage', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ coverage: true,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ coverageReporters: ['json'] as any,
+ });
+
+ harness.writeFile(
+ 'src/app/app.component.ts',
+ `
+ import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'app-root',
+ template: '
hello
',
+ standalone: true,
+ })
+ export class AppComponent {
+ title = 'app';
+
+ /* istanbul ignore next */
+ untestedFunction() {
+ return false;
+ }
+ }
+ `,
+ );
+
+ harness.writeFile(
+ 'src/app/app.component.spec.ts',
+ `
+ import { AppComponent } from './app.component';
+
+ describe('AppComponent', () => {
+ it('should create', () => {
+ const comp = new AppComponent();
+ expect(comp).toBeTruthy();
+ });
+ });
+ `,
+ );
+
+ const { result } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+ harness.expectFile('coverage/test/coverage-final.json').toExist();
+
+ const coverageMap = JSON.parse(harness.readFile('coverage/test/coverage-final.json'));
+ const appComponentPath = Object.keys(coverageMap).find((p) => p.includes('app.component.ts'));
+ expect(appComponentPath).toBeDefined();
+
+ const appComponentCoverage = coverageMap[appComponentPath!];
+
+ const statementCounts = Object.values(appComponentCoverage.s) as number[];
+ const hasUncoveredStatements = statementCounts.some((count) => count === 0);
+ expect(hasUncoveredStatements)
+ .withContext('There should be no uncovered statements as the uncalled function was ignored')
+ .toBeFalse();
+ });
+
+ it('should respect v8 ignore next comments when computing coverage', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ coverage: true,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ coverageReporters: ['json'] as any,
+ });
+
+ harness.writeFile(
+ 'src/app/app.component.ts',
+ `
+ import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'app-root',
+ template: 'hello
',
+ standalone: true,
+ })
+ export class AppComponent {
+ title = 'app';
+
+ /* v8 ignore next */
+ untestedFunction() {
+ return false;
+ }
+ }
+ `,
+ );
+
+ harness.writeFile(
+ 'src/app/app.component.spec.ts',
+ `
+ import { AppComponent } from './app.component';
+
+ describe('AppComponent', () => {
+ it('should create', () => {
+ const comp = new AppComponent();
+ expect(comp).toBeTruthy();
+ });
+ });
+ `,
+ );
+
+ const { result } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+ harness.expectFile('coverage/test/coverage-final.json').toExist();
+
+ const coverageMap = JSON.parse(harness.readFile('coverage/test/coverage-final.json'));
+ const appComponentPath = Object.keys(coverageMap).find((p) => p.includes('app.component.ts'));
+ expect(appComponentPath).toBeDefined();
+
+ const appComponentCoverage = coverageMap[appComponentPath!];
+
+ const statementCounts = Object.values(appComponentCoverage.s) as number[];
+ const hasUncoveredStatements = statementCounts.some((count) => count === 0);
+ expect(hasUncoveredStatements)
+ .withContext('There should be no uncovered statements as the uncalled function was ignored')
+ .toBeFalse();
+ });
+ });
+});