Test File Structure Standards
Beginner
Enforce consistent Jest test file organization — AAA pattern, describe grouping, naming conventions, and file placement mirroring the source directory structure.
File Patterns
**/*.test.ts**/*.test.tsx**/*.spec.ts**/*.spec.tsx**/__tests__/**
This rule applies to files matching the patterns above.
Rule Content
rule-content.md
# Test File Structure Standards
## Rule
All Jest test files MUST follow a consistent structure: AAA pattern within tests, logical describe grouping, and file placement that mirrors source code.
## File Placement
```
src/
├── services/
│ ├── userService.ts
│ └── __tests__/
│ └── userService.test.ts
├── utils/
│ ├── formatDate.ts
│ └── __tests__/
│ └── formatDate.test.ts
```
Alternative (co-located):
```
src/
├── services/
│ ├── userService.ts
│ └── userService.test.ts
```
## Test Structure
### Good
```typescript
describe('UserService', () => {
describe('createUser', () => {
it('should create user with valid data', async () => {
// Arrange
const userData = { name: 'Alice', email: 'alice@test.com' };
// Act
const user = await userService.createUser(userData);
// Assert
expect(user.name).toBe('Alice');
expect(user.id).toBeDefined();
});
it('should throw on duplicate email', async () => {
// Arrange
await userService.createUser({ name: 'Alice', email: 'dup@test.com' });
// Act & Assert
await expect(
userService.createUser({ name: 'Bob', email: 'dup@test.com' })
).rejects.toThrow('Email already exists');
});
});
describe('deleteUser', () => {
it('should remove user by ID', async () => { /* ... */ });
it('should throw on non-existent ID', async () => { /* ... */ });
});
});
```
### Bad
```typescript
// No describe grouping, vague names, mixed concerns
test('test 1', () => { /* ... */ });
test('it works', () => { /* ... */ });
test('user stuff', () => { /* ... */ });
```
## Naming Conventions
- Test files: `{module}.test.ts` or `{module}.spec.ts` (pick one, be consistent)
- Describe blocks: class/module name → method name
- Test names: "should {expected behavior} when {condition}"
## Setup and Teardown
```typescript
describe('UserService', () => {
let service: UserService;
beforeEach(() => {
service = new UserService(mockDb);
jest.clearAllMocks();
});
afterEach(async () => {
await cleanupTestData();
});
// tests...
});
```
## Anti-Patterns
- Tests without assertions (exercise code without verifying)
- Nesting describe blocks more than 3 levels deep
- Shared mutable state between tests without cleanup
- Test names that describe implementation, not behaviorFAQ
Discussion
Loading comments...