优化文件路径

This commit is contained in:
dengqichen 2025-03-06 10:56:42 +08:00
parent b7f00b5a9f
commit 39983043e1
3 changed files with 105 additions and 113 deletions

View File

@ -87,12 +87,12 @@ class BasePage {
*/
async waitForElement(selector, options = {}) {
try {
const element = options.firstOnly ?
const element = options.firstOnly ?
this.page.locator(selector).first() :
this.page.locator(selector);
await element.waitFor({
state: 'visible',
state: 'visible',
timeout: options.timeout || this.config.timeout
});
@ -156,6 +156,7 @@ class BasePage {
/**
* 等待页面加载完成
* @deprecated 请使用 waitForPageLoadWithRetry 方法替代
*/
async waitForPageLoad() {
await this.page.waitForLoadState('networkidle', {
@ -163,6 +164,83 @@ class BasePage {
});
}
/**
* 等待页面加载完成带重试机制
* @param {Object} context 上下文信息对象
* @param {string} [context.text] 页面名称或描述
* @param {string} [context.path] 页面路径
* @param {string} [subContext] 子上下文信息可选
* @returns {Promise<boolean>} 页面是否加载成功
*/
async waitForPageLoadWithRetry(context, subContext = '') {
const pageName = this.getContextName(context, subContext);
console.log(`等待页面 ${pageName} 数据加载...`);
let retryCount = 0;
const {maxRetries, retryInterval, stabilityDelay} = this.config.pageLoad;
try {
while (retryCount < maxRetries) {
// 检查错误状态
const hasError = await this.checkPageError(pageName);
if (hasError) return false;
// 检查加载状态
const isLoading = await this.elementExists(this.selectors.loadingMask);
if (!isLoading) {
await this.wait(stabilityDelay);
console.log(`✅ 页面 ${pageName} 加载完成`);
return true;
}
retryCount++;
await this.wait(retryInterval);
}
console.error(`页面加载超时: ${pageName}, 重试次数: ${maxRetries}`);
return false;
} catch (error) {
console.error(`页面加载出错: ${pageName}, 错误信息: ${error.message}`);
return false;
}
}
/**
* 检查页面是否有错误
* @param {string} pageName 页面名称
* @returns {Promise<boolean>} 是否有错误
* @private
*/
async checkPageError(pageName) {
const errorSelectors = [this.selectors.errorBox, this.selectors.errorMessage];
for (const selector of errorSelectors) {
const elements = await this.page.locator(selector).all();
if (elements.length > 0) {
const errorText = await this.getElementText(elements[0]);
console.error(`页面加载出现错误: ${pageName}, 错误信息: ${errorText}`);
return true;
}
}
return false;
}
/**
* 获取上下文名称
* @param {Object} context 上下文信息对象
* @param {string} [subContext] 子上下文信息
* @returns {string} 格式化的上下文名称
* @private
*/
getContextName(context, subContext = '') {
if (typeof context === 'string') {
return context;
}
const mainText = context.text || context.path || 'Unknown';
return subContext ? `${mainText} > ${subContext}` : mainText;
}
/**
* 获取页面标题
* @returns {Promise<string>} 页面标题
@ -218,15 +296,14 @@ class BasePage {
/**
* 安全点击元素
* @param {Object} element Playwright元素对象
* @param {string} description 元素描述用于日志
* @returns {Promise<boolean>} 是否点击成功
*/
async safeClick(element, description) {
async safeClick(element) {
try {
await element.click();
return true;
} catch (error) {
console.error(`点击${description}失败:`, error.message);
console.error(`点击失败:`, error.message);
return false;
}
}

View File

@ -18,7 +18,7 @@ class LongiLoginPage extends BasePage {
initializeSelectors() {
// 调用父类的选择器初始化
super.initializeSelectors();
// 添加或覆盖特定于 LongiLoginPage 的选择器
Object.assign(this.selectors, {
// 登录表单元素
@ -40,7 +40,7 @@ class LongiLoginPage extends BasePage {
initializeConfig() {
// 调用父类的配置初始化
super.initializeConfig();
// 添加或覆盖特定于 LongiLoginPage 的配置
Object.assign(this.config, {
loginTimeout: 10000
@ -63,14 +63,14 @@ class LongiLoginPage extends BasePage {
try {
// 方法1: 使用更精确的选择器,指定包含特定类的按钮
await this.click(this.selectors.loginButton);
console.log('使用 container-button 类选择器成功点击登录按钮');
// console.log('使用 container-button 类选择器成功点击登录按钮');
await this.waitForPageLoad();
return true;
} catch (error) {
console.log('第一种方法失败,尝试备用方法...');
try {
// 方法2: 使用精确文本匹配
await this.safeClick(await this.page.locator(this.selectors.loginButtonByText), '登录按钮(精确文本匹配)');
await this.safeClick(await this.page.locator(this.selectors.loginButtonByText));
// console.log('使用精确文本匹配成功点击登录按钮');
await this.waitForPageLoad();
return true;
@ -78,7 +78,7 @@ class LongiLoginPage extends BasePage {
console.log('第二种方法也失败,尝试第三种方法...');
try {
// 方法3: 使用first()选择第一个匹配的按钮
await this.safeClick(await this.page.locator(this.selectors.loginButtonFirst).first(), '登录按钮first方法');
await this.safeClick(await this.page.locator(this.selectors.loginButtonFirst).first());
// console.log('使用first()方法成功点击登录按钮');
await this.waitForPageLoad();
return true;
@ -144,7 +144,7 @@ class LongiLoginPage extends BasePage {
await this.enterUsername(username);
await this.enterPassword(password);
await this.enterCaptcha(captcha);
if (await this.clickLoginButton()) {
return await this.isLoginSuccessful();
}

View File

@ -19,7 +19,7 @@ class LongiMainPage extends BasePage {
initializeSelectors() {
// 调用父类的选择器初始化
super.initializeSelectors();
// 添加或覆盖特定于 LongiMainPage 的选择器
Object.assign(this.selectors, {
// 侧边导航菜单
@ -46,7 +46,7 @@ class LongiMainPage extends BasePage {
initializeConfig() {
// 调用父类的配置初始化
super.initializeConfig();
// 添加或覆盖特定于 LongiMainPage 的配置
Object.assign(this.config, {
menuTimeout: parseInt(process.env.MENU_TIME_OUT || '30000', 10)
@ -210,7 +210,7 @@ class LongiMainPage extends BasePage {
const uniqueId = `menu_${i}_${text.trim().replace(/\s+/g, '_')}`;
// 获取菜单路径
const menuPath = await this.getMenuPath(item);
const menuPath = this.getMenuPath(item);
menuItems.push({
index: i,
@ -228,27 +228,14 @@ class LongiMainPage extends BasePage {
}
/**
* 获取菜单项的路径信息
* @param {Object} menuItem 菜单项元素
* @returns {Promise<string>} 菜单路径
* 获取菜单路径
* @param {Object} menuInfo 菜单信息对象
* @param {Object} parentMenu 父级菜单可选
* @returns {string} 菜单路径
* @private
*/
async getMenuPath(menuItem) {
// 尝试获取父级菜单的文本
const parentText = await menuItem.evaluate(el => {
// 查找最近的父级菜单项
const parent = el.closest('.el-submenu');
if (parent) {
const parentTitle = parent.querySelector('.el-submenu__title');
if (parentTitle) {
const titleSpan = parentTitle.querySelector('.titleSpan');
return titleSpan ? titleSpan.textContent.trim() : parentTitle.textContent.trim();
}
}
return '';
});
const itemText = await menuItem.textContent();
return parentText ? `${parentText} > ${itemText}` : itemText;
async getMenuPath(menuInfo, parentMenu = null) {
return parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
}
/**
@ -420,7 +407,7 @@ class LongiMainPage extends BasePage {
const menuPath = this.getMenuPath(menuInfo, parentMenu);
console.log(`点击菜单: ${menuPath}`);
if (!await this.safeClick(menuInfo.element, menuPath)) {
if (!await this.safeClick(menuInfo.element)) {
return;
}
@ -430,18 +417,7 @@ class LongiMainPage extends BasePage {
}
await this.handleAllTabs(menuInfo);
await this.closeActiveTab(menuPath);
}
/**
* 获取菜单路径
* @param {Object} menuInfo 菜单信息对象
* @param {Object} parentMenu 父级菜单可选
* @returns {string} 菜单路径
* @private
*/
getMenuPath(menuInfo, parentMenu = null) {
return parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
await this.closeActiveTab(menuInfo);
}
/**
@ -506,86 +482,25 @@ class LongiMainPage extends BasePage {
);
}
/**
* 等待页面加载完成带重试机制
* @param {Object} menu 菜单对象
* @param {string} subMenuText 子菜单文本可选
* @returns {Promise<boolean>} 页面是否加载成功
*/
async waitForPageLoadWithRetry(menu, subMenuText = '') {
const pageName = this.getMenuPath(menu, {text: subMenuText});
console.log(`等待页面 ${pageName} 数据加载...`);
let retryCount = 0;
const {maxRetries, retryInterval, stabilityDelay} = this.config.pageLoad;
try {
while (retryCount < maxRetries) {
// 检查错误状态
const hasError = await this.checkPageError(pageName);
if (hasError) return false;
// 检查加载状态
const isLoading = await this.elementExists(this.selectors.loadingMask);
if (!isLoading) {
await this.wait(stabilityDelay);
console.log(`✅ 页面 ${pageName} 加载完成`);
return true;
}
retryCount++;
await this.wait(retryInterval);
}
console.error(`页面加载超时: ${pageName}, 重试次数: ${maxRetries}`);
return false;
} catch (error) {
console.error(`页面加载出错: ${pageName}, 错误信息: ${error.message}`);
return false;
}
}
/**
* 检查页面是否有错误
* @param {string} pageName 页面名称
* @returns {Promise<boolean>} 是否有错误
* @private
*/
async checkPageError(pageName) {
const errorSelectors = [this.selectors.errorBox, this.selectors.errorMessage];
for (const selector of errorSelectors) {
const elements = await this.page.locator(selector).all();
if (elements.length > 0) {
const errorText = await this.getElementText(elements[0]);
console.error(`页面加载出现错误: ${pageName}, 错误信息: ${errorText}`);
return true;
}
}
return false;
}
/**
* 关闭当前活动的标签页
* @param {string} pageName 页面名称用于日志显示
*/
async closeActiveTab(pageName) {
async closeActiveTab(parentMenu) {
try {
console.log(`🗑️ 正在关闭页面 "${pageName}" 的tab...`);
console.log(`🗑️ 正在关闭页面 "${parentMenu.text}" 的tab...`);
const activeTab = this.page.locator(this.selectors.activeTab);
const closeButton = activeTab.locator(this.selectors.closeButton);
if (await this.canCloseTab(activeTab, closeButton)) {
await closeButton.waitFor({state: 'visible', timeout: 5000});
await this.safeClick(closeButton, `${pageName}的关闭按钮`);
await this.safeClick(closeButton);
await this.wait(500);
} else {
console.log(`⚠️ [${pageName}] 没有找到可关闭的tab继续执行...`);
console.log(`⚠️ [${parentMenu.text}] 没有找到可关闭的tab继续执行...`);
}
} catch (error) {
console.error(`关闭标签页时出错 [${pageName}]:`, error.message);
console.error(`关闭标签页时出错 [${parentMenu.text}]:`, error.message);
}
}