Files
你的用户名 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

319 lines
7.7 KiB
JavaScript

// 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;