V8 Coverage showing unexpected results
- 主要语言
- TypeScript
- 星标
- 27k
- 派生
- 11.8k
- 平均合并
- 14 小时 23 分钟
- 30 天内合并 PR
- 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 中复现,然后结合对 `app.ts` 和 `app.spec.ts` 的更改,检查 `angular.json` 和 `vitest.config.ts`。将空组件的 V8 分支报告与已配置的 coverage include 和 exclude 进行比较。完成的标准是确定该结果属于预期的 V8 行为,还是 Angular CLI unit-test builder 中的缺陷,并记录可复现的案例和预期的 coverage 行为。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- angular, typescript
- 领域
- build-system, testing-qa
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 45/100