# Testing Documentation Comprehensive testing guide for the Telegram Marketing Agent System. ## Table of Contents - [Testing Strategy](#testing-strategy) - [Test Types](#test-types) - [Running Tests](#running-tests) - [Writing Tests](#writing-tests) - [CI/CD Integration](#cicd-integration) - [Coverage Goals](#coverage-goals) - [Best Practices](#best-practices) ## Testing Strategy Our testing strategy follows the Testing Pyramid approach: ``` /\ /E2E\ (5-10%) /------\ /Integration\ (20-30%) /------------\ / Unit Tests \ (60-70%) /-----------------\ ``` ### Test Categories 1. **Unit Tests**: Test individual functions, methods, and components in isolation 2. **Integration Tests**: Test interactions between components and services 3. **End-to-End Tests**: Test complete user workflows and scenarios ## Test Types ### Unit Tests Located in `tests/unit/`, these tests cover: - Service methods - Utility functions - Middleware logic - Model validations - Helper functions Example structure: ``` tests/unit/ ├── services/ │ ├── api-gateway/ │ │ ├── middleware/ │ │ │ ├── auth.test.js │ │ │ └── rateLimiter.test.js │ │ └── utils/ │ └── orchestrator/ │ └── campaignService.test.js └── utils/ ``` ### Integration Tests Located in `tests/integration/`, these tests cover: - API endpoint functionality - Database operations - Service interactions - External API mocking Example structure: ``` tests/integration/ ├── api/ │ ├── auth.test.js │ ├── campaigns.test.js │ └── users.test.js └── services/ ``` ### End-to-End Tests Located in `tests/e2e/`, these tests cover: - Complete user workflows - Multi-service interactions - Real-world scenarios Example structure: ``` tests/e2e/ ├── campaigns/ │ └── campaignWorkflow.test.js └── users/ └── userOnboarding.test.js ``` ## Running Tests ### Prerequisites ```bash # Install dependencies npm install # For each service cd services/ npm install ``` ### All Tests ```bash npm test ``` ### Unit Tests Only ```bash npm run test:unit ``` ### Integration Tests Only ```bash npm run test:integration ``` ### E2E Tests Only ```bash npm run test:e2e ``` ### Watch Mode (for development) ```bash npm run test:watch ``` ### Coverage Report ```bash npm run test:coverage ``` ### Specific Test File ```bash npx jest tests/unit/services/orchestrator/campaignService.test.js ``` ### Test Pattern ```bash npx jest --testNamePattern="should create campaign" ``` ## Writing Tests ### Unit Test Example ```javascript import { jest } from '@jest/globals'; import CampaignService from '../../../../services/orchestrator/src/services/campaignService.js'; import { createCampaign } from '../../../helpers/factories.js'; describe('CampaignService', () => { let campaignService; let mockDependency; beforeEach(() => { // Setup mocks mockDependency = { method: jest.fn() }; campaignService = new CampaignService(mockDependency); jest.clearAllMocks(); }); describe('createCampaign', () => { it('should create a new campaign', async () => { // Arrange const campaignData = createCampaign(); mockDependency.method.mockResolvedValue({ success: true }); // Act const result = await campaignService.createCampaign(campaignData); // Assert expect(result).toHaveProperty('id'); expect(mockDependency.method).toHaveBeenCalledWith(expect.any(Object)); }); it('should handle errors gracefully', async () => { // Arrange mockDependency.method.mockRejectedValue(new Error('Database error')); // Act & Assert await expect(campaignService.createCampaign({})) .rejects.toThrow('Database error'); }); }); }); ``` ### Integration Test Example ```javascript import request from 'supertest'; import app from '../../../services/api-gateway/src/app.js'; import { connectDatabase, closeDatabase, clearDatabase } from '../../helpers/database.js'; describe('Campaigns API', () => { let authToken; beforeAll(async () => { await connectDatabase(); authToken = await getAuthToken(); }); afterEach(async () => { await clearDatabase(); }); afterAll(async () => { await closeDatabase(); }); describe('POST /api/v1/campaigns', () => { it('should create campaign', async () => { const response = await request(app) .post('/api/v1/campaigns') .set('Authorization', `Bearer ${authToken}`) .send({ name: 'Test Campaign', type: 'message' }); expect(response.status).toBe(201); expect(response.body.success).toBe(true); expect(response.body.data.campaign).toHaveProperty('id'); }); }); }); ``` ### E2E Test Example ```javascript describe('Campaign Workflow', () => { it('should complete full campaign lifecycle', async () => { // 1. Create template const template = await createTemplate(); // 2. Import users const users = await importUsers(); // 3. Create segment const segment = await createSegment(); // 4. Create campaign const campaign = await createCampaign({ templateId: template.id, segmentId: segment.id }); // 5. Execute campaign const execution = await executeCampaign(campaign.id); // 6. Verify results expect(execution.status).toBe('completed'); expect(execution.messagesSent).toBe(users.length); }); }); ``` ## Test Helpers and Utilities ### Database Helpers ```javascript import { connectDatabase, closeDatabase, clearDatabase } from './helpers/database.js'; ``` ### Factory Functions ```javascript import { createUser, createCampaign, createTemplate } from './helpers/factories.js'; ``` ### Authentication Helpers ```javascript import { generateAuthToken, createAuthenticatedRequest } from './helpers/auth.js'; ``` ## CI/CD Integration Tests run automatically on: - Pull requests - Commits to main/develop branches - Before deployments ### GitHub Actions Workflow See `.github/workflows/test.yml` for the complete CI configuration. Key features: - Matrix testing (Node.js 18.x, 20.x) - Multiple database versions - Parallel test execution - Coverage reporting - Test result artifacts ### Pre-commit Hooks ```bash # Install husky npm prepare # Pre-commit hook runs: - Linting - Unit tests for changed files - Commit message validation ``` ## Coverage Goals ### Overall Coverage Targets - **Statements**: 80% - **Branches**: 70% - **Functions**: 70% - **Lines**: 80% ### Service-Specific Targets - **API Gateway**: 85% (critical path) - **Orchestrator**: 80% - **Analytics**: 75% - **User Management**: 80% - **Scheduler**: 75% ### Viewing Coverage ```bash # Generate HTML coverage report npm run test:coverage # Open in browser open coverage/lcov-report/index.html ``` ## Best Practices ### General Guidelines 1. **Test Naming**: Use descriptive test names that explain what is being tested ```javascript // Good it('should return 404 when campaign does not exist') // Bad it('test campaign') ``` 2. **Arrange-Act-Assert**: Structure tests clearly ```javascript it('should calculate discount correctly', () => { // Arrange const price = 100; const discountRate = 0.2; // Act const result = calculateDiscount(price, discountRate); // Assert expect(result).toBe(80); }); ``` 3. **Isolation**: Each test should be independent - Use `beforeEach` and `afterEach` for setup/cleanup - Don't rely on test execution order - Clear mocks between tests 4. **Mocking**: Mock external dependencies ```javascript jest.mock('axios'); axios.get.mockResolvedValue({ data: mockData }); ``` 5. **Async Testing**: Handle promises properly ```javascript // Good it('should handle async operation', async () => { await expect(asyncFunction()).resolves.toBe(expected); }); // Also good it('should handle async operation', () => { return expect(asyncFunction()).resolves.toBe(expected); }); ``` 6. **Error Testing**: Test error cases thoroughly ```javascript it('should throw error for invalid input', async () => { await expect(functionUnderTest(null)) .rejects.toThrow('Input cannot be null'); }); ``` ### Performance Considerations 1. **Use Test Databases**: MongoDB Memory Server for unit tests 2. **Parallel Execution**: Run independent tests in parallel 3. **Selective Testing**: Use `--watch` mode during development 4. **Mock Heavy Operations**: Mock file I/O, network calls ### Security Testing 1. **Authentication**: Test all auth scenarios 2. **Authorization**: Verify role-based access 3. **Input Validation**: Test with malicious inputs 4. **Rate Limiting**: Verify limits are enforced ## Troubleshooting ### Common Issues 1. **Timeout Errors** ```javascript // Increase timeout for specific test it('should handle long operation', async () => { // test code }, 10000); // 10 second timeout ``` 2. **Database Connection Issues** - Ensure MongoDB/Redis are running - Check connection strings in test environment - Clear test database between runs 3. **Flaky Tests** - Add proper waits for async operations - Mock time-dependent functions - Use stable test data 4. **Memory Leaks** - Close all connections in `afterAll` - Clear large data structures - Use `--detectLeaks` flag ## Additional Resources - [Jest Documentation](https://jestjs.io/docs/getting-started) - [Supertest Documentation](https://github.com/visionmedia/supertest) - [MongoDB Memory Server](https://github.com/nodkz/mongodb-memory-server) - [Testing Best Practices](https://github.com/goldbergyoni/javascript-testing-best-practices)