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>
319 lines
7.7 KiB
JavaScript
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; |