DEV Community

Cover image for Stop Running Your Entire Test Suite on Every Commit ๐Ÿšซ๐Ÿงช
Alan Schio
Alan Schio

Posted on

Stop Running Your Entire Test Suite on Every Commit ๐Ÿšซ๐Ÿงช

We've all been there. You make a small fix in one file, commit your changes, and watch as your entire test suite runs for the next 5 minutes. Sound familiar?

What if I told you there's a way to run only the tests that are actually related to your changes? Enter test-staged.

The Problem

Running your complete test suite before every commit is:

  • โฐ Slow - Wasting precious development time
  • ๐Ÿ˜ค Frustrating - Breaking your flow state
  • ๐Ÿ”„ Redundant - Testing code you didn't even touch

Most developers either:

  1. Skip tests entirely (dangerous!)
  2. Wait through long test runs (frustrating!)
  3. Push and pray the CI catches issues (risky!)

There has to be a better way.

The Solution: test-staged

test-staged is like lint-staged, but for tests. It intelligently identifies which tests are related to your staged changes and runs only those.

How Smart Is It?

test-staged uses different strategies depending on your test runner:

  • Jest/Vitest: Uses native dependency graph analysis (--findRelatedTests / vitest related)
  • Mocha/Ava: Intelligently maps source files to test files (e.g., user.ts โ†’ user.test.ts, src/api/users.ts โ†’ src/api/__tests__/users.test.ts)

Getting Started in 30 Seconds

Installation is a breeze:

npm install -D test-staged
# or
pnpm add -D test-staged
# or
yarn add -D test-staged
# or
bun add -D test-staged
Enter fullscreen mode Exit fullscreen mode

And that's it. Seriously. It's zero-config by default.

Set Up as a Pre-Commit Hook

The magic happens when you combine it with Husky:

# Install husky
npm install -D husky
npx husky init

# Add test-staged to pre-commit
echo "npx test-staged" > .husky/pre-commit
Enter fullscreen mode Exit fullscreen mode

Now every commit will:

  1. โœ… Only run tests related to your changes
  2. โšก Complete in seconds instead of minutes
  3. ๐Ÿ›ก๏ธ Block commits if tests fail

Real-World Examples

Example 1: Single File Change

You're working on a user authentication feature:

# You modified:
git add src/auth/login.ts

# test-staged runs ONLY:
src/auth/__tests__/login.test.ts
src/integration/__tests__/auth-flow.test.ts  # (because it imports login.ts)

# NOT running:
src/payments/__tests__/*.test.ts  โŒ
src/dashboard/__tests__/*.test.ts  โŒ
(and 200+ other unrelated tests)  โŒ
Enter fullscreen mode Exit fullscreen mode

Result: Tests complete in 3 seconds instead of 2 minutes.

Example 2: Refactoring Utilities

You refactored a utility function:

# You modified:
git add src/utils/formatDate.ts

# test-staged automatically finds ALL tests that depend on it:
src/utils/__tests__/formatDate.test.ts
src/components/__tests__/DatePicker.test.ts
src/pages/__tests__/Dashboard.test.ts
Enter fullscreen mode Exit fullscreen mode

Smart enough to catch indirect dependencies, fast enough to keep you productive.

Example 3: Monorepo Support

Working in a monorepo? test-staged has you covered:

# You're in packages/ui
git add Button.tsx

# Only runs:
packages/ui/__tests__/Button.test.tsx

# Doesn't run tests from:
packages/api/  โŒ
packages/cli/  โŒ
Enter fullscreen mode Exit fullscreen mode

Why You'll Love It

๐ŸŽฏ Zero Configuration

It automatically detects:

  • Your package manager (npm, pnpm, yarn, bun)
  • Your test runner (Jest, Vitest, Mocha, Ava)
  • Your project structure (monorepo or single package)

โšก Lightning Fast

On a typical project with 500+ tests:

  • Before: 2-3 minutes per commit
  • After: 2-5 seconds per commit

That's a 36x speed improvement in real-world usage.

๐Ÿง  Actually Intelligent

For Jest and Vitest, it uses the native dependency graph:

// If you change userService.ts
// it finds tests that import it:
import { createUser } from './userService'
import { validateUser } from './userService'
Enter fullscreen mode Exit fullscreen mode

For Mocha and Ava, it uses pattern matching:

src/models/user.ts โ†’ src/models/user.test.ts
src/api/users.ts   โ†’ src/api/__tests__/users.test.ts
lib/parser.ts      โ†’ lib/parser.spec.ts
Enter fullscreen mode Exit fullscreen mode

๐Ÿ› ๏ธ Customizable When Needed

While it works out-of-the-box, you can customize it:

// package.json
{
  "test-staged": {
    "runner": "jest",
    "mode": "related",
    "testExtensions": [".test", ".spec", ".e2e"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Or create a .test-stagedrc.json:

{
  "runner": "vitest",
  "testExtensions": [".test", ".spec", "Test", "E2E"]
}
Enter fullscreen mode Exit fullscreen mode

Supported Test Runners

Runner Detection Method
Vitest โญ Native vitest related (dependency graph)
Jest โญ Native --findRelatedTests (dependency graph)
Mocha โœ… File pattern matching
Ava โœ… File pattern matching

More runners coming soon!

The Developer Experience

Here's what your workflow looks like:

# Make your changes
vim src/components/Button.tsx

# Stage them
git add src/components/Button.tsx

# Commit (test-staged runs automatically via pre-commit hook)
git commit -m "fix: button hover state"

# Output:
Running tests for staged files...
โœ“ src/components/__tests__/Button.test.tsx (2 tests) 0.8s

Tests passed! โœจ
[main abc1234] fix: button hover state
Enter fullscreen mode Exit fullscreen mode

No manual test commands. No waiting. No broken commits.

Common Questions

Q: What if I want to run all tests?

A: Just bypass the hook: git commit --no-verify or run your test suite manually.

Q: Does it work with CI?

A: Yes! Your CI should still run the full test suite. test-staged is for local development speed.

Q: What about integration/E2E tests?

A: test-staged will find them if they import your changed files. You can also customize which tests run.

Q: Can I use it without Git hooks?

A: Absolutely! Just run npx test-staged manually whenever you want.

Try It Today

Get started in less than a minute:

npm install -D test-staged husky
npx husky init
echo "npx test-staged" > .husky/pre-commit
Enter fullscreen mode Exit fullscreen mode

Then make a commit and watch the magic happen. โœจ

Links


The Bottom Line

If you're still running your entire test suite on every commit, you're wasting time. test-staged gives you:

  • โšก Faster commits (seconds instead of minutes)
  • ๐ŸŽฏ Better focus (test only what changed)
  • ๐Ÿ›ก๏ธ Safer code (tests actually run instead of being skipped)
  • ๐Ÿš€ Better DX (zero config, just works)

Give it a try and let me know what you think! Your future self will thank you. ๐Ÿ™Œ


Have you tried test-staged? What's your current pre-commit testing strategy? Share in the comments below! ๐Ÿ‘‡

Top comments (0)