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

566 lines
18 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 私信群发功能端到端测试
* 测试私信模板、发送记录、任务管理等功能
*/
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 });
}