Initial commit: Telegram Management System
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:
你的用户名
2025-11-04 15:37:50 +08:00
commit 237c7802e5
3674 changed files with 525172 additions and 0 deletions

View File

@@ -0,0 +1,565 @@
/**
* 私信群发功能端到端测试
* 测试私信模板、发送记录、任务管理等功能
*/
import { test, expect, Page } from '@playwright/test';
const TEST_CONFIG = {
baseURL: 'http://localhost:5173',
timeout: 30000,
adminUser: {
username: 'admin',
password: '111111',
},
};
// 测试消息模板数据
const TEST_TEMPLATE = {
name: '测试模板_' + Date.now(),
title: '测试消息标题',
content: '这是一条测试私信内容,用于验证系统功能。',
type: 'text',
category: 'marketing',
variables: '${username},${date}',
};
// 测试群发任务数据
const TEST_TASK = {
name: '测试群发任务_' + Date.now(),
targetType: 'all',
sendTime: 'immediate',
priority: 'normal',
};
test.describe('私信群发 - 消息模板管理', () => {
test.beforeEach(async ({ page }) => {
test.setTimeout(TEST_CONFIG.timeout);
await page.goto(TEST_CONFIG.baseURL);
await loginAsAdmin(page);
// 导航到消息模板页面
await page.click('[data-testid="menu-private-message"]');
await page.click('[data-testid="menu-message-template"]');
await page.waitForURL(/\/private-message\/template/);
});
test('应该正确显示消息模板页面', async ({ page }) => {
// 检查页面标题
await expect(page.locator('.page-title')).toContainText(
/消息模板|模板管理/,
);
// 检查搜索表单
await expect(page.locator('[data-testid="search-name"]')).toBeVisible();
await expect(page.locator('[data-testid="search-type"]')).toBeVisible();
await expect(page.locator('[data-testid="search-button"]')).toBeVisible();
// 检查操作按钮
await expect(
page.locator('[data-testid="add-template-button"]'),
).toBeVisible();
await expect(
page.locator('[data-testid="batch-delete-button"]'),
).toBeVisible();
// 检查模板列表
await expect(page.locator('.template-card, .ant-table')).toBeVisible();
});
test('应该能创建新的消息模板', async ({ page }) => {
// 点击添加模板按钮
await page.click('[data-testid="add-template-button"]');
// 等待弹窗出现
await expect(page.locator('.ant-modal')).toBeVisible();
await expect(page.locator('.ant-modal-title')).toContainText(
/添加模板|新建模板/,
);
// 填写模板信息
await page.fill('[data-testid="form-name"]', TEST_TEMPLATE.name);
await page.fill('[data-testid="form-title"]', TEST_TEMPLATE.title);
await page.fill('[data-testid="form-content"]', TEST_TEMPLATE.content);
await page.selectOption('[data-testid="form-type"]', TEST_TEMPLATE.type);
await page.selectOption(
'[data-testid="form-category"]',
TEST_TEMPLATE.category,
);
await page.fill('[data-testid="form-variables"]', TEST_TEMPLATE.variables);
// 提交表单
await page.click('[data-testid="form-submit"]');
// 等待成功消息
await expect(page.locator('.ant-message-success')).toBeVisible();
await expect(page.locator('.ant-message-success')).toContainText(
/创建成功|添加成功/,
);
// 验证模板是否出现在列表中
await page.fill('[data-testid="search-name"]', TEST_TEMPLATE.name);
await page.click('[data-testid="search-button"]');
await page.waitForTimeout(1000);
const templateCard = page
.locator('.template-card, .ant-table-tbody tr')
.filter({ hasText: TEST_TEMPLATE.name });
await expect(templateCard).toBeVisible();
});
test('消息模板预览功能应该正常工作', async ({ page }) => {
// 搜索刚创建的模板
await page.fill('[data-testid="search-name"]', TEST_TEMPLATE.name);
await page.click('[data-testid="search-button"]');
await page.waitForTimeout(1000);
// 点击预览按钮
const previewButton = page
.locator('.template-card, .ant-table-tbody tr')
.filter({ hasText: TEST_TEMPLATE.name })
.locator('[data-testid="preview-button"]');
await previewButton.click();
// 等待预览弹窗出现
await expect(page.locator('.ant-modal')).toBeVisible();
await expect(page.locator('.ant-modal-title')).toContainText(
/模板预览|消息预览/,
);
// 检查预览内容
await expect(page.locator('[data-testid="preview-title"]')).toContainText(
TEST_TEMPLATE.title,
);
await expect(page.locator('[data-testid="preview-content"]')).toContainText(
TEST_TEMPLATE.content,
);
// 关闭预览
await page.click('.ant-modal-close');
});
test('应该能编辑消息模板', async ({ page }) => {
// 搜索模板
await page.fill('[data-testid="search-name"]', TEST_TEMPLATE.name);
await page.click('[data-testid="search-button"]');
await page.waitForTimeout(1000);
// 点击编辑按钮
const editButton = page
.locator('.template-card, .ant-table-tbody tr')
.filter({ hasText: TEST_TEMPLATE.name })
.locator('[data-testid="edit-button"]');
await editButton.click();
// 等待编辑弹窗
await expect(page.locator('.ant-modal')).toBeVisible();
await expect(page.locator('.ant-modal-title')).toContainText(
/编辑模板|修改模板/,
);
// 修改内容
const newContent = '已修改的测试私信内容';
await page.fill('[data-testid="form-content"]', newContent);
// 提交修改
await page.click('[data-testid="form-submit"]');
// 等待成功消息
await expect(page.locator('.ant-message-success')).toBeVisible();
});
test('变量替换功能应该正常工作', async ({ page }) => {
// 搜索模板
await page.fill('[data-testid="search-name"]', TEST_TEMPLATE.name);
await page.click('[data-testid="search-button"]');
await page.waitForTimeout(1000);
// 点击测试变量按钮
const testButton = page
.locator('.template-card, .ant-table-tbody tr')
.filter({ hasText: TEST_TEMPLATE.name })
.locator('[data-testid="test-variables-button"]');
await testButton.click();
// 等待测试弹窗
await expect(page.locator('.ant-modal')).toBeVisible();
await expect(page.locator('.ant-modal-title')).toContainText(
/变量测试|测试变量/,
);
// 输入测试数据
await page.fill('[data-testid="test-username"]', '张三');
await page.fill('[data-testid="test-date"]', '2024-01-01');
// 点击预览
await page.click('[data-testid="preview-with-variables"]');
// 检查变量是否被正确替换
await expect(page.locator('[data-testid="preview-result"]')).toContainText(
'张三',
);
await expect(page.locator('[data-testid="preview-result"]')).toContainText(
'2024-01-01',
);
});
});
test.describe('私信群发 - 群发任务管理', () => {
test.beforeEach(async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
await loginAsAdmin(page);
// 导航到群发任务页面
await page.click('[data-testid="menu-private-message"]');
await page.click('[data-testid="menu-send-task"]');
await page.waitForURL(/\/private-message\/task/);
});
test('应该正确显示群发任务页面', async ({ page }) => {
// 检查页面标题
await expect(page.locator('.page-title')).toContainText(
/群发任务|发送任务/,
);
// 检查创建任务按钮
await expect(
page.locator('[data-testid="create-task-button"]'),
).toBeVisible();
// 检查任务列表
await expect(page.locator('.task-list, .ant-table')).toBeVisible();
// 检查筛选器
await expect(page.locator('[data-testid="filter-status"]')).toBeVisible();
await expect(page.locator('[data-testid="filter-priority"]')).toBeVisible();
});
test('应该能创建新的群发任务', async ({ page }) => {
// 点击创建任务按钮
await page.click('[data-testid="create-task-button"]');
// 等待任务创建页面加载
await page.waitForURL(/\/private-message\/task\/create/);
// 第一步:基本信息
await page.fill('[data-testid="task-name"]', TEST_TASK.name);
await page.selectOption(
'[data-testid="task-priority"]',
TEST_TASK.priority,
);
await page.click('[data-testid="next-step"]');
// 第二步:选择模板
await page.click('[data-testid="template-selector"]');
await page.click('.template-option:first-child');
await page.click('[data-testid="next-step"]');
// 第三步:选择目标用户
await page.click(`[data-testid="target-${TEST_TASK.targetType}"]`);
await page.click('[data-testid="next-step"]');
// 第四步:发送设置
await page.click(`[data-testid="send-${TEST_TASK.sendTime}"]`);
await page.click('[data-testid="next-step"]');
// 第五步:确认并创建
await expect(page.locator('.task-summary')).toBeVisible();
await page.click('[data-testid="create-task"]');
// 等待成功消息
await expect(page.locator('.ant-message-success')).toBeVisible();
await expect(page.locator('.ant-message-success')).toContainText(
/任务创建成功|创建成功/,
);
// 应该跳转回任务列表
await page.waitForURL(/\/private-message\/task$/);
});
test('任务状态管理应该正常工作', async ({ page }) => {
// 找到一个待发送的任务
const taskRow = page
.locator('.task-item, .ant-table-tbody tr')
.filter({ hasText: /待发送|pending/ })
.first();
if ((await taskRow.count()) > 0) {
// 点击开始发送按钮
await taskRow.locator('[data-testid="start-task"]').click();
// 确认操作
await page.click('[data-testid="confirm-start"]');
// 等待状态更新
await expect(page.locator('.ant-message-success')).toBeVisible();
// 检查任务状态是否变为发送中
await page.reload();
await expect(taskRow.locator('.task-status')).toContainText(
/发送中|sending/,
);
}
});
test('任务详情页面应该正常显示', async ({ page }) => {
// 点击第一个任务的详情按钮
const detailButton = page
.locator('.task-item, .ant-table-tbody tr')
.first()
.locator('[data-testid="view-detail"]');
await detailButton.click();
// 等待详情页面加载
await page.waitForURL(/\/private-message\/task\/\d+/);
// 检查任务基本信息
await expect(page.locator('.task-info')).toBeVisible();
await expect(page.locator('.task-progress')).toBeVisible();
// 检查发送记录表格
await expect(page.locator('.send-records .ant-table')).toBeVisible();
// 检查统计信息
await expect(page.locator('.task-statistics')).toBeVisible();
});
test('任务暂停和恢复功能应该正常工作', async ({ page }) => {
// 找到一个正在发送的任务
const sendingTask = page
.locator('.task-item, .ant-table-tbody tr')
.filter({ hasText: /发送中|sending/ })
.first();
if ((await sendingTask.count()) > 0) {
// 点击暂停按钮
await sendingTask.locator('[data-testid="pause-task"]').click();
// 确认暂停
await page.click('[data-testid="confirm-pause"]');
// 等待状态更新
await expect(page.locator('.ant-message-success')).toBeVisible();
// 检查状态是否变为已暂停
await page.reload();
await expect(sendingTask.locator('.task-status')).toContainText(
/已暂停|paused/,
);
// 测试恢复功能
await sendingTask.locator('[data-testid="resume-task"]').click();
await page.click('[data-testid="confirm-resume"]');
// 等待状态更新
await expect(page.locator('.ant-message-success')).toBeVisible();
}
});
});
test.describe('私信群发 - 发送记录和统计', () => {
test.beforeEach(async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
await loginAsAdmin(page);
// 导航到发送记录页面
await page.click('[data-testid="menu-private-message"]');
await page.click('[data-testid="menu-send-record"]');
await page.waitForURL(/\/private-message\/record/);
});
test('应该正确显示发送记录页面', async ({ page }) => {
// 检查页面标题
await expect(page.locator('.page-title')).toContainText(
/发送记录|消息记录/,
);
// 检查搜索表单
await expect(page.locator('[data-testid="search-keyword"]')).toBeVisible();
await expect(page.locator('[data-testid="search-status"]')).toBeVisible();
await expect(
page.locator('[data-testid="search-date-range"]'),
).toBeVisible();
// 检查记录列表
await expect(page.locator('.ant-table')).toBeVisible();
// 检查统计卡片
await expect(page.locator('.statistics-cards')).toBeVisible();
});
test('记录搜索和筛选应该正常工作', async ({ page }) => {
// 选择发送状态
await page.selectOption('[data-testid="search-status"]', 'success');
// 选择日期范围
await page.click('[data-testid="search-date-range"]');
await page.click('.ant-picker-today-btn'); // 今天
// 点击搜索
await page.click('[data-testid="search-button"]');
// 等待搜索结果
await page.waitForTimeout(1000);
// 检查搜索结果
const records = page.locator('.ant-table-tbody tr');
if ((await records.count()) > 0) {
// 验证搜索结果状态是否正确
const statusCells = records
.locator('td')
.filter({ hasText: /成功|success/ });
expect(await statusCells.count()).toBeGreaterThan(0);
}
});
test('记录详情查看应该正常工作', async ({ page }) => {
// 点击第一条记录的详情按钮
const firstRecord = page.locator('.ant-table-tbody tr').first();
const detailButton = firstRecord.locator('[data-testid="view-detail"]');
if ((await detailButton.count()) > 0) {
await detailButton.click();
// 等待详情弹窗
await expect(page.locator('.ant-modal')).toBeVisible();
await expect(page.locator('.ant-modal-title')).toContainText(
/消息详情|发送详情/,
);
// 检查详情内容
await expect(
page.locator('[data-testid="detail-recipient"]'),
).toBeVisible();
await expect(
page.locator('[data-testid="detail-content"]'),
).toBeVisible();
await expect(
page.locator('[data-testid="detail-send-time"]'),
).toBeVisible();
await expect(page.locator('[data-testid="detail-status"]')).toBeVisible();
}
});
test('记录导出功能应该正常工作', async ({ page }) => {
const downloadPromise = page.waitForEvent('download');
// 点击导出按钮
await page.click('[data-testid="export-records"]');
const download = await downloadPromise;
expect(download.suggestedFilename()).toMatch(/发送记录.*\.xlsx$/);
});
test('统计图表应该正常显示', async ({ page }) => {
// 导航到统计页面
await page.click('[data-testid="menu-private-message"]');
await page.click('[data-testid="menu-statistics"]');
await page.waitForURL(/\/private-message\/statistics/);
// 检查统计图表
await expect(page.locator('.statistics-chart')).toBeVisible();
await expect(page.locator('.echarts-container')).toBeVisible();
// 检查时间范围选择器
await expect(
page.locator('[data-testid="time-range-selector"]'),
).toBeVisible();
// 测试时间范围切换
await page.click('[data-testid="range-7days"]');
await page.waitForTimeout(1000);
// 图表应该重新加载
await expect(page.locator('.statistics-chart')).toBeVisible();
});
});
test.describe('私信群发 - 实时监控', () => {
test.beforeEach(async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
await loginAsAdmin(page);
// 导航到实时监控页面
await page.click('[data-testid="menu-private-message"]');
await page.click('[data-testid="menu-monitor"]');
await page.waitForURL(/\/private-message\/monitor/);
});
test('实时监控页面应该正常显示', async ({ page }) => {
// 检查页面标题
await expect(page.locator('.page-title')).toContainText(
/实时监控|发送监控/,
);
// 检查实时状态卡片
await expect(page.locator('.status-cards')).toBeVisible();
await expect(
page.locator('[data-testid="active-tasks-count"]'),
).toBeVisible();
await expect(page.locator('[data-testid="sending-rate"]')).toBeVisible();
await expect(page.locator('[data-testid="success-rate"]')).toBeVisible();
// 检查实时日志
await expect(page.locator('.realtime-logs')).toBeVisible();
// 检查性能图表
await expect(page.locator('.performance-chart')).toBeVisible();
});
test('实时数据更新应该正常工作', async ({ page }) => {
// 记录初始的发送数量
const initialCount = await page
.locator('[data-testid="sent-count"]')
.textContent();
// 等待数据更新假设有WebSocket连接
await page.waitForTimeout(5000);
// 检查数据是否可能发生变化(在有实际发送任务的情况下)
const currentCount = await page
.locator('[data-testid="sent-count"]')
.textContent();
// 至少UI应该是响应的
await expect(page.locator('[data-testid="sent-count"]')).toBeVisible();
});
test('日志查看和筛选应该正常工作', async ({ page }) => {
// 检查日志级别筛选
await page.selectOption('[data-testid="log-level-filter"]', 'error');
// 等待筛选结果
await page.waitForTimeout(1000);
// 检查日志内容
const logEntries = page.locator('.log-entry');
if ((await logEntries.count()) > 0) {
// 验证筛选结果
const errorLogs = logEntries.filter({ hasText: /错误|error/i });
expect(await errorLogs.count()).toBeGreaterThan(0);
}
// 测试清空日志功能
await page.click('[data-testid="clear-logs"]');
await page.click('[data-testid="confirm-clear"]');
// 日志应该被清空
await expect(page.locator('.log-entry')).toHaveCount(0);
});
});
// 辅助函数:管理员登录
async function loginAsAdmin(page: Page) {
await page.fill(
'[data-testid="username-input"]',
TEST_CONFIG.adminUser.username,
);
await page.fill(
'[data-testid="password-input"]',
TEST_CONFIG.adminUser.password,
);
await page.click('[data-testid="login-button"]');
await page.waitForURL(/\/dashboard/, { timeout: 10000 });
}