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 `
-
-
-
+ 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 = `
-
-