CodingNic

CI/CD Fundamentals

A GitHub Actions Workflow for Testing

CI/CD Fundamentals 15 min read

A GitHub Actions Workflow for Testing

Objectives

By the end of this lesson, you should be able to:

  • Write a GitHub Actions workflow file, with the correct trigger, job, and step structure
  • Explain what each part of the workflow, on, jobs, steps, actually controls
  • Run a real Node.js test suite automatically on every push and pull request

💡 Why this matters: Course 3, Module 7 and 8 built a real, passing Jest and Supertest suite. This lesson is what actually runs it automatically, on every single push, rather than whenever someone remembers to run npm test by hand.

⚠️ A note on verification: GitHub Actions runs on GitHub’s own infrastructure, it can’t execute inside this course’s own sandboxed tooling. The YAML below was validated with a real YAML parser, confirming it’s syntactically correct and structured the way described, its actual execution, a runner starting up, checking out code, and running tests, reflects GitHub Actions’ stable, current, documented behavior. Push this to a real GitHub repository to see it run.

A Workflow File

text
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

This file lives at .github/workflows/ci.yml, that specific path is what GitHub Actions watches for, any correctly formatted workflow file there is picked up automatically.

Reading It Piece by Piece

on: defines the triggers, here, every push to main, and every pull request targeting main, a workflow can trigger on many other events too, a schedule, a manual button press, a release being published. jobs: defines one or more jobs, each running independently, potentially in parallel, runs-on: ubuntu-latest picks the operating system the job actually runs on. steps: runs in order, within a job, uses: runs a pre-built action (actions/checkout@v4 fetches the repository’s code, actions/setup-node@v4 installs a specific Node.js version), run: executes a raw shell command directly.

Why Dependencies Are Cached

cache: 'npm' on the setup-node step caches installed node_modules between workflow runs, keyed by the lockfile’s contents, exactly the same layer-caching idea from Module 3’s Dockerfile, unchanged dependencies mean a much faster npm ci on the next run, instead of downloading everything from scratch every single time.

What Actually Runs, Automatically

Every push to main, and every pull request opened against it, triggers this workflow: a fresh Ubuntu machine starts, checks out the exact code from that push, installs Node.js 20, installs dependencies, and runs npm test, exactly Course 3’s Jest and Supertest suite, if any test fails, the workflow fails, visibly, on the pull request itself, before anyone needs to review the code manually to catch it.

Try It

  1. Write this workflow file, and place it at .github/workflows/ci.yml in a real Git repository with a package.json and a test script.
  2. Push it to GitHub, open a pull request, and confirm the workflow runs automatically, visible directly on the pull request.
  3. Deliberately break a test, push that change, and confirm the workflow fails, and that failure is visible before the change is merged.
  4. Explain, in one or two sentences, what cache: 'npm' actually speeds up, and why it’s keyed by the lockfile specifically.

Recap

  • A workflow file at .github/workflows/ defines triggers (on), jobs, and steps, GitHub Actions picks it up and runs it automatically.
  • uses: runs a pre-built action, run: executes a raw shell command, both are valid steps within a job.
  • This workflow runs Course 3’s real test suite on every push and pull request, catching a broken change before it merges, exactly what continuous integration means in practice.

Next lesson: extending this workflow to build and publish Module 3’s Docker image once tests pass, continuous deployment on top of continuous integration.