█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/DevOps and Infrastructure/CI/CD Pipelines/Testing in CI
40 minIntermediate

Testing in CI

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.

Prerequisites:Environment Management

Vitest in CI

Modern, fast, almost-jest-compatible.

tsx
# .github/workflows/test.yml
name: Test
on: [pull_request, push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm test -- --coverage --reporter=verbose --reporter=junit --outputFile=junit.xml
- name: Upload junit report
if: always()
uses: actions/upload-artifact@v4
with:
name: junit
path: junit.xml
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/

Coverage thresholds — but pick the right ones

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.

Vitest coverage config

Add to vite.config.ts (or vitest.config.ts).

python
// vitest.config.ts
import { 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/**'],
},
},
});

End-to-end tests in CI

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.

Playwright in CI

Drop next to test.yml.

tsx
name: E2E
on: [pull_request]
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run build
- run: npx playwright test
env:
BASE_URL: http://localhost:3000
- if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/

Common mistakes only experienced engineers avoid

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.

Quick Check

Your test coverage % drops 5% on a PR. Is that always bad?

Pick the senior answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Environment Management
Back to CI/CD Pipelines
Security Scanning in CI→