A production-ready Node.js project with a fully automated GitHub Actions CI pipeline — Jest unit tests, lcov coverage reports, Codecov integration, and ESLint linting, all running in parallel on every Pull Request.
node-ci-pipeline/
├── .github/
│ └── workflows/
│ └── ci.yml ← GitHub Actions CI pipeline
├── src/
│ ├── mathUtils.js ← Math utility functions
│ ├── stringUtils.js ← String utility functions
│ └── arrayUtils.js ← Array utility functions
├── tests/
│ ├── mathUtils.test.js
│ ├── stringUtils.test.js
│ └── arrayUtils.test.js
├── coverage/ ← Generated by Jest (git-ignored)
├── .gitignore
├── package.json
└── README.md
- Node.js ≥ 18 — Download
- npm ≥ 9 (bundled with Node.js)
# 1. Clone the repository
git clone https://github.com/<YOUR_USERNAME>/node-ci-pipeline.git
cd node-ci-pipeline
# 2. Install dependencies (use ci for reproducible installs)
npm ci# Run all tests with coverage
npm test
# Watch mode (re-runs on file save)
npm run test:watchAfter the run, a full HTML + lcov coverage report is available in coverage/.
# Check for linting errors
npm run lint
# Auto-fix fixable issues
npm run lint:fixThe pipeline is defined in .github/workflows/ci.yml and is triggered automatically on every Pull Request targeting main.
Pull Request → main
│
├──► 🧪 test (Node 18.x) ─┐
├──► 🧪 test (Node 20.x) ─┤──► Codecov upload (20.x only)
│ │
└──► 🔍 lint ─┘
(parallel)
| Step | Action |
|---|---|
| Checkout | actions/checkout@v4 |
| Setup Node | actions/setup-node@v4 (matrix: 18.x, 20.x) |
| Install deps | npm ci |
| Run tests | npm test → Jest with --coverage |
| Upload coverage | codecov/codecov-action@v3 (Node 20 only) |
- Jest is configured to output an lcov report (
coverage/lcov.info). - A coverage threshold is enforced: ≥ 80 % lines/functions/statements, ≥ 70 % branches. The job fails if thresholds are not met.
- The
codecov/codecov-actionstep uploadslcov.infoto Codecov so coverage history is tracked per PR.
| Step | Action |
|---|---|
| Checkout | actions/checkout@v4 |
| Setup Node | actions/setup-node@v4 (20.x) |
| Install deps | npm ci |
| Lint | npm run lint → ESLint on src/ and tests/ |
Both jobs must pass for the PR Status Checks to go green.
To block PR merges until both CI jobs pass, configure branch protection rules on GitHub:
- Go to your repository → Settings → Branches
- Click "Add branch protection rule"
- Set Branch name pattern to
main - Enable the following options:
| Setting | Value |
|---|---|
| Require a pull request before merging | ✅ |
| Require status checks to pass before merging | ✅ |
| Status checks that are required | 🧪 Unit Tests (Node 18.x) and 🧪 Unit Tests (Node 20.x) and 🔍 ESLint Linting |
| Require branches to be up to date before merging | ✅ (recommended) |
| Do not allow bypassing the above settings | ✅ (optional, enforces for admins too) |
- Click "Save changes"
Tip: The status check names must exactly match the
name:field of each job inci.yml.
- Sign in at codecov.io with your GitHub account.
- Add your repository.
- Copy your Codecov Upload Token.
- In GitHub, go to Settings → Secrets and variables → Actions → New repository secret.
- Create a secret named
CODECOV_TOKENand paste the token.
The workflow will automatically upload coverage after a successful test run.
Configured in package.json under jest.coverageThreshold:
| Metric | Threshold |
|---|---|
| Statements | 80 % |
| Functions | 80 % |
| Lines | 80 % |
| Branches | 70 % |
Dropping below these thresholds will fail the CI job, blocking the PR merge.
| Practice | Details |
|---|---|
| Pinned action versions | All actions use @v4 / @v3 tags; pin to commit SHAs for maximum security |
npm ci over npm install |
Reproducible, deterministic installs from package-lock.json |
| Minimal permissions | permissions: contents: read at workflow level |
cache: "npm" |
Node setup step caches npm for faster runs |
| Matrix testing | Tests run on Node 18 and 20 simultaneously |
| Parallel jobs | test and lint run concurrently, reducing total CI time |
fail_ci_if_error: true |
Codecov upload failures surface immediately |
The project is structured to make adding more tests trivial:
- Add a new module in
src/, e.g.src/dateUtils.js - Add a corresponding test file in
tests/dateUtils.test.js - Jest will automatically discover and run it — no config changes needed.
To add a new CI job (e.g. integration tests, Docker build), add another job block in ci.yml — it will run in parallel by default unless you add a needs: dependency.
MIT