Initial commit: Telegram Management System
Some checks failed
Deploy / deploy (push) Has been cancelled
Some checks failed
Deploy / deploy (push) Has been cancelled
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>
This commit is contained in:
319
marketing-agent/test/integration/helpers.js
Normal file
319
marketing-agent/test/integration/helpers.js
Normal file
@@ -0,0 +1,319 @@
|
||||
// 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;
|
||||
Reference in New Issue
Block a user