After this lesson, you will be able to: Run Jest / Vitest in CI, gate on coverage thresholds, fail the build on coverage drops.
Tests not run in CI are tests that decay. This lesson wires the test pyramid into the pipeline.
Modern, fast, almost-jest-compatible.
# .github/workflows/test.ymlname: Teston: [pull_request, push]jobs:test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: actions/setup-node@v4with: { node-version: 20, cache: npm }- run: npm ci- run: npm test -- --coverage --reporter=verbose --reporter=junit --outputFile=junit.xml- name: Upload junit reportif: always()uses: actions/upload-artifact@v4with:name: junitpath: junit.xml- name: Upload coverageuses: actions/upload-artifact@v4with:name: coveragepath: coverage/
Vitest / Jest support `--coverage.threshold` (or a config block) that fails CI if % drops below a number. Pick THRESHOLDS PER FILE, not global. 'Global 80%' lets you have one 0% file and one 100% file. Better: changed-file coverage (codecov.io / coveralls.io), only the diff must meet a threshold. New code can't lower coverage. Threshold value: pick the current observed coverage as the baseline. Don't aim for 100%; 60-80% on critical-path code is typical for healthy teams.
Add to vite.config.ts (or vitest.config.ts).
// vitest.config.tsimport { defineConfig } from 'vitest/config';export default defineConfig({test: {coverage: {provider: 'v8',reporter: ['text', 'lcov', 'html'],reportsDirectory: './coverage',thresholds: {lines: 70,functions: 70,branches: 60,statements: 70,},exclude: ['**/*.test.ts', 'dist/**', 'node_modules/**'],},},});
Playwright is the modern standard. Runs real browsers in CI. Pattern: separate job that boots the app + DB + runs tests. Slow (5-15 min) but high-signal. Run e2e on a subset of changes (e.g. on PRs that touch frontend) to keep CI fast. Capture screenshots + videos on failure; uploaded as artifacts. Debugging 'CI flaked' is 10x easier with visual evidence.
Drop next to test.yml.
name: E2Eon: [pull_request]jobs:e2e:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: actions/setup-node@v4with: { node-version: 20, cache: npm }- run: npm ci- run: npx playwright install --with-deps chromium- run: npm run build- run: npx playwright testenv:BASE_URL: http://localhost:3000- if: always()uses: actions/upload-artifact@v4with:name: playwright-reportpath: playwright-report/
Coverage as the only metric. A 100%-covered useless test is still useless. Behavior > coverage. Setting a too-high threshold from day one. The team starts writing low-value tests to satisfy the bar. Skipping flaky-test detection. Re-runs hide flakes; fix them. Running e2e on every workflow. Use a subset of triggers + paths. Not uploading test reports. Failed builds are debugged 10x faster with HTML reports.
Pick the senior answer.
Sign in and purchase access to unlock this lesson.