V8 Coverage showing unexpected results

Ouverte
#32,836 11 commentaires 7 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
45/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
Calme
Stack technique
angular, typescript

Piste de recherche

Commencez par reproduire le problème avec Angular 21 en utilisant ng test --coverage, puis examinez angular.json et vitest.config.ts ainsi que les modifications apportées à app.ts et app.spec.ts. Comparez le rapport de branche V8 du composant vide avec les inclusions et exclusions de coverage configurées. Le travail est terminé lorsqu’il est établi si le résultat correspond au comportement attendu de V8 ou à un défaut du builder de tests unitaires d’Angular CLI, avec un cas reproductible et le comportement attendu de la coverage documenté.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

angular/build:unit-test area: @angular/build gemini-triaged
Which @angular/* package(s) are the source of the bug?

Don't known / other

Is this a regression?

No

Description

I'm in the process of migrating from jasmine/karma with istanbul coverage to vitest with v8 coverage. I'm currently migrating around 2500 unit tests. With Istanbul I had over 95% coverage across statements, branches, functions and lines. With vitest I'm seeing lower coverage, mainly on the branches with 90%.

I've noticed that even empty classes (template only) show 90% branch coverage (9/10).

A minimal reproduction:

  • Create a new Angular 21 application: ng new ng21
  • Install v8 coverage npm i --save-dev @vitest/coverage-v8
  • Remove the protected title variable from app.ts -- protected readonly title = signal('ng21');
  • Remove the should render title test from app.spec.ts
  • Run ng test --coverage

This is the coverage I see:
Image

Similar from my project:
Image

with the spec file as:

import { TestBed } from '@angular/core/testing';
import { HeaderComponent } from './header.component';
import { HeaderComponent as ClsHeaderComponent, TenantDropdownComponent } from '@cls/ui-util';
import { MockComponent } from '@cls/ui-util/testing';
import { SearchComponent } from '../../schedule/components/search/search.component';

describe('HeaderComponent', () => {
    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [HeaderComponent],
            providers: []
        })
            .overrideComponent(HeaderComponent, {
                remove: { imports: [SearchComponent, ClsHeaderComponent, TenantDropdownComponent] },
                add: {
                    imports: [
                        MockComponent({ selector: 'app-search' }) as any,
                        MockComponent({ selector: 'cls-header' }) as any,
                        MockComponent({ selector: 'cls-tenant-dropdown' }) as any
                    ]
                }
            })
            .compileComponents();
    });

    function setup() {
        const fixture = TestBed.createComponent(HeaderComponent);

        return {
            fixture,
            app: fixture.componentInstance,
            compiled: fixture.debugElement.nativeElement
        };
    }

    it('should create the app', () => {
        const { app } = setup();
        expect(app).toBeTruthy();
    });
});

angular.json

"test": {
  "builder": "@angular/build:unit-test",
  "options": {
    "browsers": ["chromium"],
    "buildTarget": "admin-ui:build",
    "headless": true,
    "tsConfig": "./tsconfig.spec.json",
    "runnerConfig": "./vitest.config.ts",
    "coverage": true,
    "coverageInclude": ["src/app/**/*.ts"],
    "coverageExclude": ["index.ts", "main.ts", "polyfills.ts", "**/*.routes.ts", "**/*.model.ts", "**/*.interface.ts"],
    "coverageReporters": ["text", "html", "lcov"],
    "coverageThresholds": {
      "statements": 90,
      "branches": 90,
      "functions": 90,
      "lines": 90
    }
  }
}

vitest.config.ts

import { defineConfig } from 'vitest/config';

export default defineConfig({
    test: {
        environment: 'jsdom',
        globals: true,
        setupFiles: ['src/test-setup.ts'],
        restoreMocks: true,
        coverage: {
            provider: 'v8'
        },
        browser: {
            screenshotFailures: false
        }
    }
});

Have I misconfigured something? Do I have an incorrect assumption of v8 coverage or is there an issue here?

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

Please provide the environment you discovered this bug in (run ng version)
Angular CLI       : 21.2.3
Angular           : 21.2.5
Node.js           : 22.13.1
Package Manager   : npm 10.9.2
Operating System  : darwin arm64

┌───────────────────────────────────┬───────────────────┬───────────────────┐
│ Package                           │ Installed Version │ Requested Version │
├───────────────────────────────────┼───────────────────┼───────────────────┤
│ @angular/animations               │ 21.2.5            │ ~21.2.0           │
│ @angular/build                    │ 21.2.3            │ ^21.2.0           │
│ @angular/cdk                      │ 21.2.3            │ ~21.2.0           │
│ @angular/cli                      │ 21.2.3            │ ~21.2.0           │
│ @angular/common                   │ 21.2.5            │ ~21.2.0           │
│ @angular/compiler                 │ 21.2.5            │ ~21.2.0           │
│ @angular/compiler-cli             │ 21.2.5            │ ~21.2.0           │
│ @angular/core                     │ 21.2.5            │ ~21.2.0           │
│ @angular/forms                    │ 21.2.5            │ ~21.2.0           │
│ @angular/language-service         │ 21.2.5            │ ~21.2.0           │
│ @angular/platform-browser         │ 21.2.5            │ ~21.2.0           │
│ @angular/platform-browser-dynamic │ 21.2.5            │ ~21.2.0           │
│ @angular/router                   │ 21.2.5            │ ~21.2.0           │
│ rxjs                              │ 7.8.2             │ ~7.8.2            │
│ typescript                        │ 5.9.3             │ ~5.9.3            │
│ vitest                            │ 4.1.0             │ ^4.0.18           │
│ zone.js                           │ 0.15.1            │ ~0.15.0           │
└───────────────────────────────────┴───────────────────┴──────────────────
Anything else?

No response

Langage dominant
TypeScript
Étoiles
27k
Forks
11.8k
Merge moyen
16 h 35 min
PR mergées (30 j)
176

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de angular/angular-cli

Toutes les issues de angular/angular-cli

Issues similaires

Plus d'issues TypeScript

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.