抽取共用部分
This commit is contained in:
parent
54296d639a
commit
23020e7825
@ -11,23 +11,89 @@ class LongiMainPage extends BasePage {
|
|||||||
*/
|
*/
|
||||||
constructor(page) {
|
constructor(page) {
|
||||||
super(page);
|
super(page);
|
||||||
|
this.initializeSelectors();
|
||||||
|
this.initializeConfig();
|
||||||
|
}
|
||||||
|
|
||||||
// 页面元素选择器
|
/**
|
||||||
|
* 初始化选择器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
initializeSelectors() {
|
||||||
this.selectors = {
|
this.selectors = {
|
||||||
// 侧边导航菜单 - 使用更精确的选择器
|
// 侧边导航菜单
|
||||||
sideNav: '.ly-side-nav, .el-menu', // 主菜单
|
sideNav: '.ly-side-nav, .el-menu',
|
||||||
menuToggle: '.hamburger-container, .fold-btn, button.hamburger, .vab-content .toggle-icon', // 菜单展开/收起按钮,提供多个可能的选择器
|
menuToggle: '.hamburger-container, .fold-btn, button.hamburger, .vab-content .toggle-icon',
|
||||||
menuContainer: '.el-scrollbar__view > .el-menu', // 菜单容器
|
menuContainer: '.el-scrollbar__view > .el-menu',
|
||||||
menuItems: '.el-sub-menu__title, .el-menu-item', // 菜单项
|
menuItems: '.el-sub-menu__title, .el-menu-item',
|
||||||
menuItemText: '.titleSpan', // 菜单项文本
|
menuItemText: '.titleSpan',
|
||||||
firstLevelIndicator: '.menuIcon', // 一级菜单指示器
|
firstLevelIndicator: '.menuIcon',
|
||||||
thirdLevelMenu: '.el-popper.is-light.el-popover .menuTitle.canClick', // 三级菜单项
|
thirdLevelMenu: '.el-popper.is-light.el-popover .menuTitle.canClick',
|
||||||
thirdLevelIndicator: '.el-icon-arrow-right', // 三级菜单指示器(箭头图标)
|
thirdLevelIndicator: '.el-icon-arrow-right',
|
||||||
subMenuIndicator: '.el-sub-menu__icon-arrow' // 子菜单指示器
|
subMenuIndicator: '.el-sub-menu__icon-arrow',
|
||||||
|
// Tab相关
|
||||||
|
tabContainer: '.workSpaceBaseTab .el-tabs__item',
|
||||||
|
activeTab: '.vab-tabs .el-tabs--card .el-tabs__item.is-active',
|
||||||
|
closeButton: '.el-icon.is-icon-close',
|
||||||
|
// 加载状态
|
||||||
|
loadingMask: '.el-loading-mask',
|
||||||
|
errorBox: '.el-message-box__message',
|
||||||
|
errorMessage: '.el-message--error',
|
||||||
|
// 临时元素
|
||||||
|
temporaryElements: '.el-loading-mask, .el-message, .el-message-box'
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 设置超时时间
|
/**
|
||||||
this.timeout = 10000;
|
* 初始化配置
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
initializeConfig() {
|
||||||
|
this.config = {
|
||||||
|
timeout: 10000,
|
||||||
|
pageLoad: {
|
||||||
|
maxRetries: 30,
|
||||||
|
retryInterval: 500,
|
||||||
|
stabilityDelay: 1000
|
||||||
|
},
|
||||||
|
menuTimeout: parseInt(process.env.MENU_TIME_OUT || '30000', 10)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待指定时间
|
||||||
|
* @param {number} ms 等待时间(毫秒)
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async wait(ms) {
|
||||||
|
await this.page.waitForTimeout(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查元素是否存在
|
||||||
|
* @param {string} selector 元素选择器
|
||||||
|
* @returns {Promise<boolean>} 是否存在
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async elementExists(selector) {
|
||||||
|
const count = await this.page.locator(selector).count();
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取元素文本
|
||||||
|
* @param {Object} element Playwright元素对象
|
||||||
|
* @returns {Promise<string>} 元素文本
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async getElementText(element) {
|
||||||
|
try {
|
||||||
|
const text = await element.textContent();
|
||||||
|
return text.trim();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取元素文本失败:', error.message);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,27 +117,16 @@ class LongiMainPage extends BasePage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 点击展开菜单
|
* 点击展开菜单
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
*/
|
||||||
async clickExpandMenu() {
|
async clickExpandMenu() {
|
||||||
try {
|
|
||||||
// 尝试查找菜单切换按钮
|
|
||||||
const toggleButton = this.page.locator(this.selectors.menuToggle).first();
|
const toggleButton = this.page.locator(this.selectors.menuToggle).first();
|
||||||
|
if (!await this.waitForElement(this.selectors.menuToggle, { returnBoolean: true, firstOnly: true })) {
|
||||||
// 检查按钮是否可见
|
|
||||||
const isVisible = await toggleButton.isVisible().catch(() => false);
|
|
||||||
if (!isVisible) {
|
|
||||||
console.log('菜单切换按钮不可见,尝试其他方法');
|
console.log('菜单切换按钮不可见,尝试其他方法');
|
||||||
// 如果按钮不可见,可以尝试其他方法,比如键盘快捷键或直接修改DOM
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击菜单切换按钮
|
|
||||||
await toggleButton.click();
|
await toggleButton.click();
|
||||||
console.log('已点击展开菜单');
|
console.log('已点击展开菜单');
|
||||||
} catch (error) {
|
|
||||||
console.error('点击展开菜单时出错:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -334,33 +389,6 @@ class LongiMainPage extends BasePage {
|
|||||||
return menuItem;
|
return menuItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行内存回收
|
|
||||||
* @param {string} context 执行内存回收的上下文信息,用于日志
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
async cleanupMemory(context = '') {
|
|
||||||
try {
|
|
||||||
await this.page.evaluate(() => {
|
|
||||||
// 清理DOM中的临时元素
|
|
||||||
const cleanup = () => {
|
|
||||||
const elements = document.querySelectorAll('.el-loading-mask, .el-message, .el-message-box');
|
|
||||||
elements.forEach(el => el.remove());
|
|
||||||
|
|
||||||
// 如果浏览器支持手动垃圾回收,则执行
|
|
||||||
if (window.gc) {
|
|
||||||
window.gc();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
cleanup();
|
|
||||||
});
|
|
||||||
console.log(`🧹 执行内存回收${context ? ` - ${context}` : ''}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('执行内存回收时出错:', error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取三级菜单列表
|
* 获取三级菜单列表
|
||||||
* @param {Object} parentMenu 父级菜单对象
|
* @param {Object} parentMenu 父级菜单对象
|
||||||
@ -432,25 +460,33 @@ class LongiMainPage extends BasePage {
|
|||||||
* @param {Object} parentMenu 父级菜单(可选)
|
* @param {Object} parentMenu 父级菜单(可选)
|
||||||
*/
|
*/
|
||||||
async handleMenuClick(menuInfo, parentMenu = null) {
|
async handleMenuClick(menuInfo, parentMenu = null) {
|
||||||
const menuPath = parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
|
const menuPath = this.getMenuPath(menuInfo, parentMenu);
|
||||||
console.log(`点击菜单: ${menuPath}`);
|
console.log(`点击菜单: ${menuPath}`);
|
||||||
|
|
||||||
// 1. 点击菜单并等待页面加载
|
if (!await this.safeClick(menuInfo.element, menuPath)) {
|
||||||
await menuInfo.element.click();
|
return;
|
||||||
const isLoaded = await this.waitForPageLoadWithRetry(menuInfo);
|
}
|
||||||
|
|
||||||
if (!isLoaded) {
|
if (!await this.waitForPageLoadWithRetry(menuInfo)) {
|
||||||
console.warn(`页面加载失败: ${menuPath}`);
|
console.warn(`页面加载失败: ${menuPath}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 处理页面中的标签页
|
|
||||||
await this.handleAllTabs(menuInfo);
|
await this.handleAllTabs(menuInfo);
|
||||||
|
|
||||||
// 3. 关闭当前标签页
|
|
||||||
await this.closeActiveTab(menuPath);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理单个TAB页
|
* 处理单个TAB页
|
||||||
* @param {Object} tabInfo TAB页信息对象
|
* @param {Object} tabInfo TAB页信息对象
|
||||||
@ -474,28 +510,17 @@ class LongiMainPage extends BasePage {
|
|||||||
*/
|
*/
|
||||||
async handleAllTabs(menu) {
|
async handleAllTabs(menu) {
|
||||||
try {
|
try {
|
||||||
// 等待TAB容器加载
|
await this.wait(1000);
|
||||||
await this.page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
// 使用更精确的选择器获取工作区的TAB页
|
const tabs = await this.page.locator(this.selectors.tabContainer).all();
|
||||||
const tabs = await this.page.locator('.workSpaceBaseTab .el-tabs__item').all();
|
|
||||||
if (tabs.length === 0) {
|
if (tabs.length === 0) {
|
||||||
console.log(`📝 ${menu.text} 没有TAB页`);
|
console.log(`📝 ${menu.text} 没有TAB页`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`📑 ${menu.text} 找到 ${tabs.length} 个TAB页`);
|
console.log(`📑 ${menu.text} 找到 ${tabs.length} 个TAB页`);
|
||||||
|
const tabInfos = await this.getTabInfos(tabs);
|
||||||
|
|
||||||
// 获取所有TAB页的完整信息
|
|
||||||
const tabInfos = await Promise.all(
|
|
||||||
tabs.map(async element => ({
|
|
||||||
text: (await element.textContent()).trim(),
|
|
||||||
isActive: await element.evaluate(el => el.classList.contains('is-active')),
|
|
||||||
element: element
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
// 处理每个非激活的TAB页
|
|
||||||
for (const tabInfo of tabInfos) {
|
for (const tabInfo of tabInfos) {
|
||||||
if (!tabInfo.isActive) {
|
if (!tabInfo.isActive) {
|
||||||
await this.handleSingleTab(tabInfo, menu);
|
await this.handleSingleTab(tabInfo, menu);
|
||||||
@ -508,6 +533,22 @@ class LongiMainPage extends BasePage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取TAB页信息
|
||||||
|
* @param {Array<Object>} tabs TAB页元素数组
|
||||||
|
* @returns {Promise<Array>} TAB页信息数组
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async getTabInfos(tabs) {
|
||||||
|
return Promise.all(
|
||||||
|
tabs.map(async element => ({
|
||||||
|
text: await this.getElementText(element),
|
||||||
|
isActive: await element.evaluate(el => el.classList.contains('is-active')),
|
||||||
|
element: element
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 等待页面加载完成,带重试机制
|
* 等待页面加载完成,带重试机制
|
||||||
* @param {Object} menu 菜单对象
|
* @param {Object} menu 菜单对象
|
||||||
@ -515,61 +556,59 @@ class LongiMainPage extends BasePage {
|
|||||||
* @returns {Promise<boolean>} 页面是否加载成功
|
* @returns {Promise<boolean>} 页面是否加载成功
|
||||||
*/
|
*/
|
||||||
async waitForPageLoadWithRetry(menu, subMenuText = '') {
|
async waitForPageLoadWithRetry(menu, subMenuText = '') {
|
||||||
const pageName = subMenuText ? `${menu.text} > ${subMenuText}` : menu.text;
|
const pageName = this.getMenuPath(menu, { text: subMenuText });
|
||||||
console.log(`等待页面 ${pageName} 数据加载...`);
|
console.log(`等待页面 ${pageName} 数据加载...`);
|
||||||
|
|
||||||
const config = {
|
|
||||||
maxRetries: 30,
|
|
||||||
retryInterval: 500,
|
|
||||||
stabilityDelay: 1000
|
|
||||||
};
|
|
||||||
|
|
||||||
let retryCount = 0;
|
let retryCount = 0;
|
||||||
|
const { maxRetries, retryInterval, stabilityDelay } = this.config.pageLoad;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (retryCount < config.maxRetries) {
|
while (retryCount < maxRetries) {
|
||||||
// 检查页面状态
|
|
||||||
const selectors = {
|
|
||||||
loadingMask: '.el-loading-mask',
|
|
||||||
errorBox: '.el-message-box__message',
|
|
||||||
errorMessage: '.el-message--error'
|
|
||||||
};
|
|
||||||
|
|
||||||
// 检查错误状态
|
// 检查错误状态
|
||||||
for (const [key, selector] of Object.entries(selectors)) {
|
const hasError = await this.checkPageError(pageName);
|
||||||
const elements = await this.page.locator(selector).all();
|
if (hasError) return false;
|
||||||
if (elements.length > 0 && key !== 'loadingMask') {
|
|
||||||
const errorText = await elements[0].textContent();
|
|
||||||
console.error(`页面加载出现错误: ${pageName}, 错误信息: ${errorText}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查加载状态
|
// 检查加载状态
|
||||||
const loadingMasks = await this.page.locator(selectors.loadingMask).all();
|
const isLoading = await this.elementExists(this.selectors.loadingMask);
|
||||||
if (loadingMasks.length === 0) {
|
if (!isLoading) {
|
||||||
// 加载完成,等待页面稳定
|
await this.wait(stabilityDelay);
|
||||||
await this.page.waitForTimeout(config.stabilityDelay);
|
|
||||||
console.log(`✅ 页面 ${pageName} 加载完成`);
|
console.log(`✅ 页面 ${pageName} 加载完成`);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 继续等待
|
|
||||||
retryCount++;
|
retryCount++;
|
||||||
await this.page.waitForTimeout(config.retryInterval);
|
await this.wait(retryInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 超时处理
|
console.error(`页面加载超时: ${pageName}, 重试次数: ${maxRetries}`);
|
||||||
console.error(`页面加载超时: ${pageName}, 重试次数: ${config.maxRetries}`);
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 任何错误都记录并返回false
|
|
||||||
console.error(`页面加载出错: ${pageName}, 错误信息: ${error.message}`);
|
console.error(`页面加载出错: ${pageName}, 错误信息: ${error.message}`);
|
||||||
return false;
|
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 页面名称,用于日志显示
|
* @param {string} pageName 页面名称,用于日志显示
|
||||||
@ -578,16 +617,13 @@ class LongiMainPage extends BasePage {
|
|||||||
try {
|
try {
|
||||||
console.log(`🗑️ 正在关闭页面 "${pageName}" 的tab...`);
|
console.log(`🗑️ 正在关闭页面 "${pageName}" 的tab...`);
|
||||||
|
|
||||||
const activeTab = this.page.locator('.vab-tabs .el-tabs--card .el-tabs__item.is-active');
|
const activeTab = this.page.locator(this.selectors.activeTab);
|
||||||
const closeButton = activeTab.locator('.el-icon.is-icon-close');
|
const closeButton = activeTab.locator(this.selectors.closeButton);
|
||||||
|
|
||||||
const hasActiveTab = await activeTab.count() > 0;
|
if (await this.canCloseTab(activeTab, closeButton)) {
|
||||||
const hasCloseButton = await closeButton.count() > 0;
|
|
||||||
|
|
||||||
if (hasActiveTab && hasCloseButton) {
|
|
||||||
await closeButton.waitFor({state: 'visible', timeout: 5000});
|
await closeButton.waitFor({state: 'visible', timeout: 5000});
|
||||||
await closeButton.click();
|
await this.safeClick(closeButton, `${pageName}的关闭按钮`);
|
||||||
await this.page.waitForTimeout(500);
|
await this.wait(500);
|
||||||
} else {
|
} else {
|
||||||
console.log(`⚠️ [${pageName}] 没有找到可关闭的tab,继续执行...`);
|
console.log(`⚠️ [${pageName}] 没有找到可关闭的tab,继续执行...`);
|
||||||
}
|
}
|
||||||
@ -595,6 +631,37 @@ class LongiMainPage extends BasePage {
|
|||||||
console.error(`关闭标签页时出错 [${pageName}]:`, error.message);
|
console.error(`关闭标签页时出错 [${pageName}]:`, error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否可以关闭标签页
|
||||||
|
* @param {Object} activeTab 活动标签页元素
|
||||||
|
* @param {Object} closeButton 关闭按钮元素
|
||||||
|
* @returns {Promise<boolean>} 是否可以关闭
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async canCloseTab(activeTab, closeButton) {
|
||||||
|
const hasActiveTab = await activeTab.count() > 0;
|
||||||
|
const hasCloseButton = await closeButton.count() > 0;
|
||||||
|
return hasActiveTab && hasCloseButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行内存回收
|
||||||
|
* @param {string} context 执行内存回收的上下文信息
|
||||||
|
*/
|
||||||
|
async cleanupMemory(context = '') {
|
||||||
|
try {
|
||||||
|
await this.page.evaluate((selector) => {
|
||||||
|
const elements = document.querySelectorAll(selector);
|
||||||
|
elements.forEach(el => el.remove());
|
||||||
|
if (window.gc) window.gc();
|
||||||
|
}, this.selectors.temporaryElements);
|
||||||
|
|
||||||
|
console.log(`🧹 执行内存回收${context ? ` - ${context}` : ''}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('执行内存回收时出错:', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = LongiMainPage;
|
module.exports = LongiMainPage;
|
||||||
@ -28,12 +28,28 @@ class BasePage {
|
|||||||
* 等待元素可见
|
* 等待元素可见
|
||||||
* @param {string} selector 元素选择器
|
* @param {string} selector 元素选择器
|
||||||
* @param {Object} options 选项
|
* @param {Object} options 选项
|
||||||
* @returns {Promise<import('@playwright/test').Locator>} 元素定位器
|
* @param {boolean} [options.returnBoolean=false] 是否返回布尔值而不是元素
|
||||||
|
* @param {boolean} [options.firstOnly=false] 是否只获取第一个元素
|
||||||
|
* @returns {Promise<import('@playwright/test').Locator|boolean>} 元素定位器或是否可见
|
||||||
*/
|
*/
|
||||||
async waitForElement(selector, options = {}) {
|
async waitForElement(selector, options = {}) {
|
||||||
const element = this.page.locator(selector);
|
try {
|
||||||
await element.waitFor({state: 'visible', timeout: options.timeout || this.timeout});
|
const element = options.firstOnly ?
|
||||||
return element;
|
this.page.locator(selector).first() :
|
||||||
|
this.page.locator(selector);
|
||||||
|
|
||||||
|
await element.waitFor({
|
||||||
|
state: 'visible',
|
||||||
|
timeout: options.timeout || this.timeout
|
||||||
|
});
|
||||||
|
|
||||||
|
return options.returnBoolean ? true : element;
|
||||||
|
} catch (error) {
|
||||||
|
if (options.returnBoolean) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,6 +161,22 @@ class BasePage {
|
|||||||
const element = await this.waitForElement(selector);
|
const element = await this.waitForElement(selector);
|
||||||
return element.getAttribute(attributeName);
|
return element.getAttribute(attributeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全点击元素
|
||||||
|
* @param {Object} element Playwright元素对象
|
||||||
|
* @param {string} description 元素描述,用于日志
|
||||||
|
* @returns {Promise<boolean>} 是否点击成功
|
||||||
|
*/
|
||||||
|
async safeClick(element, description) {
|
||||||
|
try {
|
||||||
|
await element.click();
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`点击${description}失败:`, error.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BasePage;
|
module.exports = BasePage;
|
||||||
Loading…
Reference in New Issue
Block a user