优化文件路径
This commit is contained in:
parent
b7f00b5a9f
commit
39983043e1
@ -156,6 +156,7 @@ class BasePage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 等待页面加载完成
|
* 等待页面加载完成
|
||||||
|
* @deprecated 请使用 waitForPageLoadWithRetry 方法替代
|
||||||
*/
|
*/
|
||||||
async waitForPageLoad() {
|
async waitForPageLoad() {
|
||||||
await this.page.waitForLoadState('networkidle', {
|
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>} 页面标题
|
* @returns {Promise<string>} 页面标题
|
||||||
@ -218,15 +296,14 @@ class BasePage {
|
|||||||
/**
|
/**
|
||||||
* 安全点击元素
|
* 安全点击元素
|
||||||
* @param {Object} element Playwright元素对象
|
* @param {Object} element Playwright元素对象
|
||||||
* @param {string} description 元素描述,用于日志
|
|
||||||
* @returns {Promise<boolean>} 是否点击成功
|
* @returns {Promise<boolean>} 是否点击成功
|
||||||
*/
|
*/
|
||||||
async safeClick(element, description) {
|
async safeClick(element) {
|
||||||
try {
|
try {
|
||||||
await element.click();
|
await element.click();
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`点击${description}失败:`, error.message);
|
console.error(`点击失败:`, error.message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,14 +63,14 @@ class LongiLoginPage extends BasePage {
|
|||||||
try {
|
try {
|
||||||
// 方法1: 使用更精确的选择器,指定包含特定类的按钮
|
// 方法1: 使用更精确的选择器,指定包含特定类的按钮
|
||||||
await this.click(this.selectors.loginButton);
|
await this.click(this.selectors.loginButton);
|
||||||
console.log('使用 container-button 类选择器成功点击登录按钮');
|
// console.log('使用 container-button 类选择器成功点击登录按钮');
|
||||||
await this.waitForPageLoad();
|
await this.waitForPageLoad();
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('第一种方法失败,尝试备用方法...');
|
console.log('第一种方法失败,尝试备用方法...');
|
||||||
try {
|
try {
|
||||||
// 方法2: 使用精确文本匹配
|
// 方法2: 使用精确文本匹配
|
||||||
await this.safeClick(await this.page.locator(this.selectors.loginButtonByText), '登录按钮(精确文本匹配)');
|
await this.safeClick(await this.page.locator(this.selectors.loginButtonByText));
|
||||||
// console.log('使用精确文本匹配成功点击登录按钮');
|
// console.log('使用精确文本匹配成功点击登录按钮');
|
||||||
await this.waitForPageLoad();
|
await this.waitForPageLoad();
|
||||||
return true;
|
return true;
|
||||||
@ -78,7 +78,7 @@ class LongiLoginPage extends BasePage {
|
|||||||
console.log('第二种方法也失败,尝试第三种方法...');
|
console.log('第二种方法也失败,尝试第三种方法...');
|
||||||
try {
|
try {
|
||||||
// 方法3: 使用first()选择第一个匹配的按钮
|
// 方法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()方法成功点击登录按钮');
|
// console.log('使用first()方法成功点击登录按钮');
|
||||||
await this.waitForPageLoad();
|
await this.waitForPageLoad();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -210,7 +210,7 @@ class LongiMainPage extends BasePage {
|
|||||||
const uniqueId = `menu_${i}_${text.trim().replace(/\s+/g, '_')}`;
|
const uniqueId = `menu_${i}_${text.trim().replace(/\s+/g, '_')}`;
|
||||||
|
|
||||||
// 获取菜单路径
|
// 获取菜单路径
|
||||||
const menuPath = await this.getMenuPath(item);
|
const menuPath = this.getMenuPath(item);
|
||||||
|
|
||||||
menuItems.push({
|
menuItems.push({
|
||||||
index: i,
|
index: i,
|
||||||
@ -228,27 +228,14 @@ class LongiMainPage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取菜单项的路径信息
|
* 获取菜单路径
|
||||||
* @param {Object} menuItem 菜单项元素
|
* @param {Object} menuInfo 菜单信息对象
|
||||||
* @returns {Promise<string>} 菜单路径
|
* @param {Object} parentMenu 父级菜单(可选)
|
||||||
|
* @returns {string} 菜单路径
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
async getMenuPath(menuItem) {
|
async getMenuPath(menuInfo, parentMenu = null) {
|
||||||
// 尝试获取父级菜单的文本
|
return parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -420,7 +407,7 @@ class LongiMainPage extends BasePage {
|
|||||||
const menuPath = this.getMenuPath(menuInfo, parentMenu);
|
const menuPath = this.getMenuPath(menuInfo, parentMenu);
|
||||||
console.log(`点击菜单: ${menuPath}`);
|
console.log(`点击菜单: ${menuPath}`);
|
||||||
|
|
||||||
if (!await this.safeClick(menuInfo.element, menuPath)) {
|
if (!await this.safeClick(menuInfo.element)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,18 +417,7 @@ class LongiMainPage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.handleAllTabs(menuInfo);
|
await this.handleAllTabs(menuInfo);
|
||||||
await this.closeActiveTab(menuPath);
|
await this.closeActiveTab(menuInfo);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取菜单路径
|
|
||||||
* @param {Object} menuInfo 菜单信息对象
|
|
||||||
* @param {Object} parentMenu 父级菜单(可选)
|
|
||||||
* @returns {string} 菜单路径
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
getMenuPath(menuInfo, parentMenu = null) {
|
|
||||||
return parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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 {
|
try {
|
||||||
console.log(`🗑️ 正在关闭页面 "${pageName}" 的tab...`);
|
console.log(`🗑️ 正在关闭页面 "${parentMenu.text}" 的tab...`);
|
||||||
|
|
||||||
const activeTab = this.page.locator(this.selectors.activeTab);
|
const activeTab = this.page.locator(this.selectors.activeTab);
|
||||||
const closeButton = activeTab.locator(this.selectors.closeButton);
|
const closeButton = activeTab.locator(this.selectors.closeButton);
|
||||||
|
|
||||||
if (await this.canCloseTab(activeTab, closeButton)) {
|
if (await this.canCloseTab(activeTab, closeButton)) {
|
||||||
await closeButton.waitFor({state: 'visible', timeout: 5000});
|
await closeButton.waitFor({state: 'visible', timeout: 5000});
|
||||||
await this.safeClick(closeButton, `${pageName}的关闭按钮`);
|
await this.safeClick(closeButton);
|
||||||
await this.wait(500);
|
await this.wait(500);
|
||||||
} else {
|
} else {
|
||||||
console.log(`⚠️ [${pageName}] 没有找到可关闭的tab,继续执行...`);
|
console.log(`⚠️ [${parentMenu.text}] 没有找到可关闭的tab,继续执行...`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`关闭标签页时出错 [${pageName}]:`, error.message);
|
console.error(`关闭标签页时出错 [${parentMenu.text}]:`, error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user