feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
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 MenuManagementPage extends BasePage {
|
||||
private formHelper: FormHelper;
|
||||
private tableHelper: TableHelper;
|
||||
private screenshotHelper: ScreenshotHelper;
|
||||
|
||||
private readonly selectors = {
|
||||
menuTree: '.menu-tree',
|
||||
menuTable: '.menu-table',
|
||||
addMenuButton: 'button:has-text("新增")',
|
||||
editButton: 'button:has-text("编辑")',
|
||||
deleteButton: 'button:has-text("删除")',
|
||||
searchInput: 'input[placeholder*="搜索"]',
|
||||
searchButton: 'button:has-text("查询")',
|
||||
resetButton: 'button:has-text("重置")',
|
||||
modal: '.ant-modal',
|
||||
modalTitle: '.ant-modal-title',
|
||||
modalConfirmButton: '.ant-modal-confirm-btn',
|
||||
modalCancelButton: '.ant-modal-cancel-btn',
|
||||
successMessage: '.ant-message-success',
|
||||
errorMessage: '.ant-message-error',
|
||||
menuForm: '.menu-form',
|
||||
menuNameInput: 'input[name="menuName"]',
|
||||
menuTypeSelect: 'select[name="menuType"]',
|
||||
menuIconInput: 'input[name="icon"]',
|
||||
orderNumInput: 'input[name="orderNum"]',
|
||||
pathInput: 'input[name="path"]',
|
||||
componentInput: 'input[name="component"]',
|
||||
statusSelect: 'select[name="status"]',
|
||||
visibleSelect: 'select[name="visible"]',
|
||||
remarkInput: 'textarea[name="remark"]',
|
||||
treeNode: '.ant-tree-node',
|
||||
treeExpandButton: '.ant-tree-switcher'
|
||||
};
|
||||
|
||||
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('/system/menu');
|
||||
}
|
||||
|
||||
async waitForLoad(): Promise<void> {
|
||||
testLogger.info('等待菜单管理页面加载');
|
||||
|
||||
try {
|
||||
await this.page.waitForSelector(this.selectors.menuTree, {
|
||||
state: 'visible',
|
||||
timeout: this.timeout.default
|
||||
});
|
||||
|
||||
testLogger.info('菜单管理页面加载完成');
|
||||
} catch (error) {
|
||||
testLogger.error('菜单管理页面加载超时', error as Error);
|
||||
await this.screenshotHelper.takeScreenshot('menu-management-load-error');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async clickAddMenu(): Promise<void> {
|
||||
testLogger.info('点击新增菜单按钮');
|
||||
|
||||
try {
|
||||
await this.page.waitForSelector(this.selectors.addMenuButton, {
|
||||
state: 'visible',
|
||||
timeout: this.timeout.element
|
||||
});
|
||||
|
||||
await this.page.click(this.selectors.addMenuButton);
|
||||
|
||||
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-menu-error');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async clickEditMenu(menuName: string): Promise<void> {
|
||||
testLogger.info(`点击编辑菜单按钮,菜单名称: ${menuName}`);
|
||||
|
||||
try {
|
||||
const editButtons = this.page.locator(this.selectors.editButton);
|
||||
await editButtons.first().waitFor({ state: 'visible', timeout: this.timeout.element });
|
||||
|
||||
await editButtons.first().click();
|
||||
|
||||
await this.page.waitForSelector(this.selectors.modal, {
|
||||
state: 'visible',
|
||||
timeout: this.timeout.element
|
||||
});
|
||||
|
||||
testLogger.info('编辑菜单对话框已打开');
|
||||
} catch (error) {
|
||||
testLogger.error(`点击编辑菜单按钮失败,菜单名称: ${menuName}`, error as Error);
|
||||
await this.screenshotHelper.takeScreenshot(`click-edit-menu-${menuName}-error`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async clickDeleteMenu(menuName: string): Promise<void> {
|
||||
testLogger.info(`点击删除菜单按钮,菜单名称: ${menuName}`);
|
||||
|
||||
try {
|
||||
const deleteButtons = this.page.locator(this.selectors.deleteButton);
|
||||
await deleteButtons.first().waitFor({ state: 'visible', timeout: this.timeout.element });
|
||||
|
||||
await deleteButtons.first().click();
|
||||
|
||||
testLogger.info('删除确认对话框已打开');
|
||||
} catch (error) {
|
||||
testLogger.error(`点击删除菜单按钮失败,菜单名称: ${menuName}`, error as Error);
|
||||
await this.screenshotHelper.takeScreenshot(`click-delete-menu-${menuName}-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 searchMenu(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-menu-error');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async expandTreeNode(nodeIndex: number): Promise<void> {
|
||||
testLogger.info(`展开树节点,索引: ${nodeIndex}`);
|
||||
|
||||
try {
|
||||
const expandButtons = this.page.locator(this.selectors.treeExpandButton);
|
||||
await expandButtons.nth(nodeIndex).waitFor({ state: 'visible', timeout: this.timeout.element });
|
||||
|
||||
await expandButtons.nth(nodeIndex).click();
|
||||
|
||||
testLogger.info(`树节点已展开,索引: ${nodeIndex}`);
|
||||
} catch (error) {
|
||||
testLogger.error(`展开树节点失败,索引: ${nodeIndex}`, error as Error);
|
||||
await this.screenshotHelper.takeScreenshot(`expand-tree-node-${nodeIndex}-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 getMenuCount(): Promise<number> {
|
||||
testLogger.debug('获取菜单数量');
|
||||
|
||||
try {
|
||||
const count = await this.tableHelper.getRowCount(this.selectors.menuTable);
|
||||
testLogger.debug(`菜单数量: ${count}`);
|
||||
|
||||
return count;
|
||||
} catch (error) {
|
||||
testLogger.error('获取菜单数量失败', error as Error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getTreeNodeCount(): Promise<number> {
|
||||
testLogger.debug('获取树节点数量');
|
||||
|
||||
try {
|
||||
const treeNodes = this.page.locator(this.selectors.treeNode);
|
||||
const count = await treeNodes.count();
|
||||
|
||||
testLogger.debug(`树节点数量: ${count}`);
|
||||
|
||||
return count;
|
||||
} catch (error) {
|
||||
testLogger.error('获取树节点数量失败', error as Error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user