There is no built-in /generate-tests (or /test-gen) command in Claude Code, and custom slash commands do not accept CLI-style flags such as --unit, --jest, or --threshold=90. This page describes how to build generate-tests yourself as a custom slash command — a small Markdown prompt recipe you save in your project — following the official Claude Code slash commands / skills documentation.
A custom command is just a Markdown file. The command name comes from the filename: a file at .claude/commands/generate-tests.md creates /generate-tests. (Custom commands have been merged into skills; a skill at .claude/skills/generate-tests/SKILL.md produces the same /generate-tests and is the newer, recommended form, but existing .claude/commands/*.md files keep working identically.)
Where the file lives
| Scope |
Location |
Available in |
| Project (shared via git) |
.claude/commands/generate-tests.md |
This repository |
| Personal (all your projects) |
~/.claude/commands/generate-tests.md |
Every project on your machine |
The command name is the filename without the .md extension. Subdirectories namespace the command (for example .claude/commands/test/unit.md is invoked as /test:unit).
Create the command
mkdir -p .claude/commands
Save this to .claude/commands/generate-tests.md:
---
description: Generate a test suite for the given file or function
argument-hint: [file-or-function]
---
Write a thorough automated test suite for $ARGUMENTS.
- Detect and match the project's existing test framework and conventions
(look for jest.config.*, vitest.config.*, pytest.ini, pyproject.toml,
go.mod, etc.). Do not introduce a new framework unless none exists.
- Cover the happy path, edge cases (empty/zero/boundary values), and
error handling.
- Place tests next to existing tests, following the current naming pattern.
- After writing, run the test command and fix any failures.
The $ARGUMENTS placeholder is replaced with whatever you type after the command name. The description and argument-hint frontmatter fields drive the autocomplete UI. These are the real frontmatter fields documented for custom commands/skills — there are no test-type or framework flags.
Invoke it
/generate-tests src/utils/discount.js
/generate-tests "the calculateDiscount function in pricing.ts"
Because the behavior is plain prompt text, you steer test type and framework by what you write in the recipe or in your arguments, not via flags. For example, you can keep one recipe and ask for a specific style at call time:
/generate-tests src/api/users.py — focus on integration tests with pytest fixtures
Or maintain several focused recipes (.claude/commands/test/unit.md, .claude/commands/test/integration.md, .claude/commands/test/edge-cases.md) and call /test:unit, /test:integration, etc.
Optional: pre-run context with dynamic injection
Custom commands support a documented preprocessing syntax. A line beginning with !`<command>` runs the shell command and inlines its output into the prompt before Claude reads it, and @path/to/file includes a file's contents. This lets the recipe hand Claude the source under test automatically:
---
description: Generate a test suite for the given file
argument-hint: [file]
allowed-tools: Bash(npm test:*), Bash(pytest:*)
---
Existing test layout:
!`ls -R tests __tests__ 2>/dev/null | head -40`
Source to test:
@$ARGUMENTS
Write a thorough test suite for the file above, matching existing conventions,
then run the tests.
allowed-tools grants the listed tools without a per-call permission prompt while the command is active; it does not restrict Claude's other tools. Shell-injection lines (!`...`) can be disabled org-wide with "disableSkillShellExecution": true in settings.
Example: what a generated suite looks like
Given a JavaScript function:
function calculateDiscount(price, discountPercentage, customerType) {
if (price <= 0) throw new Error("Price must be positive");
if (discountPercentage < 0 || discountPercentage > 100) {
throw new Error("Discount must be between 0 and 100");
}
const baseDiscount = price * (discountPercentage / 100);
const multiplier = customerType === "premium" ? 1.2 : 1;
return Math.min(baseDiscount * multiplier, price * 0.5);
}
/generate-tests src/pricing.js might produce a Jest suite:
describe("calculateDiscount", () => {
test("calculates a basic discount", () => {
expect(calculateDiscount(100, 10, "regular")).toBe(10);
});
test("applies the premium multiplier", () => {
expect(calculateDiscount(100, 10, "premium")).toBe(12);
});
test("caps the discount at 50% of price", () => {
expect(calculateDiscount(100, 60, "premium")).toBe(50);
});
test("throws on non-positive price", () => {
expect(() => calculateDiscount(-10, 10, "regular")).toThrow(
"Price must be positive",
);
});
test("throws on out-of-range discount", () => {
expect(() => calculateDiscount(100, 105, "regular")).toThrow(
"Discount must be between 0 and 100",
);
});
});
For Python projects the same recipe yields pytest tests using fixtures and @pytest.mark.parametrize. The framework is chosen by matching your project, not by a flag.
When to use it
Reach for a generate-tests recipe when you repeatedly ask Claude to scaffold tests and want a consistent, project-aware prompt one keystroke away. For one-off test generation you can just ask in chat — the custom command pays off when the instructions (framework detection, naming conventions, coverage expectations, run-and-fix loop) are stable enough to codify.
Notes
- This is a user-authored recipe, not an official command. There is no guaranteed coverage threshold, no
--mutation/--property-based switch, and no built-in report generation; you get whatever you ask the prompt to produce.
- Generated tests are a starting point. Review them and run the suite yourself before relying on them.