7.6 KiB
7.6 KiB
Testing Guide
Comprehensive testing strategy for MotoVaultPro Modified Feature Capsule architecture.
Testing Philosophy
Each feature capsule contains complete, isolated test suites with no cross-feature dependencies.
Test Structure
Per Feature Organization
backend/src/features/[name]/tests/
├── fixtures/ # Test data
├── unit/ # Isolated unit tests
│ ├── [name].service.test.ts
│ └── [external].client.test.ts
└── integration/ # Full API tests
└── [name].integration.test.ts
Docker Testing Workflow
Backend Testing
# Enter backend container shell
make shell-backend
# Inside container:
# Test all features
npm test
# Test single feature (complete isolation)
npm test -- features/vehicles
# Test specific test type
npm test -- features/vehicles/tests/unit
npm test -- features/vehicles/tests/integration
# Test with coverage
npm test -- features/vehicles --coverage
# Watch mode
npm run test:watch
Frontend Testing
# From project root, run tests in frontend container
docker compose exec mvp-frontend npm test
# Watch mode
docker compose exec mvp-frontend npm run test:watch
# With coverage
docker compose exec mvp-frontend npm test -- --coverage
Test Environment Setup
- Container-Based: All tests run inside Docker containers
- Database: Uses the development database in the stack (
motovaultpro) - Mock External APIs: No real API calls during testing (where implemented)
- Cleanup: Prefer transactions/cleanup per test; see feature tests for patterns
Test Types
Unit Tests
Location: features/[name]/tests/unit/
Purpose: Test business logic in isolation
Mocking: All external dependencies mocked
Example: vehicles.service.test.ts
- Tests VIN validation logic
- Tests vehicle creation with mocked vPIC responses
- Tests caching behavior with mocked Redis
- Tests error handling paths
Integration Tests
Location: features/[name]/tests/integration/
Purpose: Test complete API workflows
Database: Real test database with transactions
Example: vehicles.integration.test.ts
- Tests complete POST /api/vehicles workflow
- Tests authentication middleware
- Tests database persistence
- Tests error responses
Test Fixtures
Location: features/[name]/tests/fixtures/
Purpose: Reusable test data
Format: JSON files with valid test objects
Example: vehicles.fixtures.json
{
"validVehicle": {
"vin": "1HGBH41JXMN109186",
"nickname": "Test Honda",
"color": "Blue"
},
"vpicResponse": {
"Make": "Honda",
"Model": "Civic",
"ModelYear": "2021"
}
}
Testing Commands Reference
Development Testing
# Enter backend container
make shell-backend
# Run all tests
npm test
# Run specific feature
npm test -- features/vehicles
npm test -- features/fuel-logs
npm test -- features/maintenance
npm test -- features/stations
# Run with file watching
npm run test:watch
# Run single test file
npm test -- vehicles.service.test.ts
# Run tests matching pattern
npm test -- --testNamePattern="VIN validation"
# Frontend tests (Jest)
docker compose exec mvp-frontend npm test
Coverage Reports
# Generate coverage for specific feature
npm test -- features/vehicles --coverage
# View coverage report
# Inside the container, open using your OS tooling,
# or copy the report out of the container as needed
Container Management
# Restart containers with fresh database
make rebuild
# View test logs
make logs-backend
# Clean all test data
make clean && make start
Test Configuration
Jest Configuration
- Backend:
backend/jest.config.js - Frontend:
frontend/jest.config.ts- React + TypeScript via
ts-jest - jsdom environment
- Testing Library setup in
frontend/setupTests.ts
- React + TypeScript via
Database Testing
- DB: Same as development (
motovaultpro) within Docker - Transactions: Recommended pattern is one transaction per test
- Isolation: Keep tests independent; avoid shared state
- Seeding: Use feature-level fixtures when needed
Coverage and Availability
- Full test suite exists for
vehicles. - Other features (e.g.,
fuel-logs,stations,maintenance) have placeholders and are being built out.
Mock Strategy
- External APIs: Completely mocked (vPIC, Google Maps)
- Database: Real database with transactions
- Redis: Mocked for unit tests, real for integration
- Auth: Mocked JWT tokens for protected endpoints
Test Data Management
Fixtures Strategy
// In test files
import fixtures from '../fixtures/vehicles.fixtures.json';
describe('Vehicle Service', () => {
it('should create vehicle', async () => {
const result = await vehicleService.create(
fixtures.validVehicle,
'user123'
);
expect(result.make).toBe('Honda');
});
});
Database Seeding
beforeEach(async () => {
// Clean slate for each test
await db.query('TRUNCATE TABLE vehicles CASCADE');
// Insert test-specific data
await db.query('INSERT INTO vehicles ...', testData);
});
Debugging Tests
Debug Single Test
# Run specific test with debugging
npm test -- --testNamePattern="should create vehicle" --verbose
# Debug integration test
npm test -- features/vehicles/tests/integration --detectOpenHandles
Common Issues
Container Connection Issues
# Check container health
make logs-backend
# Restart with fresh state
make rebuild
Database Connection Issues
# Check postgres container
docker compose logs postgres
# Reset database
make clean && make start
Test Timeout Issues
# Increase timeout in jest config
# Or debug hanging connections
npm test -- --detectOpenHandles
Continuous Integration
Pre-commit Testing
All tests must pass before commits:
# Backend: Enter shell and run tests
make shell-backend
npm run lint
npm test
# Frontend: Run tests from project root
docker compose exec mvp-frontend npm run lint
docker compose exec mvp-frontend npm test
Feature Development Workflow
- Write tests first: TDD approach preferred
- Run tests continuously: Use
npm run test:watch - Test in containers: Always verify with
docker compose exec mvp-backend npm test - Check coverage: Ensure new code is covered
- Integration last: Run full test suite before PR
Test Performance
Parallel Execution
- Jest runs tests in parallel by default
- Feature isolation allows true parallel testing
- No shared state between feature tests
Test Speed Optimization
- Unit tests: Fast (< 1 second per test)
- Integration tests: Medium (< 5 seconds per test)
- Full suite: Target < 30 seconds total
Database Optimization
- Use transactions for rollback (faster than truncate)
- Minimal fixture data
- Avoid complex joins in test setup
Error Testing Strategy
Expected Error Cases
describe('Error Handling', () => {
it('should handle invalid VIN', async () => {
await expect(
vehicleService.create({ vin: 'INVALID' }, 'user123')
).rejects.toThrow('Invalid VIN format');
});
it('should handle vPIC API failure', async () => {
mockVpicClient.decode.mockRejectedValue(new Error('API down'));
const result = await vehicleService.create(validVehicle, 'user123');
expect(result.make).toBeNull(); // Graceful degradation
});
});
External Service Failures
- Mock API failures to test error handling
- Test timeout scenarios
- Test network connectivity issues
- Verify graceful degradation paths