Skip to content

Repository files navigation

CLI Testing Framework — Git Edition

A comprehensive CLI end-to-end testing framework that demonstrates real-world E2E testing of git — the most widely used CLI tool in software development. Built with TypeScript, Jest, and Node's built-in child_process (zero runtime dependencies).

Every test runs in an isolated temp directory so tests never interfere with each other or your real repos.

What's Tested

SuiteTestsWhat it covers
git init6Repo creation, .git directory, bare repos, re-init safety
git config6Set/get/unset values, list config, boolean types
git staging8add, status --porcelain, rm --cached, .gitignore, bulk staging
git commit8Commit, amend, --allow-empty, multi-line messages, author, history order
git branch10Create, list, checkout, rename, delete, divergent branches, -b shorthand
git log & diff9log formats, -n limit, diff/diff --cached, cross-branch diffs, show
git merge4Fast-forward, three-way merge, conflict detection, merge --abort
git errors7Non-repo dir, invalid subcommand, empty commit, unmerged branch delete, bad paths
Total58

Tech Stack

  • Node.js 18+
  • TypeScript 5
  • Jest 29 with ts-jest
  • child_process.spawn (zero runtime dependencies)

Project Structure

cli-testing-framework/
├── package.json
├── tsconfig.json
├── jest.config.js
├── src/
│ ├── cli-runner.ts # Generic CLI runner + git wrapper
│ ├── helpers/
│ │ └── git-test-helper.ts # Temp repo factory with file helpers
│ └── tests/
│ ├── git-init.test.ts # Repository initialization
│ ├── git-config.test.ts # Configuration management
│ ├── git-staging.test.ts # Staging area (add, status, rm)
│ ├── git-commit.test.ts # Commits & history
│ ├── git-branch.test.ts # Branching & checkout
│ ├── git-log-diff.test.ts # Log formats & diffs
│ ├── git-merge.test.ts # Merging & conflicts
│ └── git-errors.test.ts # Error handling & edge cases
└── .gitignore

Setup

npm install

Run Tests

# Run all tests with verbose output
npm test# Run tests and generate HTML + JUnit reports
npm run test:report
# Watch mode for development
npm run test:watch
# With coverage report
npm run test:coverage

Test Reporting

Every test run automatically generates two reports in the ./reports/ directory:

ReportFileFormatBest for
HTML Reportreports/test-report.htmlInteractive HTMLHuman review — open in browser
JUnit XMLreports/junit-report.xmlJUnit XMLCI/CD pipelines (Jenkins, GitHub Actions, GitLab)
# Generate reports
npm run test:report
# Open the HTML report (macOS)
open reports/test-report.html

The HTML report includes:

  • Pass/fail status for every test with expandable details
  • Execution time per test and per suite
  • Error messages and stack traces for failures
  • Suite-level grouping (init, config, staging, commit, branch, log/diff, merge, errors)

The JUnit XML report integrates with:

  • GitHub Actionsdorny/test-reporter or mikepenz/action-junit-report
  • Jenkins — JUnit post-build action
  • GitLab CIjunit artifact type

Configuration

All settings live in src/config.ts and are driven by environment variables with sensible defaults — no config file is required out of the box.

Copy .env.example to .env to customise:

cp .env.example .env
VariableDefaultDescription
GIT_BINgitPath to the git binary
GIT_DEFAULT_BRANCHmainDefault branch name for test repos
GIT_TEST_AUTHOR_NAMETest UserCommit author name
GIT_TEST_AUTHOR_EMAILtest@example.comCommit author email
GIT_TEST_TMP_ROOTOS temp dirRoot directory for temp repos
GIT_TEST_KEEP_TMPfalseSet to true to preserve temp dirs for debugging
GIT_TEST_CMD_TIMEOUT10000Timeout (ms) for individual CLI commands

Architecture

CLI Runner (cli-runner.ts)

A thin wrapper around child_process.spawn that captures exit code, stdout, and stderr. Provides:

  • runCli(command, args, options) — run any CLI command
  • runGit(args, options) — convenience wrapper that injects GIT_CONFIG_NOSYSTEM=1 to isolate tests from the user's global git config

Test Helper (git-test-helper.ts)

Factory function createTestRepo() that:

  1. Creates a unique temp directory (/tmp/git-e2e-XXXXXX)
  2. Runs git init -b main with a test identity (Test User <test@example.com>)
  3. Returns a TestRepo object with helpers: createFile(), readFile(), fileExists(), git(), commitFile()
  4. Cleans up in afterEach() via cleanup()

Test Pattern

Every test follows the same structure:

describe('git <subcommand>',()=>{letrepo: TestRepo;afterEach(()=>repo?.cleanup());it('does something specific',async()=>{repo=awaitcreateTestRepo();// arrange: create files, make commitsawaitrepo.commitFile('data.txt','setup commit');// act: run the git command under testconstresult=awaitrepo.git('diff','--cached');// assert: exit code + outputexpect(result.exitCode).toBe(0);expect(result.stdout).toContain('+modified');});});

Example Test Output

 PASS src/tests/git-init.test.ts
git init
✓ initializes a new repository
✓ creates a .git directory
✓ fresh repo status reports no commits yet
✓ re-initializing an existing repo is safe
✓ init with --bare creates a bare repository
✓ creates the correct default branch
PASS src/tests/git-commit.test.ts
git commit
✓ creates a commit with a message
✓ commit appears in the log
✓ fails when nothing is staged
✓ --allow-empty creates a commit with no file changes
✓ records the correct author
✓ amend changes the last commit message
✓ supports multi-line commit messages
✓ multiple commits create sequential history
PASS src/tests/git-merge.test.ts
git merge
✓ fast-forward merge when main has no new commits
✓ three-way merge creates a merge commit
✓ detects a merge conflict
✓ merge --abort cancels a conflicted merge
Test Suites: 8 passed, 8 total
Tests: 58 passed, 58 total

CI/CD

# GitHub Actions example
- uses: actions/checkout@v4
- uses: actions/setup-node@v4with:
node-version: '20'
- run: npm ci
- run: npm test

License

MIT

About

A comprehensive CLI end-to-end testing framework that demonstrates real-world E2E testing of git - the most widely used CLI tool in software development. Built with TypeScript, Jest, and Node's built-in 'child_process' (zero runtime dependencies).

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages