/** * 账号管理功能端到端测试 * 测试账号列表、创建、编辑、删除等功能 */ import { test, expect, Page } from '@playwright/test'; const TEST_CONFIG = { baseURL: 'http://localhost:5173', timeout: 30000, adminUser: { username: 'admin', password: '111111', }, }; // 测试账号数据 const TEST_ACCOUNT = { username: 'test_telegram_' + Date.now(), nickname: '测试账号', phone: '13800138000', email: 'test@example.com', status: 'active', remark: '这是一个测试账号', }; 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-account"]'); await page.click('[data-testid="menu-account-list"]'); await page.waitForURL(/\/account\/list/); }); test('应该正确显示账号列表页面', async ({ page }) => { // 检查页面标题 await expect(page.locator('.page-title')).toContainText( /账号列表|Telegram账号管理/, ); // 检查搜索表单 await expect(page.locator('[data-testid="search-username"]')).toBeVisible(); await expect(page.locator('[data-testid="search-status"]')).toBeVisible(); await expect(page.locator('[data-testid="search-button"]')).toBeVisible(); await expect(page.locator('[data-testid="reset-button"]')).toBeVisible(); // 检查操作按钮 await expect( page.locator('[data-testid="add-account-button"]'), ).toBeVisible(); await expect( page.locator('[data-testid="batch-delete-button"]'), ).toBeVisible(); await expect(page.locator('[data-testid="export-button"]')).toBeVisible(); // 检查表格 await expect(page.locator('.ant-table')).toBeVisible(); await expect(page.locator('.ant-table-thead')).toBeVisible(); }); test('搜索功能应该正常工作', async ({ page }) => { // 输入搜索条件 await page.fill('[data-testid="search-username"]', 'admin'); await page.selectOption('[data-testid="search-status"]', 'active'); // 点击搜索 await page.click('[data-testid="search-button"]'); // 等待搜索结果加载 await page.waitForTimeout(1000); // 检查是否显示了搜索结果 await expect(page.locator('.ant-table-tbody tr')).toHaveCount({ min: 1 }); // 检查搜索结果是否包含关键词 const firstRowUsername = await page .locator('.ant-table-tbody tr:first-child td:nth-child(2)') .textContent(); expect(firstRowUsername).toContain('admin'); // 测试重置功能 await page.click('[data-testid="reset-button"]'); await expect(page.locator('[data-testid="search-username"]')).toHaveValue( '', ); }); test('应该能创建新账号', async ({ page }) => { // 点击添加账号按钮 await page.click('[data-testid="add-account-button"]'); // 等待弹窗出现 await expect(page.locator('.ant-modal')).toBeVisible(); await expect(page.locator('.ant-modal-title')).toContainText( /添加账号|新增Telegram账号/, ); // 填写表单数据 await page.fill('[data-testid="form-username"]', TEST_ACCOUNT.username); await page.fill('[data-testid="form-nickname"]', TEST_ACCOUNT.nickname); await page.fill('[data-testid="form-phone"]', TEST_ACCOUNT.phone); await page.fill('[data-testid="form-email"]', TEST_ACCOUNT.email); await page.selectOption('[data-testid="form-status"]', TEST_ACCOUNT.status); await page.fill('[data-testid="form-remark"]', TEST_ACCOUNT.remark); // 提交表单 await page.click('[data-testid="form-submit"]'); // 等待成功消息 await expect(page.locator('.ant-message-success')).toBeVisible(); await expect(page.locator('.ant-message-success')).toContainText( /创建成功|添加成功/, ); // 弹窗应该关闭 await expect(page.locator('.ant-modal')).not.toBeVisible(); // 在列表中应该能找到新创建的账号 await page.fill('[data-testid="search-username"]', TEST_ACCOUNT.username); await page.click('[data-testid="search-button"]'); await page.waitForTimeout(1000); const foundAccount = page .locator('.ant-table-tbody tr') .filter({ hasText: TEST_ACCOUNT.username }); await expect(foundAccount).toBeVisible(); }); test('表单验证应该正常工作', async ({ page }) => { await page.click('[data-testid="add-account-button"]'); await expect(page.locator('.ant-modal')).toBeVisible(); // 不填写必填字段直接提交 await page.click('[data-testid="form-submit"]'); // 应该显示验证错误 await expect(page.locator('.ant-form-item-explain-error')).toContainText( /请输入用户名|用户名不能为空/, ); // 输入无效的邮箱格式 await page.fill('[data-testid="form-username"]', 'test_user'); await page.fill('[data-testid="form-email"]', 'invalid-email'); await page.click('[data-testid="form-submit"]'); // 应该显示邮箱格式错误 await expect(page.locator('.ant-form-item-explain-error')).toContainText( /邮箱格式不正确|请输入有效的邮箱地址/, ); // 关闭弹窗 await page.click('.ant-modal-close'); }); test('应该能编辑账号信息', async ({ page }) => { // 先搜索刚才创建的账号 await page.fill('[data-testid="search-username"]', TEST_ACCOUNT.username); await page.click('[data-testid="search-button"]'); await page.waitForTimeout(1000); // 点击编辑按钮 const editButton = page .locator('.ant-table-tbody tr') .filter({ hasText: TEST_ACCOUNT.username }) .locator('[data-testid="edit-button"]'); await editButton.click(); // 等待编辑弹窗出现 await expect(page.locator('.ant-modal')).toBeVisible(); await expect(page.locator('.ant-modal-title')).toContainText( /编辑账号|修改账号信息/, ); // 修改昵称 const newNickname = '已修改的测试账号'; await page.fill('[data-testid="form-nickname"]', newNickname); // 提交修改 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.reload(); await page.fill('[data-testid="search-username"]', TEST_ACCOUNT.username); await page.click('[data-testid="search-button"]'); await page.waitForTimeout(1000); const updatedRow = page .locator('.ant-table-tbody tr') .filter({ hasText: TEST_ACCOUNT.username }); await expect(updatedRow).toContainText(newNickname); }); test('应该能查看账号详情', async ({ page }) => { // 搜索账号 await page.fill('[data-testid="search-username"]', TEST_ACCOUNT.username); await page.click('[data-testid="search-button"]'); await page.waitForTimeout(1000); // 点击查看按钮 const viewButton = page .locator('.ant-table-tbody tr') .filter({ hasText: TEST_ACCOUNT.username }) .locator('[data-testid="view-button"]'); await viewButton.click(); // 等待详情弹窗出现 await expect(page.locator('.ant-modal')).toBeVisible(); await expect(page.locator('.ant-modal-title')).toContainText( /账号详情|查看账号信息/, ); // 检查详情信息是否正确显示 await expect(page.locator('[data-testid="detail-username"]')).toContainText( TEST_ACCOUNT.username, ); await expect(page.locator('[data-testid="detail-phone"]')).toContainText( TEST_ACCOUNT.phone, ); await expect(page.locator('[data-testid="detail-email"]')).toContainText( TEST_ACCOUNT.email, ); // 关闭详情弹窗 await page.click('.ant-modal-close'); }); test('账号状态切换应该正常工作', async ({ page }) => { // 搜索账号 await page.fill('[data-testid="search-username"]', TEST_ACCOUNT.username); await page.click('[data-testid="search-button"]'); await page.waitForTimeout(1000); const accountRow = page .locator('.ant-table-tbody tr') .filter({ hasText: TEST_ACCOUNT.username }); // 点击状态切换按钮 const statusSwitch = accountRow.locator('[data-testid="status-switch"]'); await statusSwitch.click(); // 确认状态变更 await page.click('[data-testid="confirm-status-change"]'); // 等待成功消息 await expect(page.locator('.ant-message-success')).toBeVisible(); await expect(page.locator('.ant-message-success')).toContainText( /状态更新成功|操作成功/, ); }); test('批量操作应该正常工作', async ({ page }) => { // 选择多个账号 const checkboxes = page.locator('.ant-table-tbody .ant-checkbox-input'); await checkboxes.first().check(); await checkboxes.nth(1).check(); // 批量删除按钮应该变为可用状态 await expect( page.locator('[data-testid="batch-delete-button"]'), ).not.toBeDisabled(); // 点击批量删除 await page.click('[data-testid="batch-delete-button"]'); // 确认删除操作 await expect(page.locator('.ant-modal-confirm')).toBeVisible(); await page.click('.ant-btn-primary'); // 等待操作完成 await expect(page.locator('.ant-message-success')).toBeVisible(); }); test('导出功能应该正常工作', async ({ page }) => { // 设置下载事件监听 const downloadPromise = page.waitForEvent('download'); // 点击导出按钮 await page.click('[data-testid="export-button"]'); // 等待下载开始 const download = await downloadPromise; // 验证下载文件名 expect(download.suggestedFilename()).toMatch(/账号列表.*\.xlsx$/); }); test('分页功能应该正常工作', async ({ page }) => { // 检查分页组件是否存在 await expect(page.locator('.ant-pagination')).toBeVisible(); // 如果有多页数据,测试分页切换 const nextButton = page.locator('.ant-pagination-next'); const isNextEnabled = await nextButton.isEnabled(); if (isNextEnabled) { // 点击下一页 await nextButton.click(); await page.waitForTimeout(1000); // 检查页码是否改变 await expect(page.locator('.ant-pagination-item-active')).toContainText( '2', ); // 点击上一页 await page.click('.ant-pagination-prev'); await page.waitForTimeout(1000); // 检查是否回到第一页 await expect(page.locator('.ant-pagination-item-active')).toContainText( '1', ); } }); test('表格排序功能应该正常工作', async ({ page }) => { // 点击用户名列的排序按钮 const usernameHeader = page .locator('.ant-table-thead th') .filter({ hasText: /用户名|Username/ }); await usernameHeader.locator('.ant-table-column-sorter').click(); // 等待排序完成 await page.waitForTimeout(1000); // 检查是否有排序指示器 await expect( usernameHeader.locator( '.ant-table-column-sorter-up.active, .ant-table-column-sorter-down.active', ), ).toBeVisible(); }); test('应该能删除账号', async ({ page }) => { // 搜索要删除的测试账号 await page.fill('[data-testid="search-username"]', TEST_ACCOUNT.username); await page.click('[data-testid="search-button"]'); await page.waitForTimeout(1000); // 点击删除按钮 const deleteButton = page .locator('.ant-table-tbody tr') .filter({ hasText: TEST_ACCOUNT.username }) .locator('[data-testid="delete-button"]'); await deleteButton.click(); // 确认删除 await expect(page.locator('.ant-modal-confirm')).toBeVisible(); await page.click('.ant-btn-primary'); // 等待删除成功消息 await expect(page.locator('.ant-message-success')).toBeVisible(); await expect(page.locator('.ant-message-success')).toContainText( /删除成功|操作成功/, ); // 验证账号已被删除 await page.reload(); await page.fill('[data-testid="search-username"]', TEST_ACCOUNT.username); await page.click('[data-testid="search-button"]'); await page.waitForTimeout(1000); await expect(page.locator('.ant-empty')).toBeVisible(); }); }); test.describe('账号导入功能测试', () => { test.beforeEach(async ({ page }) => { await page.goto(TEST_CONFIG.baseURL); await loginAsAdmin(page); // 导航到账号导入页面 await page.click('[data-testid="menu-account"]'); await page.click('[data-testid="menu-account-import"]'); await page.waitForURL(/\/account\/import/); }); test('应该正确显示导入页面', async ({ page }) => { // 检查页面标题 await expect(page.locator('.page-title')).toContainText( /账号导入|批量导入/, ); // 检查上传组件 await expect(page.locator('.ant-upload-dragger')).toBeVisible(); // 检查模板下载链接 await expect( page.locator('[data-testid="download-template"]'), ).toBeVisible(); // 检查导入记录表格 await expect(page.locator('.ant-table')).toBeVisible(); }); test('应该能下载导入模板', async ({ page }) => { const downloadPromise = page.waitForEvent('download'); // 点击下载模板 await page.click('[data-testid="download-template"]'); const download = await downloadPromise; expect(download.suggestedFilename()).toMatch(/账号导入模板.*\.xlsx$/); }); }); // 辅助函数:管理员登录 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 }); }