import request from 'supertest'; import app from '../../../services/api-gateway/src/app.js'; import { connectDatabase, closeDatabase, clearDatabase } from '../../helpers/database.js'; import { createCampaign, createTelegramUser, createTemplate } from '../../helpers/factories.js'; describe('Campaign Workflow E2E Tests', () => { let authToken; let userId; beforeAll(async () => { await connectDatabase(); // Register and login const registerResponse = await request(app) .post('/api/v1/auth/register') .send({ username: 'testuser', email: 'test@example.com', password: 'SecurePass123!', fullName: 'Test User' }); const loginResponse = await request(app) .post('/api/v1/auth/login') .send({ username: 'testuser', password: 'SecurePass123!' }); authToken = loginResponse.body.data.accessToken; userId = loginResponse.body.data.user.id; }); afterAll(async () => { await clearDatabase(); await closeDatabase(); }); describe('Complete Campaign Lifecycle', () => { let campaignId; let templateId; let segmentId; let telegramUsers = []; it('Step 1: Create message template', async () => { const templateData = createTemplate({ name: 'Welcome Message', category: 'onboarding', content: { en: 'Welcome {{firstName}}! Thanks for joining our community.', es: '¡Bienvenido {{firstName}}! Gracias por unirte a nuestra comunidad.' } }); const response = await request(app) .post('/api/v1/templates') .set('Authorization', `Bearer ${authToken}`) .send(templateData); expect(response.status).toBe(201); expect(response.body.success).toBe(true); templateId = response.body.data.template.id; }); it('Step 2: Import users', async () => { // Create users via API const usersData = [ createTelegramUser({ tags: ['new', 'premium'] }), createTelegramUser({ tags: ['new', 'free'] }), createTelegramUser({ tags: ['existing', 'premium'] }), createTelegramUser({ tags: ['new', 'premium'] }), createTelegramUser({ tags: ['new', 'free'] }) ]; for (const userData of usersData) { const response = await request(app) .post('/api/v1/users') .set('Authorization', `Bearer ${authToken}`) .send(userData); expect(response.status).toBe(201); telegramUsers.push(response.body.data.user); } expect(telegramUsers.length).toBe(5); }); it('Step 3: Create user segment', async () => { const segmentData = { name: 'New Premium Users', description: 'Users who are new and have premium subscription', criteria: [ { field: 'tags', operator: 'contains', value: 'new', logic: 'AND' }, { field: 'tags', operator: 'contains', value: 'premium', logic: 'AND' } ], isDynamic: true }; const response = await request(app) .post('/api/v1/segments') .set('Authorization', `Bearer ${authToken}`) .send(segmentData); expect(response.status).toBe(201); expect(response.body.success).toBe(true); segmentId = response.body.data.segment.id; // Verify segment users const segmentUsersResponse = await request(app) .get(`/api/v1/segments/${segmentId}/users`) .set('Authorization', `Bearer ${authToken}`); expect(segmentUsersResponse.status).toBe(200); expect(segmentUsersResponse.body.data.users.length).toBe(2); // Should match 2 users }); it('Step 4: Create campaign targeting segment', async () => { const campaignData = { name: 'Welcome Campaign for Premium Users', description: 'Onboarding campaign for new premium subscribers', type: 'message', content: { messageTemplateId: templateId }, targeting: { segments: [segmentId] }, settings: { rateLimit: { messagesPerSecond: 5, messagesPerUser: 1 } }, goals: { targetAudience: 2, conversionRate: 20, revenue: 1000 } }; const response = await request(app) .post('/api/v1/orchestrator/campaigns') .set('Authorization', `Bearer ${authToken}`) .send(campaignData); expect(response.status).toBe(201); expect(response.body.success).toBe(true); campaignId = response.body.data.campaign.id; }); it('Step 5: Test campaign execution', async () => { // First, test with a single user const testResponse = await request(app) .post(`/api/v1/orchestrator/campaigns/${campaignId}/execute`) .set('Authorization', `Bearer ${authToken}`) .send({ test: true, testUsers: [telegramUsers[0].telegramId] }); expect(testResponse.status).toBe(200); expect(testResponse.body.success).toBe(true); expect(testResponse.body.data.status).toBe('running'); }); it('Step 6: Activate and execute campaign', async () => { // Update campaign status to active const activateResponse = await request(app) .put(`/api/v1/orchestrator/campaigns/${campaignId}`) .set('Authorization', `Bearer ${authToken}`) .send({ status: 'active' }); expect(activateResponse.status).toBe(200); expect(activateResponse.body.data.campaign.status).toBe('active'); // Execute campaign const executeResponse = await request(app) .post(`/api/v1/orchestrator/campaigns/${campaignId}/execute`) .set('Authorization', `Bearer ${authToken}`) .send({ test: false }); expect(executeResponse.status).toBe(200); expect(executeResponse.body.success).toBe(true); expect(executeResponse.body.data).toHaveProperty('executionId'); }); it('Step 7: Monitor campaign execution', async () => { // Get execution history const executionsResponse = await request(app) .get(`/api/v1/orchestrator/campaigns/${campaignId}/executions`) .set('Authorization', `Bearer ${authToken}`); expect(executionsResponse.status).toBe(200); expect(executionsResponse.body.data.executions.length).toBeGreaterThan(0); const latestExecution = executionsResponse.body.data.executions[0]; expect(latestExecution).toHaveProperty('progress'); expect(latestExecution.progress.total).toBe(2); // Should target 2 users from segment }); it('Step 8: View campaign statistics', async () => { // Wait a bit for execution to complete await new Promise(resolve => setTimeout(resolve, 2000)); const statsResponse = await request(app) .get(`/api/v1/orchestrator/campaigns/${campaignId}/statistics`) .set('Authorization', `Bearer ${authToken}`); expect(statsResponse.status).toBe(200); expect(statsResponse.body.success).toBe(true); expect(statsResponse.body.data.statistics.overview).toHaveProperty('messagesSent'); expect(statsResponse.body.data.statistics.overview.messagesSent).toBeGreaterThan(0); }); it('Step 9: Create scheduled follow-up campaign', async () => { // Create follow-up campaign const followUpCampaign = { name: 'Premium User Engagement', description: 'Weekly engagement for premium users', type: 'message', content: { customMessage: 'Hi {{firstName}}, here are this week\'s premium features!' }, targeting: { segments: [segmentId] }, status: 'active' }; const campaignResponse = await request(app) .post('/api/v1/orchestrator/campaigns') .set('Authorization', `Bearer ${authToken}`) .send(followUpCampaign); const followUpId = campaignResponse.body.data.campaign.id; // Schedule it const scheduleData = { campaignId: followUpId, name: 'Weekly Premium Engagement', type: 'recurring', schedule: { startDateTime: new Date(Date.now() + 86400000).toISOString(), // Start tomorrow recurring: { pattern: 'weekly', frequency: { interval: 1, unit: 'week' }, daysOfWeek: [1], // Monday time: '10:00', timezone: 'America/New_York' } } }; const scheduleResponse = await request(app) .post('/api/v1/scheduler/scheduled-campaigns') .set('Authorization', `Bearer ${authToken}`) .send(scheduleData); expect(scheduleResponse.status).toBe(201); expect(scheduleResponse.body.success).toBe(true); expect(scheduleResponse.body.data.schedule.type).toBe('recurring'); }); it('Step 10: Setup webhook for campaign events', async () => { const webhookData = { name: 'Campaign Event Notifier', url: 'https://example.com/webhooks/campaigns', events: ['campaign.completed', 'campaign.failed', 'user.converted'], headers: { 'X-Webhook-Secret': 'test-secret-key' }, isActive: true }; const response = await request(app) .post('/api/v1/webhooks') .set('Authorization', `Bearer ${authToken}`) .send(webhookData); expect(response.status).toBe(201); expect(response.body.success).toBe(true); expect(response.body.data.webhook.events).toContain('campaign.completed'); }); }); describe('A/B Testing Workflow', () => { let campaignId; let abTestId; it('Should create campaign with A/B test', async () => { // Create base campaign const campaignData = createCampaign({ name: 'A/B Test Campaign', status: 'active' }); const campaignResponse = await request(app) .post('/api/v1/orchestrator/campaigns') .set('Authorization', `Bearer ${authToken}`) .send(campaignData); campaignId = campaignResponse.body.data.campaign.id; // Create A/B test const abTestData = { name: 'Subject Line Test', campaignId: campaignId, variants: [ { name: 'Control', weight: 50, content: { customMessage: '🎉 Special offer just for you!' } }, { name: 'Variant A', weight: 50, content: { customMessage: '💰 Save 50% today only!' } } ], metrics: ['open_rate', 'click_rate', 'conversion_rate'], sampleSize: 20 // 20% of audience }; const abTestResponse = await request(app) .post('/api/v1/ab-testing/experiments') .set('Authorization', `Bearer ${authToken}`) .send(abTestData); expect(abTestResponse.status).toBe(201); abTestId = abTestResponse.body.data.experiment.id; // Start A/B test const startResponse = await request(app) .post(`/api/v1/ab-testing/experiments/${abTestId}/start`) .set('Authorization', `Bearer ${authToken}`); expect(startResponse.status).toBe(200); expect(startResponse.body.success).toBe(true); }); it('Should analyze A/B test results', async () => { // Wait for some data await new Promise(resolve => setTimeout(resolve, 3000)); const resultsResponse = await request(app) .get(`/api/v1/ab-testing/experiments/${abTestId}/results`) .set('Authorization', `Bearer ${authToken}`); expect(resultsResponse.status).toBe(200); expect(resultsResponse.body.data.results).toHaveProperty('variants'); expect(resultsResponse.body.data.results).toHaveProperty('winner'); expect(resultsResponse.body.data.results).toHaveProperty('confidence'); }); }); });