metacoding
Version:
Guided Development Workflow for GitHub Copilot - Transform your coding experience with AI-guided standards, structured workflows, and quality practices
374 lines (290 loc) • 11.3 kB
Markdown
---
description: 'Node.js backend testing strategies and frameworks'
applyTo: 'test/**/*.{ts,js}'
---
# Node.js Backend Testing Guidelines
## Test Case Naming Conventions
### Test Case ID Format: `[AREA]-[TYPE]-[NUMBER]`
**Node.js/Backend Area Prefixes:**
- `API` - REST API endpoint tests
- `SRV` - Service layer tests
- `DB` - Database/ORM tests
- `AUTH` - Authentication/Authorization tests
- `UTIL` - Backend utility function tests
- `CONFIG` - Configuration management tests
- `MIDDLEWARE` - Express middleware tests
- `QUEUE` - Message queue/job processing tests
- `CACHE` - Caching layer tests
- `VALIDATION` - Input validation tests
**Type Suffixes:**
- `UNIT` - Unit tests (isolated component testing)
- `INT` - Integration tests (component interaction testing)
- `E2E` - End-to-end tests (full API workflow testing)
**Examples:**
- `API-UNIT-001` - First unit test for API endpoint
- `SRV-UNIT-001` - First unit test for Service layer
- `DB-INT-001` - First integration test for Database layer
- `AUTH-E2E-001` - First end-to-end authentication test
## Testing Strategy Overview
### Testing Pyramid for Node.js Backend
- **Unit Tests (70%):** Test individual functions and modules in isolation
- **Integration Tests (20%):** Test interactions between components
- **End-to-End Tests (10%):** Test complete user workflows through APIs
- **Contract Tests:** Verify API contracts and external service interactions
### Test Framework Selection
- **Primary Framework:** Jest for unit and integration testing
- **API Testing:** Supertest for HTTP endpoint testing
- **Database Testing:** Test containers or in-memory databases
- **Mocking:** Jest mocks for external dependencies
- **Load Testing:** Artillery or k6 for performance testing
## Unit Testing Best Practices
### Test Structure and Organization
- **Test File Naming:** Use `.test.ts` or `.spec.ts` suffix
- **Test Grouping:** Group related tests using `describe` blocks
- **Test Isolation:** Each test should be independent and idempotent
- **Test Data:** Use factories or builders for test data creation
- **Test Cleanup:** Clean up resources after each test
```typescript
// Example test structure
describe('UserService', () => {
let userService: UserService;
let mockRepository: jest.Mocked<UserRepository>;
beforeEach(() => {
mockRepository = createMockRepository();
userService = new UserService(mockRepository);
});
describe('createUser', () => {
it('should create a user with valid data', async () => {
// Arrange
const userData = UserFactory.build();
mockRepository.save.mockResolvedValue(userData);
// Act
const result = await userService.createUser(userData);
// Assert
expect(result).toEqual(userData);
expect(mockRepository.save).toHaveBeenCalledWith(userData);
});
it('should throw ValidationError for invalid email', async () => {
// Arrange
const invalidUserData = UserFactory.build({ email: 'invalid-email' });
// Act & Assert
await expect(userService.createUser(invalidUserData)).rejects.toThrow(
ValidationError
);
});
});
});
```
### Mocking Strategies
- **External Dependencies:** Mock all external services and databases
- **File System Operations:** Mock file system interactions
- **Time-Dependent Code:** Mock dates and timers
- **Environment Variables:** Mock configuration and environment
- **HTTP Requests:** Mock external API calls
```typescript
// Example mocking patterns
jest.mock('fs-extra');
jest.mock('../services/email-service');
const mockFs = fs as jest.Mocked<typeof fs>;
const mockEmailService = EmailService as jest.MockedClass<typeof EmailService>;
describe('FileProcessor', () => {
beforeEach(() => {
jest.clearAllMocks();
mockFs.readFile.mockResolvedValue('file content');
});
});
```
## Integration Testing
### Database Testing
- **Test Database:** Use separate test database or test containers
- **Transaction Rollback:** Rollback transactions after each test
- **Seed Data:** Create consistent test data sets
- **Migration Testing:** Test database migrations
- **Performance Testing:** Test query performance
```typescript
// Example database integration test
describe('UserRepository Integration', () => {
let repository: UserRepository;
let connection: Connection;
beforeAll(async () => {
connection = await createTestConnection();
repository = new UserRepository(connection);
});
afterAll(async () => {
await connection.close();
});
beforeEach(async () => {
await connection.synchronize(true); // Reset database
});
it('should save and retrieve user correctly', async () => {
// Arrange
const userData = UserFactory.build();
// Act
const savedUser = await repository.save(userData);
const retrievedUser = await repository.findById(savedUser.id);
// Assert
expect(retrievedUser).toEqual(savedUser);
});
});
```
### API Endpoint Testing
- **HTTP Testing:** Use Supertest for endpoint testing
- **Authentication Testing:** Test auth middleware and permissions
- **Validation Testing:** Test request validation and error responses
- **Response Format:** Verify response structure and data types
- **Status Code Testing:** Test all possible HTTP status codes
```typescript
// Example API endpoint test
describe('POST /api/v1/users', () => {
let app: Application;
beforeAll(() => {
app = createTestApp();
});
it('should create user with valid data', async () => {
// Arrange
const userData = UserFactory.build();
// Act
const response = await request(app)
.post('/api/v1/users')
.send(userData)
.expect(201);
// Assert
expect(response.body.success).toBe(true);
expect(response.body.data.email).toBe(userData.email);
});
it('should return 400 for invalid email', async () => {
// Arrange
const invalidData = UserFactory.build({ email: 'invalid' });
// Act
const response = await request(app)
.post('/api/v1/users')
.send(invalidData)
.expect(400);
// Assert
expect(response.body.success).toBe(false);
expect(response.body.error.code).toBe('VALIDATION_ERROR');
});
});
```
## End-to-End Testing
### Full Workflow Testing
- **User Scenarios:** Test complete user journeys
- **Multi-Service Testing:** Test interactions between services
- **Real Database:** Use real database for E2E tests
- **External Services:** Use real or staging external services
- **Browser Testing:** Test web interfaces if applicable
### Authentication and Authorization Testing
- **Login Flows:** Test complete authentication flows
- **Token Management:** Test token generation and validation
- **Permission Testing:** Test role-based access control
- **Session Management:** Test session creation and cleanup
- **Security Testing:** Test for common security vulnerabilities
## Performance Testing
### Load Testing Strategies
- **Baseline Performance:** Establish performance baselines
- **Stress Testing:** Test system limits and breaking points
- **Spike Testing:** Test sudden load increases
- **Volume Testing:** Test with large amounts of data
- **Endurance Testing:** Test sustained load over time
```javascript
// Example Artillery load test configuration
config:
target: 'http://localhost:3000'
phases:
- duration: 60
arrivalRate: 10
- duration: 120
arrivalRate: 50
- duration: 60
arrivalRate: 10
scenarios:
- name: 'User Creation Flow'
weight: 70
flow:
- post:
url: '/api/v1/users'
json:
email: '{{ $randomEmail() }}'
name: '{{ $randomString() }}'
- think: 1
- name: 'User Retrieval'
weight: 30
flow:
- get:
url: '/api/v1/users/{{ userId }}'
```
### Database Performance Testing
- **Query Performance:** Test slow query detection
- **Connection Pool Testing:** Test connection pool limits
- **Transaction Performance:** Test transaction overhead
- **Index Effectiveness:** Test query optimization
- **Data Volume Testing:** Test with production-like data volumes
## Test Data Management
### Test Factories and Builders
- **Data Factories:** Create consistent test data
- **Builder Pattern:** Flexible test data creation
- **Realistic Data:** Use realistic but not real user data
- **Data Relationships:** Handle related entity creation
- **Data Cleanup:** Ensure test data doesn't leak between tests
```typescript
// Example test factory
export class UserFactory {
static build(overrides: Partial<User> = {}): User {
return {
id: faker.string.uuid(),
email: faker.internet.email(),
name: faker.person.fullName(),
createdAt: new Date(),
updatedAt: new Date(),
...overrides,
};
}
static buildMany(count: number, overrides?: Partial<User>): User[] {
return Array.from({ length: count }, () => this.build(overrides));
}
}
```
### Database Seeding and Fixtures
- **Seed Scripts:** Create consistent database states
- **Fixture Management:** Manage test fixture lifecycle
- **Data Isolation:** Prevent test data interference
- **Cleanup Strategies:** Efficient test cleanup procedures
- **Snapshot Testing:** Use database snapshots for complex scenarios
## Security Testing
### Authentication Testing
- **Token Validation:** Test JWT token validation
- **Password Security:** Test password hashing and validation
- **Brute Force Protection:** Test rate limiting and account lockout
- **Session Security:** Test session hijacking prevention
- **Multi-Factor Authentication:** Test MFA implementation
### Authorization Testing
- **Role-Based Access:** Test different user roles and permissions
- **Resource Access:** Test access to protected resources
- **Privilege Escalation:** Test prevention of privilege escalation
- **Cross-Tenant Access:** Test multi-tenant isolation
- **API Security:** Test API authentication and authorization
### Vulnerability Testing
- **Input Validation:** Test for injection attacks
- **Cross-Site Scripting:** Test XSS prevention
- **Cross-Site Request Forgery:** Test CSRF protection
- **Dependency Scanning:** Test for vulnerable dependencies
- **Security Headers:** Test security header implementation
## Test Environment Management
### Environment Isolation
- **Test Containers:** Use Docker containers for isolation
- **Environment Variables:** Manage test-specific configuration
- **Service Mocking:** Mock external services appropriately
- **Database Isolation:** Separate test databases
- **Network Isolation:** Isolate test network traffic
### Continuous Integration Testing
- **Pipeline Integration:** Run tests in CI/CD pipelines
- **Parallel Testing:** Run tests in parallel for speed
- **Test Reporting:** Generate comprehensive test reports
- **Coverage Reporting:** Track and report test coverage
- **Failure Analysis:** Analyze and debug test failures
### Test Monitoring and Metrics
- **Test Performance:** Monitor test execution time
- **Flaky Test Detection:** Identify and fix unreliable tests
- **Coverage Trends:** Track test coverage over time
- **Test Maintenance:** Regularly review and update tests
- **Quality Gates:** Enforce quality standards through testing