V8 Coverage showing unexpected results
- 主要言語
- TypeScript
- スター
- 27k
- フォーク
- 11.8k
- 平均マージ
- 14時間 23分
- マージ済み PR(30日)
- 162
説明
### 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:
Similar from my project:
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
```true
```
### Please provide the environment you discovered this bug in (run `ng version`)
```true
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_
コントリビューションガイド
調査の方向性
`ng test --coverage` を使った Angular 21 の再現から始め、`angular.json` と `vitest.config.ts` を `app.ts` および `app.spec.ts` への変更と併せて調査します。空のコンポーネントに対する V8 のブランチレポートを、設定されている coverage の include と exclude と比較します。再現可能なケースと期待される coverage の挙動を文書化したうえで、その結果が期待される V8 の挙動なのか、Angular CLI のユニットテスト builder の不具合なのかを明らかにできれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- angular, typescript
- 領域
- build-system, testing-qa
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 静か
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 45/100