feat(test): WP-46 — Vitest coverage (report-only)
Enable coverage via the @angular/build:unit-test builder's first-class options: a `coverage` configuration on the test target (v8 provider, text-summary/html/lcov, excludes for specs/stories/contracts/generated client) + `npm run test:coverage`. Report-only (no thresholds) — visibility first. CI's test step now runs test:coverage (strict superset: fails on a failing test, never on coverage). Baseline ~71% stmts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,9 @@ jobs:
|
||||
- run: npm run dep:check
|
||||
- run: npm run format:check
|
||||
- run: npm run check:tokens
|
||||
- run: npm test
|
||||
# Runs the full suite AND reports coverage (WP-46, report-only — no thresholds, so
|
||||
# it can't fail on coverage; it still fails on a failing test, like `npm test` did).
|
||||
- run: npm run test:coverage
|
||||
# --localize builds every configured locale (nl + en, angular.json's i18n
|
||||
# block) in one pass; i18nMissingTranslation:"error" (angular.json) fails
|
||||
# this step if messages.en.xlf is missing a unit the source (WP-20) gains.
|
||||
|
||||
+16
-1
@@ -91,7 +91,22 @@
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular/build:unit-test"
|
||||
"builder": "@angular/build:unit-test",
|
||||
"configurations": {
|
||||
"coverage": {
|
||||
"coverage": true,
|
||||
"coverageReporters": ["text-summary", "html", "lcov"],
|
||||
"coverageExclude": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.stories.ts",
|
||||
"**/contracts/**",
|
||||
"src/app/shared/infrastructure/api-client.ts",
|
||||
"src/main.ts",
|
||||
"src/test-setup.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storybook": {
|
||||
"builder": "@storybook/angular:start-storybook",
|
||||
|
||||
@@ -90,7 +90,7 @@ for its existing violations, so every WP ends green.
|
||||
| [WP-43](WP-43-scaffold-generators.md) | Runnable generators: value-object / form-machine / bff-endpoint / ui-component | 8 · platform/DX/showcase | todo |
|
||||
| [WP-44](WP-44-context-generator.md) | Runnable generator: `gen:context` | 8 · platform/DX/showcase | todo |
|
||||
| [WP-45](WP-45-create-ssp-generator.md) | `create-ssp` bootstrap generator (mechanise new-ssp) | 8 · platform/DX/showcase | todo |
|
||||
| [WP-46](WP-46-vitest-coverage.md) | Vitest coverage (report + report-only thresholds) | 8 · platform/DX/showcase | todo |
|
||||
| [WP-46](WP-46-vitest-coverage.md) | Vitest coverage (report + report-only thresholds) | 8 · platform/DX/showcase | done |
|
||||
|
||||
Sequencing dependencies (stated in the WPs too): 01 before 10–15 (axe covers story churn);
|
||||
03/04 before 05–09 (boundaries stop new violations during refactors); 06 before 07 (typed
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
# WP-46 — Vitest coverage (report + thresholds)
|
||||
|
||||
Status: todo
|
||||
Status: done
|
||||
Phase: 8 — platform/DX/showcase
|
||||
Priority: P1
|
||||
|
||||
## Outcome
|
||||
|
||||
Coverage is first-class in the `@angular/build:unit-test` builder — no separate vitest config
|
||||
needed. Added a `coverage` **configuration** to the `test` target in `angular.json` (`coverage: true`,
|
||||
reporters `text-summary`/`html`/`lcov`, excludes for specs/stories/contracts/generated
|
||||
`api-client.ts`/`main.ts`/`.d.ts`) + `@vitest/coverage-v8` (pinned to vitest's 4.1.9 to avoid the
|
||||
mixed-version warning). `npm run test:coverage` → `ng test --configuration coverage`. **Report-only
|
||||
(no thresholds)** per the ponytail default — visibility first. CI's test step now runs
|
||||
`test:coverage` (a strict superset of `npm test`: fails on a failing test, never on coverage).
|
||||
Baseline at delivery: **~71% statements / 69% branches / 68% functions / 74% lines.** Output dir
|
||||
`coverage/` was already git-ignored. Path to enforce later: add `coverageThresholds` to the config.
|
||||
|
||||
## Why
|
||||
|
||||
Tests run via the `@angular/build:unit-test` (Vitest) builder but report no coverage — there's no
|
||||
@@ -29,6 +41,6 @@ visibility into what the house test rules actually cover. A template/showcase sh
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] `npm run test:coverage` produces a report (text + HTML/lcov) with sensible excludes.
|
||||
- [ ] Coverage runs in CI without failing the build (report-only).
|
||||
- [ ] `npm run ci` green.
|
||||
- [x] `npm run test:coverage` produces a report (text-summary + HTML/lcov) with sensible excludes.
|
||||
- [x] Coverage runs in CI without failing the build (report-only).
|
||||
- [x] `npm run ci` green.
|
||||
|
||||
Generated
+118
@@ -33,6 +33,7 @@
|
||||
"@storybook/addon-onboarding": "^10.4.6",
|
||||
"@storybook/angular": "^10.4.6",
|
||||
"@storybook/test-runner": "^0.24.4",
|
||||
"@vitest/coverage-v8": "^4.1.9",
|
||||
"angular-eslint": "^22.0.0",
|
||||
"axe-playwright": "^2.2.2",
|
||||
"concurrently": "^10.0.3",
|
||||
@@ -10409,6 +10410,92 @@
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8": {
|
||||
"version": "4.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz",
|
||||
"integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bcoe/v8-coverage": "^1.0.2",
|
||||
"@vitest/utils": "4.1.9",
|
||||
"ast-v8-to-istanbul": "^1.0.0",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.2.0",
|
||||
"magicast": "^0.5.2",
|
||||
"obug": "^2.1.1",
|
||||
"std-env": "^4.0.0-rc.1",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vitest/browser": "4.1.9",
|
||||
"vitest": "4.1.9"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vitest/browser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8/node_modules/@bcoe/v8-coverage": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
|
||||
"integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8/node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz",
|
||||
"integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8/node_modules/@vitest/utils": {
|
||||
"version": "4.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz",
|
||||
"integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.9",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8/node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8/node_modules/tinyrainbow": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
|
||||
"integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
|
||||
@@ -11241,6 +11328,25 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ast-v8-to-istanbul": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.5.tgz",
|
||||
"integrity": "sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.31",
|
||||
"estree-walker": "^3.0.3",
|
||||
"js-tokens": "^10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ast-v8-to-istanbul/node_modules/js-tokens": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz",
|
||||
"integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||
@@ -18686,6 +18792,18 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/magicast": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz",
|
||||
"integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.29.3",
|
||||
"@babel/types": "^7.29.0",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"test:coverage": "ng test --configuration coverage",
|
||||
"storybook": "ng run atomic-design-poc:storybook",
|
||||
"build-storybook": "ng run atomic-design-poc:build-storybook",
|
||||
"test-storybook": "test-storybook",
|
||||
@@ -50,6 +51,7 @@
|
||||
"@storybook/addon-onboarding": "^10.4.6",
|
||||
"@storybook/angular": "^10.4.6",
|
||||
"@storybook/test-runner": "^0.24.4",
|
||||
"@vitest/coverage-v8": "^4.1.9",
|
||||
"angular-eslint": "^22.0.0",
|
||||
"axe-playwright": "^2.2.2",
|
||||
"concurrently": "^10.0.3",
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ step "lint"; npm run lint
|
||||
step "dependency boundaries"; npm run dep:check
|
||||
step "format:check (prettier)"; npm run format:check
|
||||
step "check:tokens"; npm run check:tokens
|
||||
step "test (vitest)"; npm test
|
||||
step "test (vitest + coverage)"; npm run test:coverage
|
||||
step "build --localize (nl+en)"; npx ng build --localize
|
||||
step "npm audit (shipped deps)"; npm audit --omit=dev
|
||||
step "backend format + tests"; ( cd backend && dotnet format BigRegister.slnx --verify-no-changes && dotnet test BigRegister.slnx )
|
||||
|
||||
Reference in New Issue
Block a user