Files
telegram-management-system/marketing-agent/tests/e2e/campaigns/campaignWorkflow.test.js
你的用户名 237c7802e5
Some checks failed
Deploy / deploy (push) Has been cancelled
Initial commit: Telegram Management System
Full-stack web application for Telegram management
- Frontend: Vue 3 + Vben Admin
- Backend: NestJS
- Features: User management, group broadcast, statistics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 15:37:50 +08:00

372 lines
12 KiB
JavaScript

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');
});
});
});