█
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/Software Engineering/Testing/Running Tests in CI
40 minIntermediate

Running Tests in CI

After this lesson, you will be able to: Run the test suite automatically on every pull request, fail the build on any failure, and publish coverage reports.

Tests that only run on your machine protect only you. Continuous integration runs the whole suite on every push and pull request, so a regression blocks the merge instead of reaching production. This lesson wires unit, integration, and e2e tests into GitHub Actions with coverage reporting.

Prerequisites:Test-Driven Development

Why tests belong in CI, not just on your laptop

Local tests are easy to skip under deadline pressure, and they only reflect your machine's state. CI runs the suite in a clean, reproducible environment on every pull request, for every contributor, every time. A failed test turns the PR red and (with branch protection) blocks the merge. That is what makes 'all tests pass' a property of main rather than a hope. It also catches the classic 'works on my machine' bugs from uncommitted files or local-only dependencies.

A GitHub Actions test workflow

Run on every push and PR. Cache dependencies for speed. Fail the job (and the PR) on any test failure.

tsx
# .github/workflows/test.yml
name: tests
on:
push: { branches: [main] }
pull_request:
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env: { POSTGRES_PASSWORD: test }
ports: ['5432:5432']
options: >-
--health-cmd pg_isready --health-interval 10s
--health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm run test:ci # vitest run --coverage; non-zero exit fails the job
- uses: codecov/codecov-action@v4
with: { files: ./coverage/coverage-final.json }

Make failures block the merge

A red CI run only matters if it stops the merge. In the GitHub repo settings, protect the main branch and mark the test job a required status check. Now a pull request cannot merge until tests pass, which is the entire point of CI. Add the e2e job as a separate workflow step (with Playwright's browsers cached) so slow e2e tests do not block the fast unit feedback, but still gate the merge.

💡 Keep CI fast or people route around it

If the suite takes twenty minutes, developers stop waiting for it. Cache dependencies and browser binaries, run independent jobs in parallel, and put the fast unit tests first so failures surface in seconds. A fast, trustworthy CI is one people respect; a slow, flaky one gets bypassed.

Quick Check

Your CI workflow runs the tests but teammates keep merging PRs with failing tests. What's missing?

Pick the best answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Test-Driven Development
Back to Testing
Passion Project: Add a Real Test Suite→