import { Page, Locator } from '@playwright/test'; export class LoginPage { readonly page: Page; readonly usernameInput: Locator; readonly passwordInput: Locator; readonly loginButton: Locator; readonly errorMessage: Locator; readonly successMessage: Locator; constructor(page: Page) { this.page = page; this.usernameInput = page.locator('input[placeholder="用户名"]'); this.passwordInput = page.locator('input[placeholder="密码"]'); this.loginButton = page.getByRole('button', { name: /登\s*录/ }); this.errorMessage = page.locator('.ant-message-error .ant-message-notice-content'); this.successMessage = page.locator('.ant-message-success .ant-message-notice-content'); } async goto() { await this.page.goto('/login'); await this.page.waitForLoadState('networkidle'); } async login(username: string, password: string) { await this.usernameInput.fill(username); await this.passwordInput.fill(password); await this.loginButton.click(); await this.page.waitForURL(/\/(dashboard)/, { timeout: 30000 }); await this.page.waitForLoadState('networkidle'); } async loginAndExpectError(username: string, password: string) { await this.usernameInput.fill(username); await this.passwordInput.fill(password); await this.loginButton.click(); } async getErrorMessage(): Promise { try { await this.errorMessage.waitFor({ state: 'visible', timeout: 5000 }); return await this.errorMessage.textContent(); } catch { return null; } } async logout() { const avatar = this.page.locator('.ant-avatar').first(); await avatar.click(); await this.page.waitForTimeout(500); const logoutItem = this.page.locator('.ant-dropdown-menu-item:has-text("退出登录")'); await logoutItem.click(); await this.page.waitForURL('**/login', { timeout: 10000 }); } async isLoggedIn(): Promise { return this.page.url().includes('/dashboard'); } }