/** * 超管端 E2E 测试 - 通用工具函数 */ import { Page, expect } from '@playwright/test'; import { ADMIN_CONFIG } from './fixtures'; /** * 使用超管账号登录 */ export async function loginAsAdmin(page: Page) { console.log('🔍 开始登录流程...'); await page.goto('/login', { timeout: 30000, waitUntil: 'commit' }); await page.waitForTimeout(500); // 检查是否在登录页面 const currentUrl = page.url(); console.log('📍 当前 URL:', currentUrl); // 点击超管角色按钮 - 查找包含"超管"文本的元素 console.log('⏳ 点击超管角色按钮...'); await page.getByText('超管').first().click(); await page.waitForTimeout(300); // 输入账号密码 console.log('⏳ 输入账号密码...'); await page.getByPlaceholder('请输入账号').fill(ADMIN_CONFIG.account); await page.getByPlaceholder('请输入密码').fill(ADMIN_CONFIG.password); // 点击登录按钮 console.log('⏳ 点击登录按钮...'); await page.locator('button:has-text("登 录")').first().click(); // 等待登录 API 请求完成 console.log('⏳ 等待登录 API 响应...'); const loginResponse = await page.waitForResponse( response => response.url().includes('/api/v1/auth/login') && response.status() === 200, { timeout: 15000 } ).catch((err) => { console.log('登录请求等待超时:', err.message); return null; }); if (loginResponse) { const responseData = await loginResponse.json().catch(() => null); console.log('🔍 登录响应:', responseData ? '成功' : '失败'); } // 等待登录成功后的重定向 await page.waitForLoadState('networkidle', { timeout: 20000 }).catch(() => { console.log('⚠️ networkidle 等待超时'); }); // 验证是否已跳转到管理页面 const finalUrl = page.url(); console.log('📍 登录后 URL:', finalUrl); await page.waitForURL('**/admin/**', { timeout: 10000 }).catch(() => { console.log('⚠️ URL 等待超时,当前 URL:', page.url()); }); // 验证是否看到管理页面的特征元素 await page.locator('.ant-layout:has-text("课程管理")').first().waitFor({ state: 'visible', timeout: 10000 }).catch(() => { console.log('⚠️ 管理页面容器未找到,当前页面内容:', page.url()); }); await page.waitForTimeout(1000); console.log('✅ 登录流程完成'); } /** * 退出登录 */ export async function logout(page: Page) { // 点击右上角用户菜单 await page.getByRole('button', { name: /退出登录|退出|logout/i }).click(); await page.waitForURL('**/login*'); } /** * 等待表格加载完成 */ export async function waitForTable(page: Page, timeout = 30000) { // 使用 first() 避免严格模式 violation const table = page.locator('.ant-table').first(); // 等待表格附加到 DOM(允许空表状态) await table.waitFor({ state: 'attached', timeout }).catch(() => { console.log('表格等待超时,继续执行'); }); } /** * 等待弹窗显示 */ export async function waitForModal(page: Page, title?: string, timeout = 5000) { if (title) { await page.getByText(title).waitFor({ timeout }); } else { await page.waitForSelector('.ant-modal', { timeout }); } } /** * 等待成功提示 */ export async function waitForSuccess(page: Page, message?: string, timeout = 5000) { if (message) { await page.getByText(message).waitFor({ timeout }); } else { await page.waitForSelector('.ant-message-success', { timeout }); } } /** * 等待错误提示 */ export async function waitForError(page: Page, message?: string, timeout = 5000) { if (message) { await page.getByText(message).waitFor({ timeout }); } else { await page.waitForSelector('.ant-message-error', { timeout }); } } /** * 在表格中查找并点击操作按钮 */ export async function clickRowAction(page: Page, rowName: string, action: string) { const row = page.getByRole('row').filter({ hasText: rowName }); await row.getByRole('button', { name: action }).click(); } /** * 关闭弹窗 */ export async function closeModal(page: Page) { await page.keyboard.press('Escape'); // 或者点击关闭按钮 await page.locator('.ant-modal-close').click(); }