test-standards-enforcer
Installation
SKILL.md
Contains Hooks
This skill uses Claude hooks which can execute code automatically in response to events. Review carefully before installing.
Enforce 2026 testing best practices with BLOCKING validation.
Validation Rules
BLOCKING Rules (exit 1)
| Rule | Check | Example Violation |
|---|---|---|
| Test Location | Tests must be in tests/ or __tests__/ |
src/utils/helper.test.ts |
| AAA Pattern | Tests must have Arrange/Act/Assert structure | No clear sections |
| Descriptive Names | Test names must describe behavior | test('test1') |
| No Shared State | Tests must not share mutable state | let globalVar = [] without reset |
| Coverage Threshold | Coverage must be ≥ 80% | 75% coverage |
File Location Rules
ALLOWED:
tests/unit/user.test.ts
tests/integration/api.test.ts
__tests__/components/Button.test.tsx
app/tests/test_users.py
tests/conftest.py
BLOCKED:
src/utils/helper.test.ts # Tests in src/
components/Button.test.tsx # Tests outside test dir
app/routers/test_routes.py # Tests mixed with source
Naming Conventions
TypeScript/JavaScript:
// GOOD - Descriptive, behavior-focused
test('should return empty array when no items exist', () => {})
test('throws ValidationError when email is invalid', () => {})
it('renders loading spinner while fetching', () => {})
// BLOCKED - Too short, not descriptive
test('test1', () => {})
test('works', () => {})
it('test', () => {})
Python:
# GOOD - snake_case, descriptive
def test_should_return_user_when_id_exists():
def test_raises_not_found_when_user_missing():
# BLOCKED - Not descriptive, wrong case
def testUser(): # camelCase
def test_1(): # Not descriptive
AAA Pattern (Required)
Every test must follow Arrange-Act-Assert:
TypeScript Example
describe('calculateDiscount', () => {
test('should apply 10% discount for orders over $100', () => {
// Arrange
const order = createOrder({ total: 150 });
const calculator = new DiscountCalculator();
// Act
const discount = calculator.calculate(order);
// Assert
expect(discount).toBe(15);
});
});
Python Example
class TestCalculateDiscount:
def test_applies_10_percent_discount_over_threshold(self):
# Arrange
order = Order(total=150)
calculator = DiscountCalculator()
# Act
discount = calculator.calculate(order)
# Assert
assert discount == 15
Test Isolation (Required)
Tests must not share mutable state:
// BLOCKED - Shared mutable state
let items = [];
test('adds item', () => {
items.push('a');
expect(items).toHaveLength(1);
});
test('removes item', () => {
// FAILS - items already has 'a' from previous test
expect(items).toHaveLength(0);
});
// GOOD - Reset state in beforeEach
describe('ItemList', () => {
let items: string[];
beforeEach(() => {
items = []; // Fresh state each test
});
test('adds item', () => {
items.push('a');
expect(items).toHaveLength(1);
});
test('starts empty', () => {
expect(items).toHaveLength(0); // Works!
});
});
Coverage Requirements
| Area | Minimum | Target |
|---|---|---|
| Overall | 80% | 90% |
| Business Logic | 90% | 100% |
| Critical Paths | 95% | 100% |
| New Code | 100% | 100% |
Running Coverage
TypeScript (Vitest/Jest):
npm test -- --coverage
npx vitest --coverage
Python (pytest):
pytest --cov=app --cov-report=json
Parameterized Tests
Use parameterized tests for multiple similar cases:
TypeScript
describe('isValidEmail', () => {
test.each([
['user@example.com', true],
['invalid', false],
['@missing.com', false],
['user@domain.co.uk', true],
['user+tag@example.com', true],
])('isValidEmail(%s) returns %s', (email, expected) => {
expect(isValidEmail(email)).toBe(expected);
});
});
Python
import pytest
class TestIsValidEmail:
@pytest.mark.parametrize("email,expected", [
("user@example.com", True),
("invalid", False),
("@missing.com", False),
("user@domain.co.uk", True),
])
def test_email_validation(self, email: str, expected: bool):
assert is_valid_email(email) == expected
Fixture Best Practices (Python)
import pytest
# Function scope (default) - Fresh each test
@pytest.fixture
def db_session():
session = create_session()
yield session
session.rollback()
# Module scope - Shared across file
@pytest.fixture(scope="module")
def expensive_model():
return load_ml_model() # Only loads once per file
# Session scope - Shared across all tests
@pytest.fixture(scope="session")
def db_engine():
engine = create_engine(TEST_DB_URL)
yield engine
engine.dispose()
Common Violations
1. Test in Wrong Location
BLOCKED: Test file must be in tests/ directory
File: src/utils/helpers.test.ts
Move to: tests/utils/helpers.test.ts
2. Missing AAA Structure
BLOCKED: Test pattern violations detected
- Tests should follow AAA pattern (Arrange/Act/Assert)
- Add comments or clear separation between sections
3. Shared Mutable State
BLOCKED: Test pattern violations detected
- Shared mutable state detected. Use beforeEach to reset state.
4. Coverage Below Threshold
BLOCKED: Coverage 75.2% is below threshold 80%
Actions required:
1. Add tests for uncovered code
2. Run: npm test -- --coverage
3. Ensure coverage >= 80% before proceeding
Related Skills
integration-testing- Component interaction testse2e-testing- End-to-end with Playwrightmsw-mocking- Network mockingtest-data-management- Fixtures and factories
Capability Details
aaa-pattern
Keywords: AAA, arrange act assert, test structure, test pattern Solves:
- Enforce Arrange-Act-Assert pattern
- Ensure clear test structure
- Improve test readability
test-naming
Keywords: test name, test naming, descriptive test, test description Solves:
- Enforce descriptive test names
- Block generic test names like test1
- Improve test documentation
test-location
Keywords: test location, test directory, tests folder, where tests Solves:
- Validate test file placement
- Block tests mixed with source
- Enforce test directory structure
coverage-threshold
Keywords: coverage, test coverage, code coverage, 80%, threshold Solves:
- Enforce minimum 80% coverage
- Block merges with low coverage
- Maintain quality standards
test-isolation
Keywords: test isolation, shared state, independent tests, flaky Solves:
- Detect shared mutable state
- Ensure test independence
- Prevent flaky tests
Weekly Installs
13
Repository
yonatangross/orchestkitGitHub Stars
150
First Seen
Jan 22, 2026
Security Audits
Installed on
claude-code11
gemini-cli8
opencode8
antigravity8
codex7
windsurf7