Testing

Regression Test Generator

Diffs two git refs, identifies behavior-affecting changes, and generates targeted test cases that cover exactly what changed.

SKILL.md

SKILL.md
---
description: Generate regression tests for changes between two git refs
allowed-tools: Bash(git *), Read, Write, Glob, Grep
---

# Regression Test Generator

Analyze the diff between two git refs and generate targeted test cases that specifically cover the changed behavior. Unlike general test generation, this focuses exclusively on what changed — catching regressions without redundant coverage.

## Arguments

- `$1` — the "before" git ref (default: `HEAD~1`)
- `$2` — the "after" git ref (default: `HEAD`)

If `$ARGUMENTS` is provided as a single value, treat it as `$1` and default `$2` to HEAD. If two values are provided separated by space, use the first as `$1` and second as `$2`.

## Steps

1. **Get the diff.** Run:
   ```
   git diff ${1:-HEAD~1}..${2:-HEAD} --name-only
   ```
   to list changed files. Then run:
   ```
   git diff ${1:-HEAD~1}..${2:-HEAD}
   ```
   to get the full diff.

2. **Filter to testable changes.** Ignore changes to:
   - Configuration files (`*.config.*`, `.*rc`)
   - Documentation (`*.md`, `*.txt`)
   - Test files themselves (we are *generating* tests, not testing tests)
   - Lock files, generated files, build output

3. **Analyze each changed file.** For each file with meaningful changes, read the full "after" version and identify:
   - **New functions/methods** — need tests for the new behavior
   - **Modified function signatures** — new parameters, changed return types
   - **Changed conditionals** — new branches, modified conditions
   - **Changed error handling** — new throw/catch, modified error messages
   - **Changed data transformations** — different mapping, filtering, or reduction logic

4. **Identify the project's test framework.** Look for:
   - `jest.config.*` or `"jest"` in package.json → Jest
   - `vitest.config.*` → Vitest
   - `mocha` in dependencies → Mocha + Chai
   - `.pytest.ini` or `conftest.py` → pytest
   - Read an existing test file to confirm patterns.

5. **Generate regression tests.** For each changed behavior:
   - Write a test that **would have passed before the change** and now tests the **new expected behavior**
   - Name tests descriptively: `it('returns 404 when user is soft-deleted', ...)` not `it('handles deleted users', ...)`
   - For modified functions, test both the new behavior AND that unchanged behavior still works (contract preservation)
   - For new conditional branches, test both the true and false paths
   - Mock external dependencies consistently with existing test patterns

6. **Place test files.** Write tests adjacent to their source files following the project's convention. If a test file already exists for the changed module, create a new describe block within it rather than a separate file.

7. **Verify tests compile.** Run the project's type checker or linter on the new test files to ensure they are syntactically valid.

## Output

After generating the tests, provide a summary:
- Number of changed functions covered
- Number of new test cases generated
- Any changed behavior that could NOT be automatically tested (and why)

## Rules

- Do not generate tests for unchanged code — focus exclusively on the delta.
- Each test should fail if the change is reverted (this is the definition of a regression test).
- Prefer testing behavior over implementation: test what a function returns, not how it computes it.
- If a change is purely a refactor with no behavior change, note that no regression tests are needed and explain why.

How It Works

Traditional test generators analyze code and produce tests for everything. This skill takes a fundamentally different approach: it analyzes the *delta* between two versions and generates tests for exactly what changed. This is closer to how experienced developers think about testing — "I changed this behavior, so I need a test that would catch it if someone accidentally reverted it."

The filtering step is critical for practical value. Changes to config files, documentation, and lock files do not need regression tests. By focusing only on behavior-affecting code changes, the skill avoids generating noise tests that inflate coverage numbers without actually catching regressions.

The instruction that each test "should fail if the change is reverted" is the acid test for regression tests. This framing ensures the generated tests are not just generic assertions but are genuinely tied to the specific change. Combined with the contract preservation tests (verifying unchanged behavior still works), the output provides a safety net for both intentional and unintentional behavioral changes.