08ea5fbe98
添加用户管理视图、API和状态管理文件
277 lines
8.9 KiB
TypeScript
277 lines
8.9 KiB
TypeScript
import { Page } from '@playwright/test';
|
|
import { BasePage } from './base-page';
|
|
import { FormHelper } from '../helpers/form-helper';
|
|
import { TableHelper } from '../helpers/table-helper';
|
|
import { ScreenshotHelper } from '../helpers/screenshot-helper';
|
|
import { testLogger } from '../core/test-logger';
|
|
|
|
export class UserManagementPage extends BasePage {
|
|
private formHelper: FormHelper;
|
|
private tableHelper: TableHelper;
|
|
private screenshotHelper: ScreenshotHelper;
|
|
|
|
private readonly selectors = {
|
|
userTable: '.el-table',
|
|
addUserButton: 'button:has-text("新增用户")',
|
|
editButton: 'button:has-text("编辑")',
|
|
deleteButton: 'button:has-text("删除")',
|
|
searchInput: 'input[data-testid="search-username-input"]',
|
|
searchButton: 'button:has-text("搜索")',
|
|
resetButton: 'button:has-text("重置")',
|
|
modal: '.el-dialog',
|
|
modalTitle: '.el-dialog__title',
|
|
modalConfirmButton: 'button:has-text("确定")',
|
|
modalCancelButton: 'button:has-text("取消")',
|
|
successMessage: '.el-message--success',
|
|
errorMessage: '.el-message--error',
|
|
pagination: '.el-pagination',
|
|
userForm: '.el-form',
|
|
usernameInput: 'input[data-testid="username-input"]',
|
|
passwordInput: 'input[data-testid="password-input"]',
|
|
emailInput: 'input[data-testid="email-input"]',
|
|
phoneInput: 'input[data-testid="phone-input"]',
|
|
realNameInput: 'input[placeholder="请输入昵称"]',
|
|
statusSelect: '.el-radio-group',
|
|
roleSelect: '.el-select',
|
|
roleOption: '.el-select-dropdown__item'
|
|
};
|
|
|
|
constructor(page: Page) {
|
|
super(page);
|
|
this.formHelper = new FormHelper(page);
|
|
this.tableHelper = new TableHelper(page);
|
|
this.screenshotHelper = new ScreenshotHelper(page);
|
|
}
|
|
|
|
async navigate(): Promise<void> {
|
|
testLogger.info('导航到用户管理页面');
|
|
await super.navigate('/users');
|
|
}
|
|
|
|
async waitForLoad(): Promise<void> {
|
|
testLogger.info('等待用户管理页面加载');
|
|
|
|
try {
|
|
await this.page.waitForSelector(this.selectors.userTable, {
|
|
state: 'visible',
|
|
timeout: this.timeout.default
|
|
});
|
|
|
|
testLogger.info('用户管理页面加载完成');
|
|
} catch (error) {
|
|
testLogger.error('用户管理页面加载超时', error as Error);
|
|
await this.screenshotHelper.takeScreenshot('user-management-load-error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async clickAddUser(): Promise<void> {
|
|
testLogger.info('点击新增用户按钮');
|
|
|
|
try {
|
|
await this.page.waitForSelector(this.selectors.addUserButton, {
|
|
state: 'visible',
|
|
timeout: this.timeout.element
|
|
});
|
|
|
|
await this.page.click(this.selectors.addUserButton);
|
|
|
|
await this.page.waitForSelector(this.selectors.modal, {
|
|
state: 'visible',
|
|
timeout: this.timeout.element
|
|
});
|
|
|
|
testLogger.info('新增用户对话框已打开');
|
|
} catch (error) {
|
|
testLogger.error('点击新增用户按钮失败', error as Error);
|
|
await this.screenshotHelper.takeScreenshot('click-add-user-error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async clickEditUser(rowIndex: number): Promise<void> {
|
|
testLogger.info(`点击编辑用户按钮,行索引: ${rowIndex}`);
|
|
|
|
try {
|
|
const editButtons = this.page.locator(this.selectors.editButton);
|
|
await editButtons.nth(rowIndex).waitFor({ state: 'visible', timeout: this.timeout.element });
|
|
|
|
await editButtons.nth(rowIndex).click();
|
|
|
|
await this.page.waitForSelector(this.selectors.modal, {
|
|
state: 'visible',
|
|
timeout: this.timeout.element
|
|
});
|
|
|
|
testLogger.info('编辑用户对话框已打开');
|
|
} catch (error) {
|
|
testLogger.error(`点击编辑用户按钮失败,行索引: ${rowIndex}`, error as Error);
|
|
await this.screenshotHelper.takeScreenshot(`click-edit-user-${rowIndex}-error`);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async clickDeleteUser(rowIndex: number): Promise<void> {
|
|
testLogger.info(`点击删除用户按钮,行索引: ${rowIndex}`);
|
|
|
|
try {
|
|
const deleteButtons = this.page.locator(this.selectors.deleteButton);
|
|
await deleteButtons.nth(rowIndex).waitFor({ state: 'visible', timeout: this.timeout.element });
|
|
|
|
await deleteButtons.nth(rowIndex).click();
|
|
|
|
testLogger.info('删除确认对话框已打开');
|
|
} catch (error) {
|
|
testLogger.error(`点击删除用户按钮失败,行索引: ${rowIndex}`, error as Error);
|
|
await this.screenshotHelper.takeScreenshot(`click-delete-user-${rowIndex}-error`);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async confirmDelete(): Promise<void> {
|
|
testLogger.info('确认删除用户');
|
|
|
|
try {
|
|
await this.page.waitForSelector(this.selectors.modalConfirmButton, {
|
|
state: 'visible',
|
|
timeout: this.timeout.element
|
|
});
|
|
|
|
await this.page.click(this.selectors.modalConfirmButton);
|
|
|
|
await this.page.waitForSelector(this.selectors.modal, {
|
|
state: 'hidden',
|
|
timeout: this.timeout.element
|
|
});
|
|
|
|
testLogger.info('用户删除确认成功');
|
|
} catch (error) {
|
|
testLogger.error('确认删除用户失败', error as Error);
|
|
await this.screenshotHelper.takeScreenshot('confirm-delete-error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async searchUser(keyword: string): Promise<void> {
|
|
testLogger.info(`搜索用户,关键词: ${keyword}`);
|
|
|
|
try {
|
|
await this.page.waitForSelector(this.selectors.searchInput, {
|
|
state: 'visible',
|
|
timeout: this.timeout.element
|
|
});
|
|
|
|
await this.page.fill(this.selectors.searchInput, keyword);
|
|
await this.page.click(this.selectors.searchButton);
|
|
|
|
await this.page.waitForLoadState('networkidle', {
|
|
timeout: this.timeout.network
|
|
});
|
|
|
|
testLogger.info('用户搜索完成');
|
|
} catch (error) {
|
|
testLogger.error(`搜索用户失败,关键词: ${keyword}`, error as Error);
|
|
await this.screenshotHelper.takeScreenshot('search-user-error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async resetSearch(): Promise<void> {
|
|
testLogger.info('重置搜索条件');
|
|
|
|
try {
|
|
await this.page.waitForSelector(this.selectors.resetButton, {
|
|
state: 'visible',
|
|
timeout: this.timeout.element
|
|
});
|
|
|
|
await this.page.click(this.selectors.resetButton);
|
|
|
|
await this.page.waitForLoadState('networkidle', {
|
|
timeout: this.timeout.network
|
|
});
|
|
|
|
testLogger.info('搜索条件已重置');
|
|
} catch (error) {
|
|
testLogger.error('重置搜索条件失败', error as Error);
|
|
await this.screenshotHelper.takeScreenshot('reset-search-error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async getSuccessMessage(): Promise<string> {
|
|
testLogger.debug('获取成功消息');
|
|
|
|
try {
|
|
const successElement = this.page.locator(this.selectors.successMessage);
|
|
await successElement.waitFor({ state: 'visible', timeout: this.timeout.element });
|
|
|
|
const message = await successElement.textContent();
|
|
testLogger.debug(`成功消息: ${message}`);
|
|
|
|
return message || '';
|
|
} catch (error) {
|
|
testLogger.error('获取成功消息失败', error as Error);
|
|
return '';
|
|
}
|
|
}
|
|
|
|
async getErrorMessage(): Promise<string> {
|
|
testLogger.debug('获取错误消息');
|
|
|
|
try {
|
|
const errorElement = this.page.locator(this.selectors.errorMessage);
|
|
await errorElement.waitFor({ state: 'visible', timeout: this.timeout.element });
|
|
|
|
const message = await errorElement.textContent();
|
|
testLogger.debug(`错误消息: ${message}`);
|
|
|
|
return message || '';
|
|
} catch (error) {
|
|
testLogger.error('获取错误消息失败', error as Error);
|
|
return '';
|
|
}
|
|
}
|
|
|
|
async getUserCount(): Promise<number> {
|
|
testLogger.debug('获取用户数量');
|
|
|
|
try {
|
|
const count = await this.tableHelper.getRowCount(this.selectors.userTable);
|
|
testLogger.debug(`用户数量: ${count}`);
|
|
|
|
return count;
|
|
} catch (error) {
|
|
testLogger.error('获取用户数量失败', error as Error);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
async selectRoles(roleNames: string[]): Promise<void> {
|
|
testLogger.info('选择角色', { roleNames });
|
|
|
|
try {
|
|
const roleSelect = this.page.locator(this.selectors.roleSelect);
|
|
await roleSelect.waitFor({ state: 'visible', timeout: this.timeout.element });
|
|
await roleSelect.click();
|
|
|
|
await this.page.waitForSelector(this.selectors.roleOption, { timeout: 5000 });
|
|
|
|
for (const roleName of roleNames) {
|
|
const option = this.page.locator(this.selectors.roleOption).filter({ hasText: roleName });
|
|
await option.waitFor({ state: 'visible', timeout: 3000 });
|
|
await option.click();
|
|
await this.page.waitForTimeout(200);
|
|
}
|
|
|
|
await this.page.keyboard.press('Escape');
|
|
await this.page.waitForTimeout(500);
|
|
|
|
testLogger.info('角色选择完成');
|
|
} catch (error) {
|
|
testLogger.error('选择角色失败', error as Error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|