import { Page, Locator } from '@playwright/test'; import { BasePage } from './BasePage'; export class AdminLoginPage extends BasePage { readonly emailInput: Locator; readonly passwordInput: Locator; readonly loginButton: Locator; readonly errorMessage: Locator; constructor(page: Page) { super(page); this.emailInput = page.locator('#email, input[type="email"]'); this.passwordInput = page.locator('#password, input[type="password"]'); this.loginButton = page.getByRole('button', { name: /登录|login/i }); this.errorMessage = page.locator('[role="alert"], .text-red-700'); } async goto() { await this.navigate('/admin/login'); await this.page.waitForLoadState('domcontentloaded', { timeout: 30000 }); await this.page.waitForTimeout(1000); await this.emailInput.waitFor({ state: 'visible', timeout: 20000 }); } async login(email: string, password: string) { await this.emailInput.fill(email); await this.passwordInput.fill(password); await this.loginButton.click(); } async expectLoginSuccess() { await this.page.waitForURL(/\/admin(?!\/login)/); } async expectLoginError() { await this.errorMessage.waitFor({ state: 'visible' }); } } export class AdminDashboardPage extends BasePage { readonly sidebar: Locator; readonly navigationItems: Locator; readonly contentMenuItem: Locator; readonly settingsMenuItem: Locator; readonly usersMenuItem: Locator; readonly logsMenuItem: Locator; readonly logoutButton: Locator; constructor(page: Page) { super(page); this.sidebar = page.locator('aside, [role="navigation"]'); this.navigationItems = this.sidebar.locator('nav a, nav button'); this.contentMenuItem = this.sidebar.getByRole('link', { name: /内容管理/i }); this.settingsMenuItem = this.sidebar.getByRole('link', { name: /配置中心|设置/i }); this.usersMenuItem = this.sidebar.getByRole('link', { name: /用户管理/i }); this.logsMenuItem = this.sidebar.getByRole('link', { name: /审计日志|日志/i }); this.logoutButton = this.sidebar.getByRole('button', { name: /登出|退出|logout/i }); } async goto() { await this.navigate('/admin'); await this.waitForLoadState('networkidle'); } async navigateToContent() { await this.contentMenuItem.click(); await this.waitForLoadState('networkidle'); } async navigateToSettings() { await this.settingsMenuItem.click(); await this.waitForLoadState('networkidle'); } async navigateToUsers() { await this.usersMenuItem.click(); await this.waitForLoadState('networkidle'); } async navigateToLogs() { await this.logsMenuItem.click(); await this.waitForLoadState('networkidle'); } async logout() { await this.logoutButton.click(); } } export class AdminContentPage extends BasePage { readonly createButton: Locator; readonly contentList: Locator; readonly searchInput: Locator; readonly filterButtons: Locator; readonly editButtons: Locator; readonly deleteButtons: Locator; constructor(page: Page) { super(page); this.createButton = page.getByRole('button', { name: /创建|新建|create/i }); this.contentList = page.locator('table tbody tr').or(page.locator('[data-testid="content-item"]')); this.searchInput = page.locator('input[type="search"], input[placeholder*="搜索"]'); this.filterButtons = page.locator('button[role="tab"], select'); this.editButtons = page.getByRole('button', { name: /编辑|edit/i }); this.deleteButtons = page.getByRole('button', { name: /删除|delete/i }); } async goto() { await this.navigate('/admin/content'); await this.waitForLoadState('networkidle'); } async createContent(data: { type: string; title: string; slug: string; content?: string; }) { await this.createButton.click(); await this.page.locator('select[name="type"]').selectOption(data.type); await this.page.locator('input[name="title"]').fill(data.title); await this.page.locator('input[name="slug"]').fill(data.slug); if (data.content) { await this.page.locator('textarea[name="content"], .ProseMirror').fill(data.content); } await this.page.getByRole('button', { name: /保存|submit/i }).click(); } async searchContent(query: string) { await this.searchInput.fill(query); await this.page.keyboard.press('Enter'); await this.waitForLoadState('networkidle'); } async editContent(index: number) { const editButton = this.editButtons.nth(index); await editButton.click(); await this.waitForLoadState('networkidle'); } async deleteContent(index: number) { const deleteButton = this.deleteButtons.nth(index); await deleteButton.click(); const confirmButton = this.page.getByRole('button', { name: /确认|确定|confirm/i }); if (await confirmButton.isVisible()) { await confirmButton.click(); } await this.waitForLoadState('networkidle'); } } export class AdminUsersPage extends BasePage { readonly createButton: Locator; readonly usersList: Locator; readonly searchInput: Locator; readonly editButtons: Locator; readonly deleteButtons: Locator; constructor(page: Page) { super(page); this.createButton = page.getByRole('button', { name: /创建|新建|create/i }); this.usersList = page.locator('table tbody tr, [role="listitem"]'); this.searchInput = page.locator('input[type="search"], input[placeholder*="搜索"]'); this.editButtons = page.getByRole('button', { name: /编辑|edit/i }); this.deleteButtons = page.getByRole('button', { name: /删除|delete/i }); } async goto() { await this.navigate('/admin/users'); await this.waitForLoadState('networkidle'); } async createUser(data: { email: string; name: string; password: string; role: string; }) { await this.createButton.click(); await this.page.locator('input[name="email"]').fill(data.email); await this.page.locator('input[name="name"]').fill(data.name); await this.page.locator('input[name="password"]').fill(data.password); await this.page.locator('select[name="role"]').selectOption(data.role); await this.page.getByRole('button', { name: /保存|submit/i }).click(); } async deleteUser(index: number) { const deleteButton = this.deleteButtons.nth(index); await deleteButton.click(); const confirmButton = this.page.getByRole('button', { name: /确认|确定|confirm/i }); if (await confirmButton.isVisible()) { await confirmButton.click(); } await this.waitForLoadState('networkidle'); } } export class AdminLogsPage extends BasePage { readonly logsList: Locator; readonly actionFilter: Locator; readonly resourceTypeFilter: Locator; readonly refreshButton: Locator; readonly pagination: Locator; constructor(page: Page) { super(page); this.logsList = page.locator('table tbody tr, [role="listitem"]'); this.actionFilter = page.locator('select[name="action"], select').first(); this.resourceTypeFilter = page.locator('select[name="resourceType"], select').nth(1); this.refreshButton = page.getByRole('button', { name: /刷新|refresh/i }); this.pagination = page.locator('[role="navigation"], .pagination'); } async goto() { await this.navigate('/admin/logs'); await this.waitForLoadState('networkidle'); } async filterByAction(action: string) { await this.actionFilter.selectOption(action); await this.waitForLoadState('networkidle'); } async filterByResourceType(type: string) { await this.resourceTypeFilter.selectOption(type); await this.waitForLoadState('networkidle'); } async refresh() { await this.refreshButton.click(); await this.waitForLoadState('networkidle'); } async goToPage(pageNumber: number) { await this.pagination.getByRole('button', { name: String(pageNumber) }).click(); await this.waitForLoadState('networkidle'); } }