Test
Review and generate tests following consistent principles.
Usage
/test # Review tests related to current context (default) /test --review # Explicit review mode /test --review --staged # Review staged test files /test --review --all # Review all tests (parallel agents) /test --generate <target> # Generate tests for file/module/feature /test --generate --staged # Generate tests for staged code changes
Testing Principles
Both review and generate modes follow these principles. Review checks conformance; generate applies them.
1. Test Behavior, Not Implementation
// BAD: Breaks on any refactor
expect(component.state.internalFlag).toBe(true);
expect(service._privateMethod).toHaveBeenCalled();
// GOOD: Test observable behavior
expect(screen.getByText('Welcome')).toBeVisible();
expect(result.status).toBe('success');
2. Mock Only External Boundaries
// BAD: Testing mocks, not real code
jest.mock('./database');
jest.mock('./auth');
jest.mock('./validator');
jest.mock('./logger');
// What's actually being tested?
// GOOD: Mock only external boundaries
jest.mock('./externalPaymentApi');
3. Meaningful Assertions
// BAD: Test always passes
test('user login', async () => {
await loginUser('test@example.com');
// No expect() - what are we testing?
});
// GOOD: Verify outcomes
test('user login', async () => {
const result = await loginUser('test@example.com');
expect(result.token).toBeDefined();
expect(result.user.email).toBe('test@example.com');
});
4. No Brittle Timing
// BAD: Flaky - depends on timing
await doAsyncThing();
await new Promise(r => setTimeout(r, 100));
expect(result).toBe('done');
// GOOD: Wait for actual condition
await waitFor(() => expect(result).toBe('done'));
5. Independent Tests
// BAD: Tests depend on execution order
let sharedState;
test('first', () => { sharedState = setup(); });
test('second', () => { expect(sharedState.value).toBe(1); }); // Fails if run alone
// GOOD: Each test sets up its own state
test('first', () => { const state = setup(); /* ... */ });
test('second', () => { const state = setup(); expect(state.value).toBe(1); });
6. Cover Edge Cases
- •Empty inputs
- •Null/undefined
- •Boundary values (0, -1, MAX_INT)
- •Error conditions
- •Concurrent access
- •Unicode/special characters
7. Focused Tests
// BAD: Tests too much, hard to debug failures
test('user flow', async () => {
// 50 lines testing signup, login, profile, settings, logout
});
// GOOD: One concern per test
test('signup creates user', ...);
test('login sets session', ...);
8. Named Constants Over Magic Values
// BAD: What is 42? Why 'abc123'?
expect(calculate(42)).toBe(84);
expect(validate('abc123')).toBe(true);
// GOOD: Named constants explain intent
const VALID_USER_ID = 'user_12345';
const DOUBLED_VALUE = INPUT * 2;
Review Mode (--review)
Default mode. Checks tests against the principles above.
Scope
| Flag | Scope | Method |
|---|---|---|
| (none) | Context-related tests | Find tests for recently discussed code |
--staged | Staged test files | git diff --cached --name-only -- '*test*' '*spec*' |
--all | All test files | Glob **/*test*.{ts,js,py,dart} etc. |
Workflow
- •Get file list based on scope
- •Review (directly if ≤5 files, parallel sub-agents if more)
- •Report findings by priority
Checklist
Principles:
- • Tests verify behavior, not implementation
- • Mocks limited to external boundaries
- • All tests have meaningful assertions
- • No brittle timing (setTimeout, sleep)
- • Tests are independent (no shared state)
- • Edge cases covered
- • Tests are focused (one concern each)
Flaky Patterns:
- • No unseeded
Math.random() - • No unmocked
new Date() - • No network calls to real services
- • No file system dependencies without cleanup
- • No environment variable assumptions
Completeness (for code being reviewed):
- • All public functions/methods have tests
- • All exported components have tests
- • Error paths are tested, not just happy paths
- • Edge cases identified in code have corresponding tests
Pattern Conformance (for --staged/new tests):
- • File naming matches project convention
- • Test organization matches existing tests (suite grouping and test naming conventions per framework — see Terminology Mapping)
- • Setup/teardown patterns match existing tests (per-test and per-suite setup per framework)
- • Mocking approach consistent with project (framework-specific mocking or dependency injection)
- • Assertion style matches (expect vs assert, matchers used)
Coverage Check
If a coverage script exists, run it to identify gaps:
# Check for coverage scripts grep -E "coverage|test:cov" package.json 2>/dev/null cat pyproject.toml 2>/dev/null | grep -A5 "pytest"
Common coverage commands:
- •
npm run test:coverageornpm run coverage - •
pytest --cov - •
go test -cover - •
flutter test --coverage
Report uncovered lines/branches for files in scope.
Output Format
## Test Review: {scope}
### Critical Issues
- {file}:{test} - {issue}
### Completeness Gaps
- {code_file}:{function} - no tests found
- {code_file}:{function} - missing test for error case
- {code_file}:{function} - missing test for edge case: {scenario}
### Coverage Report
(if coverage script available)
- Overall: {X}% statements, {Y}% branches
- Uncovered in scope:
- {file}:{lines} - {description}
### Pattern Violations (--staged)
- {test_file} - setup pattern differs from existing tests
- {test_file} - mocking approach inconsistent with {example_file}
### Test Smells
- {file}:{test} - {smell}
### Suggestions
- {improvement}
Generate Mode (--generate)
Create tests for code following the principles above.
Red-Green Verification (for bug fixes)
When generating tests for a bug fix, verify the test actually catches the bug:
- •Run the new test with the fix applied -- confirm PASS (green)
- •Temporarily revert the fix
- •Run the test again -- confirm FAIL (red)
- •Re-apply the fix
- •Run the test -- confirm PASS again (green)
Only claim the test is valid if it fails without the fix and passes with it. This prevents tests that pass for unrelated reasons.
Scope
| Flag | Scope | Method |
|---|---|---|
<target> | Specific file/function/module | Read the code, generate tests |
--staged | Staged code changes | Generate tests for what changed |
Workflow
- •Detect framework - Jest, pytest, go test, vitest, etc. from project
- •Analyze existing test patterns - read 2-3 existing test files to learn:
- •File naming and location conventions
- •Describe/it structure and nesting style
- •Setup/teardown patterns (beforeEach, fixtures, factories)
- •Mocking approach (jest.mock, manual mocks, DI)
- •Assertion style and common matchers
- •Test data patterns (inline, fixtures, builders)
- •Read the code - understand what needs testing
- •Check existing tests - avoid duplicates, extend if needed
- •Generate tests following both principles AND project patterns
Framework Detection
Check for:
- •
jest.config.*,package.jsonwith jest → Jest - •
vitest.config.*→ Vitest - •
pytest.ini,pyproject.tomlwith pytest → pytest - •
*_test.gofiles → Go testing - •
*_test.dartfiles → Flutter test - •
.rspec,Gemfilewith rspec → RSpec - •
Cargo.tomlwith[dev-dependencies]→ Rust#[test] - •
*.test.tsxor*.spec.tsxwith@testing-library/reactin package.json → React Testing Library - •
phpunit.xml→ PHPUnit
Framework Terminology Mapping
When reviewing or generating tests, translate concepts to the detected framework:
| Concept | Jest/Vitest | pytest | Go testing | Flutter test |
|---|---|---|---|---|
| Test suite grouping | describe() | class or module | func Test... prefix | group() |
| Individual test | it() / test() | def test_...() | func Test...(t *testing.T) | test() / testWidgets() |
| Setup (per-test) | beforeEach() | setup_method / fixture | t.Cleanup() or helper | setUp() |
| Setup (per-suite) | beforeAll() | setUpClass / session fixture | TestMain() | setUpAll() |
| Mocking | jest.mock() | unittest.mock.patch | interface + stub struct | mockito package |
| Assertion | expect(x).toBe(y) | assert x == y | if got != want { t.Errorf() } | expect(x, equals(y)) |
| Async test | async/await | @pytest.mark.asyncio | t.Run with goroutines | async test + pump() |
| Skip test | it.skip() | @pytest.mark.skip | t.Skip() | skip() |
Use this table to adapt all examples and checklists below. Code examples in this skill use JavaScript/Jest syntax as a reference; translate idioms to the detected framework.
Test File Placement
Follow project conventions:
- •
__tests__/directory (common in JS/TS) - •
*.test.tsor*.spec.tsalongside source - •
test/directory at project root - •
*_test.pyalongside source or intests/
What to Generate
The templates below use Jest syntax for illustration. Adapt structure and syntax to the detected framework using the Terminology Mapping table above. For example, in pytest use
def test_returns_expected_result():instead ofit('returns expected result', ...).
For a function:
describe('{functionName}', () => {
it('returns expected result for valid input', () => {
// Happy path
});
it('handles empty input', () => {
// Edge case
});
it('throws on invalid input', () => {
// Error handling
});
it('handles boundary value', () => {
// Edge case: 0, MAX, etc.
});
});
For a component:
describe('{ComponentName}', () => {
it('renders with required props', () => {
// Happy path
});
it('responds to user interaction', () => {
// User events
});
it('displays error state', () => {
// Error handling
});
it('handles loading state', () => {
// Async states
});
});
For a service/API:
describe('{ServiceName}', () => {
it('returns data on success', () => {
// Happy path
});
it('handles errors gracefully', () => {
// Error handling
});
it('validates input', () => {
// Input validation
});
});
For staged changes:
- •Identify what changed (new function, modified behavior, etc.)
- •Find or create relevant test file
- •Generate tests for the changes
- •Ensure edge cases are covered
Output
Generate test files directly, matching project patterns:
- •Place in location matching existing test file structure
- •Use same describe/it nesting style as other tests
- •Match setup/teardown patterns (beforeEach, fixtures, etc.)
- •Use same mocking approach as existing tests
- •Match assertion style and matchers
- •Use consistent test data patterns (inline, fixtures, builders)
- •Add brief comments for non-obvious test cases
Before generating, show the patterns found:
## Detected Test Patterns **Location:** `__tests__/` alongside source **Structure:** `describe` per class/module, `it` per behavior **Setup:** `beforeEach` with factory functions **Mocking:** jest.mock for external, DI for internal **Assertions:** jest matchers, testing-library queries Generating tests following these patterns...
Examples
Generate tests for a payment function:
/test --generate lib/services/payment.ts
Detects the project's test framework and patterns, then generates a test file covering happy path (successful charge), error handling (declined card, network failure), and edge cases (zero amount, currency mismatch). Places the file following existing test conventions.
Review staged tests catches over-mocking:
/test --review --staged
Reviews staged test files against the testing principles. Flags tests that mock internal modules instead of only external boundaries, and identifies tests with no meaningful assertions that would pass regardless of behavior.
Troubleshooting
Generated tests fail immediately on first run
Solution: Verify the correct test framework was detected by checking the "Detected Test Patterns" output. If imports or setup are wrong, point --generate at an existing passing test file so the generator can match its patterns exactly.
Cannot detect the project's test framework
Solution: Ensure a framework config file exists (jest.config.*, vitest.config.*, pytest.ini, or pyproject.toml with pytest section). If the project uses a non-standard setup, run /test --generate <target> and specify the framework in your prompt.
Notes
- •Default is review mode with context-based scope
- •Both modes use the same principles - review checks, generate applies
- •Use
--stagedbefore commits to catch issues or generate missing tests - •Use
--allperiodically for comprehensive review - •Sub-agents parallelize large reviews/generations
- •Integration tests > unit tests with heavy mocking