kindergarten_java/lesingle-edu-reading-platform-frontend/tests/e2e/teacher/helpers.ts

212 lines
6.3 KiB
TypeScript
Raw Normal View History

2026-03-17 10:38:51 +08:00
/**
* E2E -
*/
import { Page, expect } from '@playwright/test';
import { TEACHER_CONFIG } from './fixtures';
/**
* 使
*/
export async function loginAsTeacher(page: Page) {
await page.goto('/login');
// 点击教师角色按钮
await page.locator('.role-btn').filter({ hasText: '教师' }).first().click();
// 输入账号密码
await page.getByPlaceholder('请输入账号').fill(TEACHER_CONFIG.account);
await page.getByPlaceholder('请输入密码').fill(TEACHER_CONFIG.password);
// 点击登录按钮
await page.locator('.login-btn').click();
// 等待登录按钮消失(表示登录请求完成)
await page.locator('.login-btn').waitFor({ state: 'hidden', timeout: 10000 });
// 等待页面加载
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
// 等待 URL 包含 teacher使用正则表达式
await page.waitForURL(/teacher/, { timeout: 5000 }).catch(() => {});
}
/**
*
* @param page
* @param parentMenu
* @param childMenu
*/
export async function clickSubMenu(page: Page, parentMenu: string, childMenu: string) {
// 等待页面加载
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
await page.waitForTimeout(2000);
// 检查侧边栏是否折叠,如果折叠则展开
const isCollapsed = await page.locator('.ant-layout-sider-collapsed').count() > 0;
if (isCollapsed) {
const collapseButton = page.locator('.trigger').first();
await collapseButton.click();
await page.waitForTimeout(1000);
}
// 尝试直接点击菜单项(扁平菜单)
const directMenuItem = page.locator('[role="menuitem"]').filter({ hasText: childMenu }).first();
if (await directMenuItem.count() > 0) {
await directMenuItem.click();
await page.waitForTimeout(1500);
return;
}
// 点击一级菜单展开(父子菜单结构)
2026-03-17 10:38:51 +08:00
const parentMenuItem = page.locator('.ant-menu-submenu-title:has-text("' + parentMenu + '")').first();
await parentMenuItem.click();
// 等待二级菜单 DOM 出现
await page.waitForSelector('.ant-menu-submenu-open', { timeout: 5000 }).catch(() => {});
await page.waitForTimeout(500);
// 使用 evaluate 在浏览器上下文中点击,绕过可见性检查
await page.evaluate((menuText) => {
const items = Array.from(document.querySelectorAll('.ant-menu-item'));
const target = items.find(item => item.textContent?.includes(menuText));
if (target) {
(target as HTMLElement).click();
}
}, childMenu);
await page.waitForTimeout(1500);
}
/**
*
* @param page
* @param menuText
*/
export async function clickMenuItem(page: Page, menuText: string) {
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
await page.waitForTimeout(1000);
const menuItem = page.locator('[role="menuitem"]').filter({ hasText: menuText }).first();
await menuItem.click();
await page.waitForTimeout(1500);
}
2026-03-17 10:38:51 +08:00
/**
* 退
*/
export async function logout(page: Page) {
// 尝试多种方式找到退出登录按钮
// 方式 1查找退出登录按钮
const logoutBtn1 = page.getByText(/退出登录 | 退出|logout/i).first();
if (await logoutBtn1.count() > 0) {
try {
await logoutBtn1.click({ timeout: 3000 });
await page.waitForURL(/.*\/login.*/, { timeout: 10000 }).catch(() => {});
return;
} catch (e) {
// 如果点击失败,继续尝试其他方式
}
}
// 方式 2查找用户头像/菜单按钮并点击
const userMenuBtn = page.locator('.ant-dropdown-trigger, .user-menu, [class*="user"]').first();
if (await userMenuBtn.count() > 0) {
try {
await userMenuBtn.click({ timeout: 3000 });
await page.waitForTimeout(500);
const logoutInMenu = page.getByText(/退出登录 | 退出|logout/i).first();
if (await logoutInMenu.count() > 0) {
await logoutInMenu.click({ timeout: 3000 });
await page.waitForURL(/.*\/login.*/, { timeout: 10000 }).catch(() => {});
return;
}
} catch (e) {
// 如果点击失败,继续尝试其他方式
}
}
// 方式 3尝试清空 localStorage 和 sessionStorage 并跳转到登录页
await page.evaluate(() => {
localStorage.clear();
sessionStorage.clear();
});
await page.goto('/login');
await page.waitForURL(/.*\/login.*/, { timeout: 10000 });
}
/**
*
*/
export async function waitForTable(page: Page, timeout = 10000) {
await page.waitForSelector('table, .ant-table', { timeout });
}
/**
*
*/
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');
// 或者点击关闭按钮
const closeBtn = page.locator('.ant-modal-close');
if (await closeBtn.count() > 0) {
await closeBtn.click();
}
}
/**
*
*/
export async function waitForPageLoad(page: Page, timeout = 10000) {
await page.waitForLoadState('networkidle', { timeout });
}
/**
* API
*/
export async function waitForAPI(page: Page, urlPattern: string | RegExp, timeout = 10000) {
await page.waitForResponse(urlPattern, { timeout }).catch(() => {});
}