From 08910deeed650a0412020d11bc70ae621eeb0dc9 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Thu, 6 Mar 2025 09:27:38 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/pages/LongiMainPage.js | 347 +++++++---------------------------- 1 file changed, 69 insertions(+), 278 deletions(-) diff --git a/tests/pages/LongiMainPage.js b/tests/pages/LongiMainPage.js index 4a09b6e..8c63f43 100644 --- a/tests/pages/LongiMainPage.js +++ b/tests/pages/LongiMainPage.js @@ -263,224 +263,6 @@ class LongiMainPage extends BasePage { } } - /** - * 通过索引查找菜单项 - * @param {number} index 菜单项索引 - * @param {Array} menuItems 菜单项数组,如果未提供则会调用findMenuItems获取 - * @returns {Promise} 找到的菜单项或null - */ - async findMenuItemByIndex(index, menuItems = null) { - try { - // 如果未提供菜单项数组,则获取 - if (!menuItems) { - menuItems = await this.findMenuItems(); - } - - // 查找指定索引的菜单项 - const menuItem = menuItems.find(item => item.index === index); - - if (menuItem) { - console.log(`通过索引 ${index} 找到菜单项: "${menuItem.text}"`); - return menuItem; - } else { - console.log(`未找到索引为 ${index} 的菜单项`); - return null; - } - } catch (error) { - console.error(`通过索引查找菜单项时出错: ${error}`); - return null; - } - } - - /** - * 通过文本和可选的索引查找菜单项 - * 当有多个同名菜单项时,可以通过指定occurrence来选择第几个匹配项 - * @param {string} text 菜单项文本 - * @param {number} occurrence 第几个匹配项,从0开始计数,默认为0(第一个) - * @param {Array} menuItems 菜单项数组,如果未提供则会调用findMenuItems获取 - * @returns {Promise} 找到的菜单项或null - */ - async findMenuItemByText(text, occurrence = 0, menuItems = null) { - try { - // 如果未提供菜单项数组,则获取 - if (!menuItems) { - menuItems = await this.findMenuItems(); - } - - // 查找所有匹配文本的菜单项 - const matchingItems = menuItems.filter(item => item.text === text); - - if (matchingItems.length > 0) { - if (occurrence < matchingItems.length) { - const menuItem = matchingItems[occurrence]; - console.log(`通过文本 "${text}" 找到第 ${occurrence + 1} 个菜单项,索引为 ${menuItem.index}`); - return menuItem; - } else { - console.log(`未找到第 ${occurrence + 1} 个文本为 "${text}" 的菜单项,只有 ${matchingItems.length} 个匹配项`); - return null; - } - } else { - console.log(`未找到文本为 "${text}" 的菜单项`); - return null; - } - } catch (error) { - console.error(`通过文本查找菜单项时出错: ${error}`); - return null; - } - } - - /** - * 通过唯一ID查找菜单项 - * @param {string} uniqueId 菜单项的唯一ID - * @param {Array} menuItems 菜单项数组,如果未提供则会调用findMenuItems获取 - * @returns {Promise} 找到的菜单项或null - */ - async findMenuItemByUniqueId(uniqueId, menuItems = null) { - try { - // 如果未提供菜单项数组,则获取 - if (!menuItems) { - menuItems = await this.findMenuItems(); - } - - // 查找指定唯一ID的菜单项 - const menuItem = menuItems.find(item => item.uniqueId === uniqueId); - - if (menuItem) { - console.log(`通过唯一ID ${uniqueId} 找到菜单项: "${menuItem.text}"`); - return menuItem; - } else { - console.log(`未找到唯一ID为 ${uniqueId} 的菜单项`); - return null; - } - } catch (error) { - console.error(`通过唯一ID查找菜单项时出错: ${error}`); - return null; - } - } - - /** - * 检查是否存在三级菜单并进行相应处理 - * @param {Object} menuItem 菜单项对象,包含索引、文本和元素 - * @param {number} timeout 超时时间(毫秒),默认30秒 - * @returns {Promise<{hasThirdMenu: boolean, thirdMenuItems: Array}>} 是否有三级菜单及三级菜单项数组 - */ - async checkForThirdLevelMenu(menuItem, timeout = 30000) { - try { - console.log(`点击菜单项 "${menuItem.text}" 检查三级菜单...`); - - // 点击菜单项,触发三级菜单弹出 - await menuItem.element.click(); - - // 等待弹出动画完成,增加等待时间 - await this.page.waitForTimeout(2000); - - // 检查三级菜单 - const thirdMenuSelector = this.selectors.thirdLevelMenu; - - // 尝试等待三级菜单出现,但不抛出错误 - const hasThirdMenu = await this.page.locator(thirdMenuSelector).count().then(count => count > 0).catch(() => false); - - // 如果没有立即找到,再等待一段时间再次检查 - let thirdMenuCount = 0; - if (hasThirdMenu) { - thirdMenuCount = await this.page.locator(thirdMenuSelector).count(); - } else { - // 再等待一段时间,有些菜单可能加载较慢 - await this.page.waitForTimeout(1000); - thirdMenuCount = await this.page.locator(thirdMenuSelector).count(); - } - - console.log(`菜单项 "${menuItem.text}" ${thirdMenuCount > 0 ? '有' : '没有'}三级菜单,找到 ${thirdMenuCount} 个三级菜单项`); - - // 如果没有三级菜单,直接返回 - if (thirdMenuCount === 0) { - return {hasThirdMenu: false, thirdMenuItems: []}; - } - - // 收集三级菜单项 - const thirdMenuItems = []; - for (let i = 0; i < thirdMenuCount; i++) { - const item = this.page.locator(thirdMenuSelector).nth(i); - const text = await item.textContent(); - - thirdMenuItems.push({ - index: i, - text: text.trim(), - element: item - }); - } - - // 输出三级菜单项文本 - const menuTexts = thirdMenuItems.map(item => item.text).join(', '); - console.log(`三级菜单项: ${menuTexts}`); - - return {hasThirdMenu: true, thirdMenuItems}; - } catch (error) { - console.error(`检查三级菜单时出错: ${error}`); - return {hasThirdMenu: false, thirdMenuItems: []}; - } - } - - /** - * 处理菜单项,包括检查和处理可能的三级菜单 - * @param {Object} menuItem 菜单项对象,包含索引、文本和元素以及hasThirdMenu标志 - * @param {Function} processWithThirdMenu 处理有三级菜单情况的回调函数 - * @param {Function} processWithoutThirdMenu 处理没有三级菜单情况的回调函数 - * @returns {Promise<{hasThirdMenu: boolean, thirdMenuItems: Array}>} 处理结果 - */ - async processMenuItem(menuItem, processWithThirdMenu = null, processWithoutThirdMenu = null) { - try { - console.log(`处理菜单项: "${menuItem.text}"`); - - // 使用菜单项中的hasThirdMenu字段 - const hasThirdMenu = menuItem.hasThirdMenu; - - // 点击菜单项 - await menuItem.element.click(); - await this.page.waitForTimeout(1000); // 等待可能的动画完成 - - let thirdMenuItems = []; - - // 如果有三级菜单,获取三级菜单项 - if (hasThirdMenu) { - const thirdMenuSelector = this.selectors.thirdLevelMenu; - const thirdMenuCount = await this.page.locator(thirdMenuSelector).count(); - - console.log(`菜单项 "${menuItem.text}" 有三级菜单,找到 ${thirdMenuCount} 个三级菜单项`); - - // 收集三级菜单项 - for (let i = 0; i < thirdMenuCount; i++) { - const item = this.page.locator(thirdMenuSelector).nth(i); - const text = await item.textContent(); - - thirdMenuItems.push({ - index: i, - text: text.trim(), - element: item - }); - } - - // 输出三级菜单项文本 - const menuTexts = thirdMenuItems.map(item => item.text).join(', '); - console.log(`三级菜单项: ${menuTexts}`); - } else { - console.log(`菜单项 "${menuItem.text}" 没有三级菜单`); - } - - // 根据是否有三级菜单调用相应的处理函数 - if (hasThirdMenu && processWithThirdMenu) { - await processWithThirdMenu(menuItem, thirdMenuItems); - } else if (!hasThirdMenu && processWithoutThirdMenu) { - await processWithoutThirdMenu(menuItem); - } - - return {hasThirdMenu, thirdMenuItems}; - } catch (error) { - console.error(`处理菜单项时出错: ${error}`); - return {hasThirdMenu: false, thirdMenuItems: []}; - } - } - async handleAllMenuClicks(menuItems) { for (let i = 0; i < menuItems.length; i++) { await this.handleSingleMenuClick(menuItems[i]); @@ -547,6 +329,33 @@ class LongiMainPage extends BasePage { } } + /** + * 执行内存回收 + * @param {string} context 执行内存回收的上下文信息,用于日志 + * @returns {Promise} + * @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); + } + } + async handleSingleMenuClick(menu) { try { await this.expandSideMenu(); @@ -566,20 +375,7 @@ class LongiMainPage extends BasePage { } // 执行内存回收 - 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(`🧹 执行内存回收 - ${menu.text}`); + await this.cleanupMemory(menu.text); } catch (error) { console.error(`处理菜单失败 [${menu.text}]:`, error.message); @@ -723,58 +519,59 @@ class LongiMainPage extends BasePage { * @param {Object} menu 菜单对象 */ async handleThreeLevelMenu(menu) { - try { - console.log(`正在处理 ${menu.text} 菜单`); - await menu.element.click(); + console.log(`处理三级菜单: ${menu.text}`); - // 等待一个短暂的时间让弹出层出现 - await this.page.waitForTimeout(500); + // 1. 点击展开三级菜单 + await menu.element.click(); + await this.page.waitForTimeout(500); - // 获取三级菜单列表 - const thirdMenus = await this.getThirdLevelMenus(menu); + // 2. 获取三级菜单列表 + const thirdMenus = await this.getThirdLevelMenus(menu); + if (thirdMenus.length === 0) { + console.log(`未找到三级菜单项`); + return; + } - // 这里可以根据需要处理三级菜单项 - for (const thirdMenu of thirdMenus) { - await this.handleMenuClick(thirdMenu, menu); + // 3. 处理每个三级菜单项 + for (let i = 0; i < thirdMenus.length; i++) { + const thirdMenu = thirdMenus[i]; + console.log(`处理第 ${i + 1}/${thirdMenus.length} 个三级菜单项: ${thirdMenu.text}`); - // 如果不是最后一个菜单项,需要重新点击父菜单展开三级菜单 - if (thirdMenu !== thirdMenus[thirdMenus.length - 1]) { - await menu.element.click(); - await this.page.waitForTimeout(500); - } + await this.handleMenuClick(thirdMenu, menu); + + // 如果还有下一个菜单项,重新展开三级菜单 + if (i < thirdMenus.length - 1) { + await menu.element.click(); + await this.page.waitForTimeout(500); } - - } catch (error) { - console.error(`处理三级菜单时出错 [${menu.text}]:`, error.message); - throw error; } } /** - * 通用的菜单点击和页面加载处理方法 - * @param {Object} menuInfo 菜单信息对象,包含text属性 + * 处理菜单点击和页面加载 + * @param {Object} menuInfo 菜单信息对象 * @param {Object} parentMenu 父级菜单(可选) - * @returns {Promise} 处理是否成功 */ - async handleMenuClick(menuInfo, parentMenu) { - try { - const menuPath = parentMenu.text ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text; - console.log(`🔸 点击菜单: ${menuPath}`); - await menuInfo.element.click(); - // 等待页面加载 - const loadResult = await this.waitForPageLoadWithRetry(menuInfo); - if (loadResult) { - // 处理所有TAB页 - await this.handleAllTabs(menuInfo); + async handleMenuClick(menuInfo, parentMenu = null) { + const menuPath = parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text; + console.log(`点击菜单: ${menuPath}`); - // 关闭标签页 - await this.closeActiveTab(menuPath); - } - return true; - } catch (error) { - console.error(`处理菜单点击失败 [${menuInfo.text}]:`, error.message); + // 1. 点击菜单并等待页面加载 + await menuInfo.element.click(); + const loadResult = await this.waitForPageLoadWithRetry(menuInfo); + + if (!loadResult) { + console.warn(`页面加载失败: ${menuPath}`); return false; } + + // 2. 处理页面中的标签页 + await this.handleAllTabs(menuInfo); + + // 3. 关闭当前标签页 + await this.closeActiveTab(menuPath); + + return true; } /** @@ -792,14 +589,7 @@ class LongiMainPage extends BasePage { // 直接使用传入的element点击 await tabInfo.element.click(); - // 等待页面加载 - const loadResult = await this.waitForPageLoadWithRetry(parentMenu, tabInfo.text); - if (!loadResult) { - console.warn('页面加载失败'); - return false; - } - - return true; + return !await this.waitForPageLoadWithRetry(parentMenu, tabInfo.text); } catch (error) { console.error(`处理TAB页失败 [${parentMenu.text} > ${tabInfo.text}]:`, error.message); return false; @@ -851,6 +641,7 @@ class LongiMainPage extends BasePage { return false; } } + } module.exports = LongiMainPage; \ No newline at end of file