08ea5fbe98
添加用户管理视图、API和状态管理文件
234 lines
6.8 KiB
TypeScript
234 lines
6.8 KiB
TypeScript
import { Page, expect } from '@playwright/test';
|
|
import { BasePage } from './base-page';
|
|
import { testLogger } from '../core/test-logger';
|
|
|
|
export class LoginPage extends BasePage {
|
|
private readonly selectors = {
|
|
usernameInput: '[data-testid="username-input"]',
|
|
passwordInput: '[data-testid="password-input"]',
|
|
loginButton: '[data-testid="login-button"]',
|
|
errorMessage: '.ant-message-error',
|
|
successMessage: '.ant-message-success',
|
|
loginForm: '[data-testid="login-form"]',
|
|
rememberMeCheckbox: '[data-testid="remember-checkbox"]',
|
|
forgotPasswordLink: 'text=忘记密码',
|
|
registerLink: 'text=注册账号'
|
|
};
|
|
|
|
constructor(page: Page) {
|
|
super(page);
|
|
}
|
|
|
|
async navigate(): Promise<void> {
|
|
testLogger.info('导航到登录页面');
|
|
await super.navigate('/login');
|
|
}
|
|
|
|
async waitForLoad(): Promise<void> {
|
|
testLogger.debug('等待登录页面加载完成');
|
|
|
|
try {
|
|
await Promise.all([
|
|
this.waitForElement(this.selectors.usernameInput),
|
|
this.waitForElement(this.selectors.passwordInput),
|
|
this.waitForElement(this.selectors.loginButton)
|
|
]);
|
|
|
|
testLogger.info('登录页面加载完成');
|
|
} catch (error) {
|
|
testLogger.error('登录页面加载失败', error as Error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async getUsernameInput() {
|
|
return this.page.locator(this.selectors.usernameInput);
|
|
}
|
|
|
|
async getPasswordInput() {
|
|
return this.page.locator(this.selectors.passwordInput);
|
|
}
|
|
|
|
async getLoginButton() {
|
|
return this.page.locator(this.selectors.loginButton);
|
|
}
|
|
|
|
async getErrorMessage() {
|
|
return this.page.locator(this.selectors.errorMessage);
|
|
}
|
|
|
|
async getSuccessMessage() {
|
|
return this.page.locator(this.selectors.successMessage);
|
|
}
|
|
|
|
async fillUsername(username: string): Promise<void> {
|
|
testLogger.info(`填写用户名: ${username}`);
|
|
await this.fill(this.selectors.usernameInput, username);
|
|
}
|
|
|
|
async fillPassword(password: string): Promise<void> {
|
|
testLogger.info('填写密码');
|
|
await this.fill(this.selectors.passwordInput, password);
|
|
}
|
|
|
|
async clickLoginButton(): Promise<void> {
|
|
testLogger.info('点击登录按钮');
|
|
await this.click(this.selectors.loginButton);
|
|
}
|
|
|
|
async toggleRememberMe(remember: boolean): Promise<void> {
|
|
testLogger.info(`设置记住密码: ${remember}`);
|
|
|
|
if (remember) {
|
|
await this.check(this.selectors.rememberMeCheckbox);
|
|
} else {
|
|
await this.uncheck(this.selectors.rememberMeCheckbox);
|
|
}
|
|
}
|
|
|
|
async login(username: string, password: string, rememberMe: boolean = false): Promise<void> {
|
|
testLogger.startStep('用户登录');
|
|
|
|
try {
|
|
await this.waitForLoad();
|
|
await this.fillUsername(username);
|
|
await this.fillPassword(password);
|
|
|
|
if (rememberMe) {
|
|
await this.toggleRememberMe(true);
|
|
}
|
|
|
|
await this.clickLoginButton();
|
|
|
|
testLogger.endStep('用户登录', 'passed');
|
|
} catch (error) {
|
|
testLogger.endStep('用户登录', 'failed', error as Error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async loginAndWaitForDashboard(username: string, password: string, rememberMe: boolean = false): Promise<void> {
|
|
testLogger.startStep('登录并等待跳转到仪表盘');
|
|
|
|
try {
|
|
await this.login(username, password, rememberMe);
|
|
|
|
await this.waitForURL(/.*dashboard/, this.timeout.navigation);
|
|
|
|
testLogger.endStep('登录并等待跳转到仪表盘', 'passed');
|
|
} catch (error) {
|
|
testLogger.endStep('登录并等待跳转到仪表盘', 'failed', error as Error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async expectErrorMessage(message: string): Promise<void> {
|
|
testLogger.debug(`期望错误消息: ${message}`);
|
|
|
|
const errorLocator = this.getErrorMessage();
|
|
await expect(errorLocator).toBeVisible({ timeout: 5000 });
|
|
await expect(errorLocator).toContainText(message);
|
|
}
|
|
|
|
async expectSuccessMessage(message: string): Promise<void> {
|
|
testLogger.debug(`期望成功消息: ${message}`);
|
|
|
|
const successLocator = this.getSuccessMessage();
|
|
await expect(successLocator).toBeVisible({ timeout: 5000 });
|
|
await expect(successLocator).toContainText(message);
|
|
}
|
|
|
|
async hasErrorMessage(): Promise<boolean> {
|
|
const errorLocator = this.getErrorMessage();
|
|
const count = await errorLocator.count();
|
|
return count > 0;
|
|
}
|
|
|
|
async hasSuccessMessage(): Promise<boolean> {
|
|
const successLocator = this.getSuccessMessage();
|
|
const count = await successLocator.count();
|
|
return count > 0;
|
|
}
|
|
|
|
async getErrorMessageText(): Promise<string> {
|
|
const errorLocator = this.getErrorMessage();
|
|
const text = await errorLocator.textContent();
|
|
return text || '';
|
|
}
|
|
|
|
async getSuccessMessageText(): Promise<string> {
|
|
const successLocator = this.getSuccessMessage();
|
|
const text = await successLocator.textContent();
|
|
return text || '';
|
|
}
|
|
|
|
async isLoginButtonEnabled(): Promise<boolean> {
|
|
const loginButton = this.getLoginButton();
|
|
return await loginButton.isEnabled();
|
|
}
|
|
|
|
async isUsernameInputVisible(): Promise<boolean> {
|
|
return await this.isVisible(this.selectors.usernameInput);
|
|
}
|
|
|
|
async isPasswordInputVisible(): Promise<boolean> {
|
|
return await this.isVisible(this.selectors.passwordInput);
|
|
}
|
|
|
|
async isLoginFormVisible(): Promise<boolean> {
|
|
return await this.isVisible(this.selectors.loginForm);
|
|
}
|
|
|
|
async clearUsername(): Promise<void> {
|
|
testLogger.info('清空用户名输入框');
|
|
const usernameInput = this.getUsernameInput();
|
|
await usernameInput.fill('');
|
|
}
|
|
|
|
async clearPassword(): Promise<void> {
|
|
testLogger.info('清空密码输入框');
|
|
const passwordInput = this.getPasswordInput();
|
|
await passwordInput.fill('');
|
|
}
|
|
|
|
async clearAllFields(): Promise<void> {
|
|
await this.clearUsername();
|
|
await this.clearPassword();
|
|
}
|
|
|
|
async clickForgotPassword(): Promise<void> {
|
|
testLogger.info('点击忘记密码链接');
|
|
await this.click(this.selectors.forgotPasswordLink);
|
|
}
|
|
|
|
async clickRegister(): Promise<void> {
|
|
testLogger.info('点击注册账号链接');
|
|
await this.click(this.selectors.registerLink);
|
|
}
|
|
|
|
async pressEnter(): Promise<void> {
|
|
testLogger.info('按Enter键提交登录');
|
|
await this.page.keyboard.press('Enter');
|
|
}
|
|
|
|
async loginWithEnter(username: string, password: string): Promise<void> {
|
|
testLogger.startStep('使用Enter键登录');
|
|
|
|
try {
|
|
await this.waitForLoad();
|
|
await this.fillUsername(username);
|
|
await this.fillPassword(password);
|
|
await this.pressEnter();
|
|
|
|
testLogger.endStep('使用Enter键登录', 'passed');
|
|
} catch (error) {
|
|
testLogger.endStep('使用Enter键登录', 'failed', error as Error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async takeScreenshotOnLogin(name: string = 'login-page'): Promise<string> {
|
|
return await this.takeScreenshot(name);
|
|
}
|
|
}
|