// Test Helpers const jwt = require('jsonwebtoken'); const axios = require('axios'); const { v4: uuidv4 } = require('uuid'); class TestHelpers { constructor(testEnv) { this.testEnv = testEnv; this.apiClient = null; } // Create authenticated API client async createAuthenticatedClient(baseURL, user) { const token = this.generateJWT(user); return axios.create({ baseURL, headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, validateStatus: () => true // Don't throw on any status }); } // Generate JWT token for testing generateJWT(user) { return jwt.sign( { userId: user.id, username: user.username, email: user.email }, process.env.JWT_SECRET || 'test-jwt-secret', { expiresIn: '1h' } ); } // Create test campaign async createTestCampaign(data = {}) { const defaultData = { campaignId: uuidv4(), name: `Test Campaign ${Date.now()}`, description: 'Test campaign for integration testing', targetAudience: { groups: ['test-group-1', 'test-group-2'], tags: ['test', 'automated'], filters: {} }, messages: [ { content: 'Test message content', type: 'text', delay: 0 } ], schedule: { startTime: new Date(), endTime: new Date(Date.now() + 86400000), // +1 day timezone: 'UTC' }, goals: { impressions: 1000, clicks: 100, conversions: 10 }, status: 'draft' }; const campaign = { ...defaultData, ...data }; // Save to MongoDB const Campaign = require('../../services/orchestrator/src/models/Campaign'); return await Campaign.create(campaign); } // Create test task async createTestTask(data = {}) { const defaultData = { taskId: uuidv4(), type: 'SEND_MESSAGE', payload: { message: 'Test message', chatId: 'test-chat-123', options: {} }, priority: 'medium', status: 'pending', retryCount: 0, maxRetries: 3 }; const task = { ...defaultData, ...data }; // Save to MongoDB const Task = require('../../services/orchestrator/src/models/Task'); return await Task.create(task); } // Wait for condition with timeout async waitForCondition(checkFn, timeout = 5000, interval = 100) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { if (await checkFn()) { return true; } await this.sleep(interval); } return false; } // Sleep helper sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Mock external services setupMocks() { // Mock Telegram System API const nock = require('nock'); const telegramMock = nock(process.env.TELEGRAM_SYSTEM_URL || 'http://localhost:8080') .persist() .post('/api/messages/send') .reply(200, { success: true, messageId: uuidv4(), timestamp: new Date().toISOString() }) .get('/api/accounts') .reply(200, { accounts: [ { id: 'test-account-1', phone: '+1234567890', status: 'active' } ] }) .get('/api/groups') .reply(200, { groups: [ { id: 'test-group-1', title: 'Test Group 1', members_count: 100 } ] }); // Mock Claude API const claudeMock = nock('https://api.anthropic.com') .persist() .post('/v1/messages') .reply(200, { id: 'msg_' + uuidv4(), type: 'message', content: [ { type: 'text', text: 'Mocked Claude response for testing' } ] }); // Mock OpenAI API const openaiMock = nock('https://api.openai.com') .persist() .post('/v1/moderations') .reply(200, { id: 'modr-' + uuidv4(), results: [ { flagged: false, categories: { hate: false, harassment: false, violence: false } } ] }); return { telegramMock, claudeMock, openaiMock }; } // Clean up mocks cleanupMocks() { const nock = require('nock'); nock.cleanAll(); } // Verify API response expectApiSuccess(response, statusCode = 200) { expect(response.status).toBe(statusCode); expect(response.data).toBeDefined(); if (response.data.error) { throw new Error(`API Error: ${response.data.error}`); } return response.data; } // Verify API error expectApiError(response, statusCode, errorMessage) { expect(response.status).toBe(statusCode); if (errorMessage) { expect(response.data.error).toContain(errorMessage); } return response.data; } // Create test webhook async createTestWebhook(url, events = ['message.sent', 'campaign.completed']) { return { id: uuidv4(), url, events, secret: 'test-webhook-secret', active: true, createdAt: new Date() }; } // Simulate webhook delivery async simulateWebhookDelivery(webhook, event, data) { const crypto = require('crypto'); const payload = { id: uuidv4(), event, data, timestamp: new Date().toISOString() }; const signature = crypto .createHmac('sha256', webhook.secret) .update(JSON.stringify(payload)) .digest('hex'); return axios.post(webhook.url, payload, { headers: { 'X-Webhook-Signature': signature, 'Content-Type': 'application/json' }, validateStatus: () => true }); } // Generate test data generateTestData(type, count = 10) { const data = []; for (let i = 0; i < count; i++) { switch (type) { case 'messages': data.push({ messageId: uuidv4(), content: `Test message ${i + 1}`, chatId: `chat-${i + 1}`, timestamp: new Date(Date.now() - i * 60000) // 1 min apart }); break; case 'events': data.push({ eventId: uuidv4(), type: ['message.sent', 'message.delivered', 'message.read'][i % 3], data: { messageId: uuidv4() }, timestamp: new Date() }); break; case 'metrics': data.push({ timestamp: new Date(Date.now() - i * 3600000), // 1 hour apart impressions: Math.floor(Math.random() * 1000), clicks: Math.floor(Math.random() * 100), conversions: Math.floor(Math.random() * 10) }); break; } } return data; } // Verify database state async verifyDatabaseState(expectations) { const results = {}; if (expectations.mongodb) { for (const [collection, query] of Object.entries(expectations.mongodb)) { const Model = require(`../../services/orchestrator/src/models/${collection}`); results[collection] = await Model.find(query); } } if (expectations.postgres) { for (const [table, query] of Object.entries(expectations.postgres)) { const result = await this.testEnv.pgPool.query( `SELECT * FROM ${table} WHERE ${query}` ); results[table] = result.rows; } } if (expectations.redis) { const redis = this.testEnv.getRedisClient(); for (const key of expectations.redis) { results[`redis:${key}`] = await redis.get(key); } } return results; } } module.exports = TestHelpers;