# 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 ### Primary Test Command ```bash # Run all tests in containers make test ``` This executes: `docker compose exec backend npm test` ### Feature-Specific Testing ```bash # Test single feature (complete isolation) make shell-backend 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 ``` ### Test Environment Setup 1. **Container-Based**: All tests run inside Docker containers 2. **Database**: Uses the development database in the stack (`motovaultpro`) 3. **Mock External APIs**: No real API calls during testing (where implemented) 4. **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` ```json { "validVehicle": { "vin": "1HGBH41JXMN109186", "nickname": "Test Honda", "color": "Blue" }, "vpicResponse": { "Make": "Honda", "Model": "Civic", "ModelYear": "2021" } } ``` ## Testing Commands Reference ### Development Testing ```bash # 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" ``` ### Coverage Reports ```bash # Generate coverage for specific feature npm test -- features/vehicles --coverage # View coverage report open coverage/lcov-report/index.html ``` ### Container Management ```bash # Restart containers with fresh database make rebuild # View test logs make logs-backend # Clean all test data make clean && make dev ``` ## Test Configuration ### Jest Configuration **File**: `backend/jest.config.js` **Setup**: TypeScript support, test environment **Coverage**: Exclude node_modules, include src only ### 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 ```javascript // 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 ```javascript 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 ```bash # 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 ```bash # Check container health make logs-backend # Restart with fresh state make rebuild ``` #### Database Connection Issues ```bash # Check postgres container docker compose logs postgres # Reset database make clean && make dev ``` #### Test Timeout Issues ```bash # Increase timeout in jest config # Or debug hanging connections npm test -- --detectOpenHandles ``` ## Continuous Integration ### Pre-commit Testing All tests must pass before commits: ```bash # Run linting and tests npm run lint npm test # In Docker environment make test ``` ### Feature Development Workflow 1. **Write tests first**: TDD approach preferred 2. **Run tests continuously**: Use `npm run test:watch` 3. **Test in containers**: Always verify with `make test` 4. **Check coverage**: Ensure new code is covered 5. **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 ```javascript 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