test-standards-enforcer
Enforce testing best practices - AAA pattern, naming conventions, isolation, coverage thresholds. Blocks non-compliant tests. Use when writing or reviewing tests.
Works with
---
name: test-standards-enforcer
description: Enforce testing best practices - AAA pattern, naming conventions, isolation, coverage thresholds. Blocks non-compliant tests. Use when writing or reviewing tests.
license: MIT
---
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:**
```typescript
// 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:**
```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
```typescript
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
```python
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:
```typescript
// 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):**
```bash
npm test -- --coverage
npx vitest --coverage
```
**Python (pytest):**
```bash
pytest --cov=app --cov-report=json
```
## Parameterized Tests
Use parameterized tests for multiple similar cases:
### TypeScript
```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
```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)
```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 tests
- `e2e-testing` - End-to-end with Playwright
- `msw-mocking` - Network mocking
- `test-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 testsMore Testing skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
setup-pre-commit
mattpocock/skills
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
agent-browser
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

