From d12e39ff3aae1d35be107f328e859ec0909f9d4b Mon Sep 17 00:00:00 2001 From: dengqichen Date: Mon, 3 Mar 2025 18:10:29 +0800 Subject: [PATCH] aaaaaaaaaa --- cypress.config.js | 50 +- cypress/e2e/需求计划页面是否可用.cy.js | 931 ++++++++++-------------- cypress/e2e/需求计划页面是否可用1.cy.js | 217 ++++-- 3 files changed, 555 insertions(+), 643 deletions(-) diff --git a/cypress.config.js b/cypress.config.js index 09d4150..35b94fe 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -59,7 +59,7 @@ module.exports = { createReportDir(dirPath) { try { if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { recursive: true }); + fs.mkdirSync(dirPath, {recursive: true}); } return null; } catch (e) { @@ -73,7 +73,7 @@ module.exports = { const reportsDir = path.join(__dirname, 'cypress', 'reports'); const reports = []; const files = fs.readdirSync(reportsDir); - + files.forEach(file => { if (file.startsWith(`${environment}-menu-test-report-batch-`) && file.endsWith('.json')) { const filePath = path.join(reportsDir, file); @@ -81,7 +81,7 @@ module.exports = { reports.push(JSON.parse(content)); } }); - + return reports; } catch (e) { console.error('Read reports failed:', e); @@ -93,13 +93,13 @@ module.exports = { try { const reportsDir = path.join(__dirname, 'cypress', 'reports'); const files = fs.readdirSync(reportsDir); - + files.forEach(file => { if (file.startsWith(`${environment}-menu-test-report-batch-`) && file.endsWith('.json')) { fs.unlinkSync(path.join(reportsDir, file)); } }); - + return null; } catch (e) { console.error('Cleanup reports failed:', e); @@ -107,11 +107,11 @@ module.exports = { } }, - saveReport({ data, filename }) { + saveReport({data, filename}) { try { const reportsDir = path.join(__dirname, 'cypress', 'reports'); if (!fs.existsSync(reportsDir)) { - fs.mkdirSync(reportsDir, { recursive: true }); + fs.mkdirSync(reportsDir, {recursive: true}); } fs.writeFileSync( path.join(reportsDir, filename), @@ -122,9 +122,43 @@ module.exports = { console.error('Save report failed:', e); return null; } + }, + getLatestDataFile() { + const fixturesDir = path.join(__dirname, 'cypress/fixtures'); + + try { + // 读取fixtures目录 + const files = fs.readdirSync(fixturesDir); + + // 过滤出数据文件 + const dataFiles = files.filter(file => + file.includes('-data-') && file.endsWith('.json') + ); + + if (dataFiles.length === 0) { + return null; // 没有找到数据文件 + } + + // 按文件名倒序排序 + dataFiles.sort().reverse(); + + const latestFile = dataFiles[0]; + + // 读取文件内容 + const fileContent = JSON.parse( + fs.readFileSync(path.join(fixturesDir, latestFile), 'utf8') + ); + + return { + filename: latestFile, + content: fileContent + }; + } catch (error) { + console.error('读取数据文件时出错:', error); + return null; + } } }); - return config; }, }, diff --git a/cypress/e2e/需求计划页面是否可用.cy.js b/cypress/e2e/需求计划页面是否可用.cy.js index ca16bcc..d42202a 100644 --- a/cypress/e2e/需求计划页面是否可用.cy.js +++ b/cypress/e2e/需求计划页面是否可用.cy.js @@ -7,38 +7,6 @@ describe('隆基系统全部页面验证', () => { }); }); - // 每个测试用例结束后清理内存 - afterEach(() => { - cleanupMemory(); - }); - - // 创建通用对话框模板函数 - const createDialogTemplate = (options) => { - const { - dialogClass, - title, - width, - bodyContent, - footerContent - } = options; - - return ` -
-
-
- ${title} -
-
- ${bodyContent} -
- -
-
- `; - }; - // 格式化时间的辅助函数 const formatTime = (date) => { return date.toLocaleString('zh-CN', { @@ -77,7 +45,7 @@ describe('隆基系统全部页面验证', () => { // 添加环境选择和登录处理函数 const handleLogin = (environment) => { const envConfig = ENV_CONFIG[environment]; - + cy.visit(envConfig.url); // 忽略未捕获的异常 Cypress.on('uncaught:exception', (err, runnable) => false); @@ -88,7 +56,7 @@ describe('隆基系统全部页面验证', () => { // 清空输入框 cy.get('input[name="username"]').clear(); cy.get('input[name="passWord"]').clear(); - + // 输入账号密码 cy.get('input[name="username"]').type(envConfig.username); cy.get('input[name="passWord"]').type(envConfig.password); @@ -106,33 +74,34 @@ describe('隆基系统全部页面验证', () => { let envSelected = false; cy.visit('https://ibp-dev.longi.com/main/#/login'); - + // 忽略未捕获的异常 Cypress.on('uncaught:exception', (err, runnable) => false); // 创建环境选择对话框 - const envDialogBodyContent = ` -
- 请选择要测试的环境 -
-
- - + const dialogHtml = ` +
+
+
+ 选择测试环境 +
+
+
+ 请选择要测试的环境 +
+
+ + +
+
+
`; - const dialogHtml = createDialogTemplate({ - dialogClass: 'env-select-dialog', - title: '选择测试环境', - width: '400px', - bodyContent: envDialogBodyContent, - footerContent: '' - }); - // 添加对话框到页面 cy.get('body').then($body => { $body.append(dialogHtml); @@ -185,101 +154,39 @@ describe('隆基系统全部页面验证', () => { } }; - // 优化内存清理函数,确保与Cypress命令链兼容 + // 每个测试用例前不再重新访问登录页 + // beforeEach(() => { + // // 只设置异常处理 + // Cypress.on('uncaught:exception', (err, runnable) => false); + // }); + + // 添加内存清理的公共方法 const cleanupMemory = () => { - cy.log('🧹 执行内存清理...'); - - // 记录清理前的内存使用情况 - cy.window({log: false}).then(win => { - if (win.performance && win.performance.memory) { - const beforeMemory = Math.round(win.performance.memory.usedJSHeapSize / 1024 / 1024); - cy.log(`清理前内存使用: ${beforeMemory}MB`); - } - - // 执行内存清理操作 - try { - // 1. 清理DOM元素 - const elementsToRemove = [ - '.el-loading-mask', - '.el-message', - '.el-message-box:not(.is-message)', - '.el-notification', - '.el-drawer__wrapper:not(.active)', - '.el-tooltip__popper', - '.el-select-dropdown', - '.el-popover', - '.el-dropdown-menu', - '.v-modal' - ]; - - elementsToRemove.forEach(selector => { - if (Cypress.$(selector).length > 0) { - Cypress.$(selector).remove(); - } - }); - - // 2. 清理iframe内容 - Cypress.$('iframe').each((_, el) => { - try { - el.src = 'about:blank'; - } catch (e) { - // 忽略错误 - } - }); - - // 3. 清理大型表格内容 - Cypress.$('.el-table__body tr').each((index, el) => { - if (index > 20) { - Cypress.$(el).remove(); - } - }); - - // 4. 清理事件监听器(保留菜单相关元素) - Cypress.$('*:not(.el-menu):not(.el-menu-item):not(.el-submenu):not(.sidebar-menu):not(.el-scrollbar__view)').each((_, el) => { - try { - const element = Cypress.$(el); - // 只清理非菜单元素的事件 - if (!element.closest('.el-menu, .sidebar-menu').length) { - element.off(); - } - } catch (e) { - // 忽略错误 - } - }); - - // 5. 清理定时器 - let id = window.setTimeout(() => {}, 0); - while (id--) { - window.clearTimeout(id); - window.clearInterval(id); - } - - // 6. 清理Vue相关引用 - if (win.__VUE_DEVTOOLS_GLOBAL_HOOK__) { - win.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue = null; - } - - // 7. 手动触发一些可能的内存释放 - win.dispatchEvent(new Event('beforeunload')); - - // 8. 清理控制台 - console.clear(); - } catch (e) { - console.error('清理DOM时出错:', e); - } - }).then(() => { - // 等待一段时间让垃圾回收生效 - return cy.wait(1000, {log: false}); - }).then(() => { - // 再次检查内存使用情况 - return cy.window({log: false}).then(win => { - if (win.performance && win.performance.memory) { - const afterMemory = Math.round(win.performance.memory.usedJSHeapSize / 1024 / 1024); - cy.log(`清理后内存使用: ${afterMemory}MB`); - } - cy.log('🧹 内存清理完成'); - }); + // 执行垃圾回收 + cy.task('clearMemory', null, {log: false}); + + // 清理DOM快照 + cy.get('body').then(() => { + Cypress.$(document).find('*').off(); + Cypress.$('.el-loading-mask').remove(); + Cypress.$('.el-message').remove(); + Cypress.$('.el-message-box').remove(); + + // 清理可能的内存泄漏 + Cypress.$('iframe').remove(); // 移除所有iframe + Cypress.$('img').remove(); // 移除所有图片 + Cypress.$('video').remove(); // 移除所有视频 + + // 清理事件监听器 + const win = Cypress.$(window); + win.off(); + win.find('*').off(); }); + + // 手动清理一些可能的引用 + if (window.gc) { + window.gc(); + } }; // 添加关闭tab的公共方法 @@ -306,29 +213,20 @@ describe('隆基系统全部页面验证', () => { // 添加报告写入方法 const writeReportBatch = () => { - if (testReport.currentBatch.pages.length === 0) { - return; - } + const batchNumber = Math.floor(testReport.summary.totalPages / 20); // 每20个页面写入一次 + const fileName = `cypress/reports/${selectedEnvironment}-menu-test-report-batch-${batchNumber}.json`; - const batchNumber = Math.floor(Math.random() * 10000); - cy.log(`📊 写入批次报告 ${batchNumber}:`); cy.log(`当前批次页面数: ${testReport.currentBatch.pages.length}`); cy.log(`当前批次失败页面数: ${testReport.currentBatch.failedPages.length}`); - - cy.task('saveReport', { - data: testReport.currentBatch, - filename: `${selectedEnvironment}-menu-test-report-batch-${batchNumber}.json` - }).then(() => { - cy.log(`✅ 批次报告已写入`); - - // 清空当前批次 + + cy.writeFile(fileName, testReport.currentBatch).then(() => { + cy.log(`✅ 批次报告已写入: ${fileName}`); + // 清空当前批次数据,释放内存 testReport.currentBatch = { pages: [], failedPages: [] }; - - // 清理内存 cleanupMemory(); }); }; @@ -403,19 +301,18 @@ describe('隆基系统全部页面验证', () => { cy.log(`\n📑 页面 "${currentPage.name}" 发现 ${$inactiveTabs.length} 个待访问的tab页`); testReport.summary.totalTabs += $inactiveTabs.length; - // 使用迭代方式处理Tab页,避免深度递归 - const processTabsSequentially = (tabs, startIndex = 0) => { - if (startIndex >= tabs.length) { + const processTab = (index = 0) => { + if (index >= $inactiveTabs.length) { cy.log(`✅ 页面 "${currentPage.name}" 的所有tab页处理完成`); - return cy.wrap(null); + return; } - - const $currentTab = Cypress.$(tabs[startIndex]); + + const tabProgress = ((index + 1) / $inactiveTabs.length * 100).toFixed(1); + const $currentTab = Cypress.$($inactiveTabs[index]); const tabText = $currentTab.text().trim(); - const tabProgress = ((startIndex + 1) / tabs.length * 100).toFixed(1); - - cy.log(`🔸 正在处理tab页 [${startIndex + 1}/${tabs.length}] (${tabProgress}%): ${currentPage.name} > ${tabText}`); - + + cy.log(`🔸 正在处理tab页 [${index + 1}/${$inactiveTabs.length}] (${tabProgress}%): ${currentPage.name} > ${tabText}`); + const tabStartTime = new Date(); const tabInfo = { name: tabText, @@ -424,131 +321,142 @@ describe('隆基系统全部页面验证', () => { duration: '', status: 'pending' }; - + if (!currentPage.tabs) { currentPage.tabs = []; } currentPage.tabs.push(tabInfo); - - // 处理单个Tab,然后链式处理下一个 - return cy.wrap($currentTab) - .click({force: true}) - .then(() => { - cy.log(`⏳ [${currentPage.name}] 已点击tab页: ${tabText},等待加载...`); - return waitForTabLoadWithTimeout(currentPage, tabInfo, tabStartTime, 30); - }) - .then(() => { - // 处理下一个Tab - return processTabsSequentially(tabs, startIndex + 1); - }); - }; - - // 等待Tab加载的函数,使用超时机制 - const waitForTabLoadWithTimeout = (currentPage, tabInfo, tabStartTime, maxRetries, retryCount = 0) => { - if (retryCount >= maxRetries) { - cy.log(`❌ [${currentPage.name}] Tab页 ${tabInfo.name} 加载超时 [${retryCount}次重试]`); - updateTabInfo(tabInfo, tabStartTime, 'timeout'); - return cy.wrap(null); - } - - return cy.get('@pageBody').then($body => { - const isLoading = $body.find('.el-loading-mask').length > 0; - const hasTabError = $body.find('.el-message-box__message').length > 0 || - $body.find('.el-message--error').length > 0; - - if (hasTabError) { - cy.log(`❌ [${currentPage.name}] Tab页 ${tabInfo.name} 加载出现错误`); - updateTabInfo(tabInfo, tabStartTime, 'error'); - return cy.wrap(null); - } - - if (isLoading) { - cy.log(`⏳ [${currentPage.name}] Tab页 ${tabInfo.name} 第 ${retryCount + 1} 次检查加载状态...`); - return cy.wait(500).then(() => { - return waitForTabLoadWithTimeout(currentPage, tabInfo, tabStartTime, maxRetries, retryCount + 1); + + cy.wrap($currentTab).click({force: true}).then(() => { + cy.log(`⏳ [${currentPage.name}] 已点击tab页: ${tabText},等待加载...`); + + let tabLoadRetry = 0; + const waitForTabLoad = () => { + if (tabLoadRetry >= 30) { + cy.log(`❌ [${currentPage.name}] Tab页 ${tabText} 加载超时 [${tabLoadRetry}次重试],继续下一个`); + updateTabInfo(tabInfo, tabStartTime, 'timeout'); + processTab(index + 1); + return; + } + + cy.get('@pageBody').then($body => { + const isLoading = $body.find('.el-loading-mask').length > 0; + const hasTabError = $body.find('.el-message-box__message').length > 0 || + $body.find('.el-message--error').length > 0; + + if (hasTabError) { + cy.log(`❌ [${currentPage.name}] Tab页 ${tabText} 加载出现错误`); + updateTabInfo(tabInfo, tabStartTime, 'error'); + processTab(index + 1); + return; + } + + if (isLoading) { + tabLoadRetry++; + cy.log(`⏳ [${currentPage.name}] Tab页 ${tabText} 第 ${tabLoadRetry} 次检查加载状态...`); + cy.wait(500).then(waitForTabLoad); + } else { + updateTabInfo(tabInfo, tabStartTime, 'success'); + cy.log(`✅ [${currentPage.name}] Tab页 ${tabText} 加载完成 (耗时: ${tabInfo.duration}秒)`); + cy.wait(1000).then(() => processTab(index + 1)); + } }); - } else { - updateTabInfo(tabInfo, tabStartTime, 'success'); - cy.log(`✅ [${currentPage.name}] Tab页 ${tabInfo.name} 加载完成 (耗时: ${tabInfo.duration}秒)`); - return cy.wait(1000); - } + }; + + waitForTabLoad(); }); }; - - // 开始处理所有Tab - return processTabsSequentially($inactiveTabs); + + processTab(); }; // 处理页面中的tab页 const processPageTabs = (currentPage, pageStartTime) => { - return cy.get('.workSpaceBaseTab').as('workTabs').then($tabs => { - if ($tabs.length > 0) { - return cy.get('@workTabs').find('.el-tabs__item').as('allTabs').then($allTabs => { - const $activeTab = $allTabs.filter('.is-active'); - const $inactiveTabs = $allTabs.filter(':not(.is-active)').toArray(); - - // 首先处理活动的Tab页,使用页面开始时间 - if ($activeTab.length > 0) { - const activeTabText = $activeTab.text().trim(); - const tabInfo = { - name: activeTabText, - startTime: formatTime(pageStartTime), // 使用页面开始时间作为Tab开始时间 - endTime: '', - duration: '', - status: 'pending' - }; - - if (!currentPage.tabs) { - currentPage.tabs = []; - } - currentPage.tabs.push(tabInfo); - testReport.summary.totalTabs += 1; - - // 检查活动Tab页的加载状态 - let activeTabLoadRetry = 0; - const waitForActiveTabLoad = () => { - if (activeTabLoadRetry >= 30) { - cy.log(`❌ [${currentPage.name}] 活动Tab页 ${activeTabText} 加载超时`); - updateTabInfo(tabInfo, pageStartTime, 'timeout'); - return; + return cy.get('body').then($body => { + const hasWorkTabs = $body.find('.workSpaceBaseTab').length > 0; + if (hasWorkTabs) { + // 如果存在 .workSpaceBaseTab,则按原来的逻辑处理 + return cy.get('.workSpaceBaseTab').as('workTabs').then($tabs => { + if ($tabs.length > 0) { + return cy.get('@workTabs').find('.el-tabs__item').as('allTabs').then($allTabs => { + const $activeTab = $allTabs.filter('.is-active'); + const $inactiveTabs = $allTabs.filter(':not(.is-active)').toArray(); + + // 首先处理活动的Tab页,使用页面开始时间 + if ($activeTab.length > 0) { + const activeTabText = $activeTab.text().trim(); + const tabInfo = { + name: activeTabText, + startTime: formatTime(pageStartTime), // 使用页面开始时间作为Tab开始时间 + endTime: '', + duration: '', + status: 'pending' + }; + + if (!currentPage.tabs) { + currentPage.tabs = []; + } + currentPage.tabs.push(tabInfo); + testReport.summary.totalTabs += 1; + + // 检查活动Tab页的加载状态 + let activeTabLoadRetry = 0; + const waitForActiveTabLoad = () => { + // ... 原有代码 ... + }; + + waitForActiveTabLoad(); } - - cy.get('@pageBody').then($body => { - const isLoading = $body.find('.el-loading-mask').length > 0; - const hasTabError = $body.find('.el-message-box__message').length > 0 || - $body.find('.el-message--error').length > 0; - - if (hasTabError) { - cy.log(`❌ [${currentPage.name}] 活动Tab页 ${activeTabText} 加载出现错误`); - updateTabInfo(tabInfo, pageStartTime, 'error'); - return; - } - - if (isLoading) { - activeTabLoadRetry++; - cy.log(`⏳ [${currentPage.name}] 活动Tab页 ${activeTabText} 第 ${activeTabLoadRetry} 次检查加载状态...`); - cy.wait(500).then(waitForActiveTabLoad); - } else { - updateTabInfo(tabInfo, pageStartTime, 'success'); - cy.log(`✅ [${currentPage.name}] 活动Tab页 ${activeTabText} 加载完成 (耗时: ${tabInfo.duration}秒)`); - } - }); - }; - - waitForActiveTabLoad(); + + // 然后处理其他Tab页 + if ($inactiveTabs.length > 0) { + processMultipleTabs(currentPage, $inactiveTabs); + } else if ($allTabs.length === 1) { + cy.log(`ℹ️ [${currentPage.name}] 只有一个活动的tab页`); + } + + closeActiveTab(currentPage.name); + }); + } else { + cy.log(`ℹ️ [${currentPage.name}] 页面中没有找到workSpaceBaseTab的内容`); + closeActiveTab(currentPage.name); } - - // 然后处理其他Tab页 - if ($inactiveTabs.length > 0) { - processMultipleTabs(currentPage, $inactiveTabs); - } else if ($allTabs.length === 1) { - cy.log(`ℹ️ [${currentPage.name}] 只有一个活动的tab页`); - } - - closeActiveTab(currentPage.name); }); } else { - cy.log(`ℹ️ [${currentPage.name}] 页面中没有找到workSpaceBaseTab`); + // 如果不存在 .workSpaceBaseTab,记录信息并继续 + cy.log(`ℹ️ [${currentPage.name}] 页面中没有找到workSpaceBaseTab元素,可能是不同类型的页面`); + + // 尝试查找页面中可能存在的其他tab结构 + const hasOtherTabs = $body.find('.el-tabs__item').length > 0; + + if (hasOtherTabs) { + cy.log(`ℹ️ [${currentPage.name}] 找到其他类型的tab元素,尝试处理`); + return cy.get('.el-tabs__item').as('otherTabs').then($otherTabs => { + const $activeTab = $otherTabs.filter('.is-active'); + const $inactiveTabs = $otherTabs.filter(':not(.is-active)').toArray(); + + // 处理这些tab,类似于原来的逻辑 + // ... + }); + } else { + cy.log(`ℹ️ [${currentPage.name}] 页面中没有找到任何tab元素,记录为单页面`); + // 将页面记录为没有tab的单页面 + const tabInfo = { + name: "页面内容", + startTime: formatTime(pageStartTime), + endTime: formatTime(new Date()), + duration: calculateDuration(pageStartTime, new Date()), + status: 'success' + }; + + if (!currentPage.tabs) { + currentPage.tabs = []; + } + currentPage.tabs.push(tabInfo); + testReport.summary.totalTabs += 1; + + closeActiveTab(currentPage.name); + } } }); }; @@ -609,50 +517,38 @@ describe('隆基系统全部页面验证', () => { pageInfo.hasThirdMenu = true; cy.log(`✓ ${menuText} 包含 ${$thirdMenuItems.length} 个三级菜单`); - // 使用迭代方式处理三级菜单,避免深度递归 - const processThirdMenuSequentially = (items, startIndex = 0) => { - if (startIndex >= items.length) { + const processThirdMenu = (thirdIndex = 0) => { + if (thirdIndex >= $thirdMenuItems.length) { pageInfo.endTime = formatTime(new Date()); const thirdMenuProgress = (100).toFixed(1); cy.log(`✅ 完成菜单 "${menuText}" 的所有三级菜单处理 (${thirdMenuProgress}%)`); closeActiveTab(menuText); - return cy.wait(1000).then(() => processMenuItems(index + 1)); + cy.wait(1000).then(() => processMenuItems(index + 1)); + return; } - const thirdMenuProgress = ((startIndex + 1) / items.length * 100).toFixed(1); + const thirdMenuProgress = ((thirdIndex + 1) / $thirdMenuItems.length * 100).toFixed(1); - if (startIndex > 0) { - return cy.wrap($menuItem).click() - .wait(1000) - .then(() => { - return cy.get('@thirdMenuItems') - .eq(startIndex) - .then(processCurrentThirdMenuItem); - }); - } else { - return cy.get('@thirdMenuItems') - .eq(startIndex) - .then(processCurrentThirdMenuItem); + if (thirdIndex > 0) { + cy.wrap($menuItem).click(); + cy.wait(1000); } - function processCurrentThirdMenuItem($thirdMenu) { - const thirdMenuText = $thirdMenu.text().trim(); - cy.log(`\n🔸 处理三级菜单 [${startIndex + 1}/${items.length}] (${thirdMenuProgress}%): ${menuText} > ${thirdMenuText}`); + cy.get('@thirdMenuItems') + .eq(thirdIndex) + .then($thirdMenu => { + const thirdMenuText = $thirdMenu.text().trim(); + cy.log(`\n🔸 处理三级菜单 [${thirdIndex + 1}/${$thirdMenuItems.length}] (${thirdMenuProgress}%): ${menuText} > ${thirdMenuText}`); - const thirdMenuPage = new PageInfo(thirdMenuText, true, menuText).addToBatch(); + const thirdMenuPage = new PageInfo(thirdMenuText, true, menuText).addToBatch(); - return cy.wrap($thirdMenu).click() - .then(() => { - waitForPageLoad(thirdMenuPage, new Date()); - return cy.wait(1000); - }) - .then(() => { - return processThirdMenuSequentially(items, startIndex + 1); - }); - } + cy.wrap($thirdMenu).click(); + waitForPageLoad(thirdMenuPage, new Date()); + cy.wait(1000).then(() => processThirdMenu(thirdIndex + 1)); + }); }; - return processThirdMenuSequentially($thirdMenuItems); + processThirdMenu(); }; // 处理没有三级菜单的情况 @@ -720,35 +616,35 @@ describe('隆基系统全部页面验证', () => { cy.log(`🔍 找到 ${menuItems.length} 个可测试的菜单项`); // 创建菜单选择对话框 - const menuDialogBodyContent = ` - -