aaaaaaaaaa
This commit is contained in:
parent
d55befa222
commit
d12e39ff3a
@ -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) {
|
||||
@ -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;
|
||||
},
|
||||
},
|
||||
|
||||
@ -7,38 +7,6 @@ describe('隆基系统全部页面验证', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// 每个测试用例结束后清理内存
|
||||
afterEach(() => {
|
||||
cleanupMemory();
|
||||
});
|
||||
|
||||
// 创建通用对话框模板函数
|
||||
const createDialogTemplate = (options) => {
|
||||
const {
|
||||
dialogClass,
|
||||
title,
|
||||
width,
|
||||
bodyContent,
|
||||
footerContent
|
||||
} = options;
|
||||
|
||||
return `
|
||||
<div class="el-dialog__wrapper ${dialogClass}" style="position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto; margin: 0; z-index: 2000; background: rgba(0, 0, 0, 0.5);">
|
||||
<div class="el-dialog" style="margin: 15vh auto 50px; width: ${width || '500px'}; background: #fff; border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);">
|
||||
<div class="el-dialog__header" style="padding: 20px; border-bottom: 1px solid #eee;">
|
||||
<span class="el-dialog__title" style="font-size: 18px; color: #303133;">${title}</span>
|
||||
</div>
|
||||
<div class="el-dialog__body" style="padding: 20px; max-height: 50vh; overflow-y: auto;">
|
||||
${bodyContent}
|
||||
</div>
|
||||
<div class="el-dialog__footer" style="padding: 20px; text-align: right; border-top: 1px solid #eee;">
|
||||
${footerContent}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
// 格式化时间的辅助函数
|
||||
const formatTime = (date) => {
|
||||
return date.toLocaleString('zh-CN', {
|
||||
@ -111,7 +79,13 @@ describe('隆基系统全部页面验证', () => {
|
||||
Cypress.on('uncaught:exception', (err, runnable) => false);
|
||||
|
||||
// 创建环境选择对话框
|
||||
const envDialogBodyContent = `
|
||||
const dialogHtml = `
|
||||
<div class="el-dialog__wrapper env-select-dialog" style="position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto; margin: 0; z-index: 2000; background: rgba(0, 0, 0, 0.5);">
|
||||
<div class="el-dialog" style="margin: 15vh auto 50px; width: 400px; background: #fff; border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);">
|
||||
<div class="el-dialog__header" style="padding: 20px; border-bottom: 1px solid #eee;">
|
||||
<span class="el-dialog__title" style="font-size: 18px; color: #303133;">选择测试环境</span>
|
||||
</div>
|
||||
<div class="el-dialog__body" style="padding: 20px;">
|
||||
<div class="env-selection-status" style="margin-bottom: 15px; padding: 10px; background-color: #f0f9eb; border-radius: 4px; color: #67c23a;">
|
||||
请选择要测试的环境
|
||||
</div>
|
||||
@ -123,16 +97,11 @@ describe('隆基系统全部页面验证', () => {
|
||||
UAT环境
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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.task('clearMemory', null, {log: false});
|
||||
|
||||
// 记录清理前的内存使用情况
|
||||
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`);
|
||||
}
|
||||
// 清理DOM快照
|
||||
cy.get('body').then(() => {
|
||||
Cypress.$(document).find('*').off();
|
||||
Cypress.$('.el-loading-mask').remove();
|
||||
Cypress.$('.el-message').remove();
|
||||
Cypress.$('.el-message-box').remove();
|
||||
|
||||
// 执行内存清理操作
|
||||
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'
|
||||
];
|
||||
// 清理可能的内存泄漏
|
||||
Cypress.$('iframe').remove(); // 移除所有iframe
|
||||
Cypress.$('img').remove(); // 移除所有图片
|
||||
Cypress.$('video').remove(); // 移除所有视频
|
||||
|
||||
elementsToRemove.forEach(selector => {
|
||||
if (Cypress.$(selector).length > 0) {
|
||||
Cypress.$(selector).remove();
|
||||
}
|
||||
// 清理事件监听器
|
||||
const win = Cypress.$(window);
|
||||
win.off();
|
||||
win.find('*').off();
|
||||
});
|
||||
|
||||
// 2. 清理iframe内容
|
||||
Cypress.$('iframe').each((_, el) => {
|
||||
try {
|
||||
el.src = 'about:blank';
|
||||
} catch (e) {
|
||||
// 忽略错误
|
||||
// 手动清理一些可能的引用
|
||||
if (window.gc) {
|
||||
window.gc();
|
||||
}
|
||||
});
|
||||
|
||||
// 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('🧹 内存清理完成');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 添加关闭tab的公共方法
|
||||
@ -306,29 +213,20 @@ describe('隆基系统全部页面验证', () => {
|
||||
|
||||
// 添加报告写入方法
|
||||
const writeReportBatch = () => {
|
||||
if (testReport.currentBatch.pages.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const batchNumber = Math.floor(Math.random() * 10000);
|
||||
const batchNumber = Math.floor(testReport.summary.totalPages / 20); // 每20个页面写入一次
|
||||
const fileName = `cypress/reports/${selectedEnvironment}-menu-test-report-batch-${batchNumber}.json`;
|
||||
|
||||
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,18 +301,17 @@ 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 = {
|
||||
@ -430,57 +327,55 @@ describe('隆基系统全部页面验证', () => {
|
||||
}
|
||||
currentPage.tabs.push(tabInfo);
|
||||
|
||||
// 处理单个Tab,然后链式处理下一个
|
||||
return cy.wrap($currentTab)
|
||||
.click({force: true})
|
||||
.then(() => {
|
||||
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}次重试]`);
|
||||
let tabLoadRetry = 0;
|
||||
const waitForTabLoad = () => {
|
||||
if (tabLoadRetry >= 30) {
|
||||
cy.log(`❌ [${currentPage.name}] Tab页 ${tabText} 加载超时 [${tabLoadRetry}次重试],继续下一个`);
|
||||
updateTabInfo(tabInfo, tabStartTime, 'timeout');
|
||||
return cy.wrap(null);
|
||||
processTab(index + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
return cy.get('@pageBody').then($body => {
|
||||
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} 加载出现错误`);
|
||||
cy.log(`❌ [${currentPage.name}] Tab页 ${tabText} 加载出现错误`);
|
||||
updateTabInfo(tabInfo, tabStartTime, 'error');
|
||||
return cy.wrap(null);
|
||||
processTab(index + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
cy.log(`⏳ [${currentPage.name}] Tab页 ${tabInfo.name} 第 ${retryCount + 1} 次检查加载状态...`);
|
||||
return cy.wait(500).then(() => {
|
||||
return waitForTabLoadWithTimeout(currentPage, tabInfo, tabStartTime, maxRetries, retryCount + 1);
|
||||
});
|
||||
tabLoadRetry++;
|
||||
cy.log(`⏳ [${currentPage.name}] Tab页 ${tabText} 第 ${tabLoadRetry} 次检查加载状态...`);
|
||||
cy.wait(500).then(waitForTabLoad);
|
||||
} else {
|
||||
updateTabInfo(tabInfo, tabStartTime, 'success');
|
||||
cy.log(`✅ [${currentPage.name}] Tab页 ${tabInfo.name} 加载完成 (耗时: ${tabInfo.duration}秒)`);
|
||||
return cy.wait(1000);
|
||||
cy.log(`✅ [${currentPage.name}] Tab页 ${tabText} 加载完成 (耗时: ${tabInfo.duration}秒)`);
|
||||
cy.wait(1000).then(() => processTab(index + 1));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 开始处理所有Tab
|
||||
return processTabsSequentially($inactiveTabs);
|
||||
waitForTabLoad();
|
||||
});
|
||||
};
|
||||
|
||||
processTab();
|
||||
};
|
||||
|
||||
// 处理页面中的tab页
|
||||
const processPageTabs = (currentPage, pageStartTime) => {
|
||||
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 => {
|
||||
@ -507,32 +402,7 @@ describe('隆基系统全部页面验证', () => {
|
||||
// 检查活动Tab页的加载状态
|
||||
let activeTabLoadRetry = 0;
|
||||
const waitForActiveTabLoad = () => {
|
||||
if (activeTabLoadRetry >= 30) {
|
||||
cy.log(`❌ [${currentPage.name}] 活动Tab页 ${activeTabText} 加载超时`);
|
||||
updateTabInfo(tabInfo, pageStartTime, 'timeout');
|
||||
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页 ${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();
|
||||
@ -548,7 +418,45 @@ describe('隆基系统全部页面验证', () => {
|
||||
closeActiveTab(currentPage.name);
|
||||
});
|
||||
} else {
|
||||
cy.log(`ℹ️ [${currentPage.name}] 页面中没有找到workSpaceBaseTab`);
|
||||
cy.log(`ℹ️ [${currentPage.name}] 页面中没有找到workSpaceBaseTab的内容`);
|
||||
closeActiveTab(currentPage.name);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 如果不存在 .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) {
|
||||
cy.get('@thirdMenuItems')
|
||||
.eq(thirdIndex)
|
||||
.then($thirdMenu => {
|
||||
const thirdMenuText = $thirdMenu.text().trim();
|
||||
cy.log(`\n🔸 处理三级菜单 [${startIndex + 1}/${items.length}] (${thirdMenuProgress}%): ${menuText} > ${thirdMenuText}`);
|
||||
cy.log(`\n🔸 处理三级菜单 [${thirdIndex + 1}/${$thirdMenuItems.length}] (${thirdMenuProgress}%): ${menuText} > ${thirdMenuText}`);
|
||||
|
||||
const thirdMenuPage = new PageInfo(thirdMenuText, true, menuText).addToBatch();
|
||||
|
||||
return cy.wrap($thirdMenu).click()
|
||||
.then(() => {
|
||||
cy.wrap($thirdMenu).click();
|
||||
waitForPageLoad(thirdMenuPage, new Date());
|
||||
return cy.wait(1000);
|
||||
})
|
||||
.then(() => {
|
||||
return processThirdMenuSequentially(items, startIndex + 1);
|
||||
cy.wait(1000).then(() => processThirdMenu(thirdIndex + 1));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return processThirdMenuSequentially($thirdMenuItems);
|
||||
processThirdMenu();
|
||||
};
|
||||
|
||||
// 处理没有三级菜单的情况
|
||||
@ -720,7 +616,13 @@ describe('隆基系统全部页面验证', () => {
|
||||
cy.log(`🔍 找到 ${menuItems.length} 个可测试的菜单项`);
|
||||
|
||||
// 创建菜单选择对话框
|
||||
const menuDialogBodyContent = `
|
||||
const dialogHtml = `
|
||||
<div class="el-dialog__wrapper menu-select-dialog" style="position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto; margin: 0; z-index: 2000; background: rgba(0, 0, 0, 0.5);">
|
||||
<div class="el-dialog" style="margin: 15vh auto 50px; width: 600px; background: #fff; border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);">
|
||||
<div class="el-dialog__header" style="padding: 20px; border-bottom: 1px solid #eee;">
|
||||
<span class="el-dialog__title" style="font-size: 18px; color: #303133;">选择要测试的菜单</span>
|
||||
</div>
|
||||
<div class="el-dialog__body" style="padding: 20px; max-height: 50vh; overflow-y: auto;">
|
||||
<div class="menu-selection-status" style="margin-bottom: 15px; padding: 10px; background-color: #f0f9eb; border-radius: 4px; color: #67c23a;">
|
||||
请选择需要测试的菜单项,然后点击"开始测试"按钮开始测试。
|
||||
</div>
|
||||
@ -734,21 +636,15 @@ describe('隆基系统全部页面验证', () => {
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
|
||||
const menuDialogFooterContent = `
|
||||
</div>
|
||||
<div class="el-dialog__footer" style="padding: 20px; text-align: right; border-top: 1px solid #eee;">
|
||||
<button class="select-all-btn el-button el-button--default" style="margin-right: 10px;">全选</button>
|
||||
<button class="start-test-btn el-button el-button--primary" disabled>开始测试</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const dialogHtml = createDialogTemplate({
|
||||
dialogClass: 'menu-select-dialog',
|
||||
title: '选择要测试的菜单',
|
||||
width: '600px',
|
||||
bodyContent: menuDialogBodyContent,
|
||||
footerContent: menuDialogFooterContent
|
||||
});
|
||||
|
||||
// 添加对话框到页面
|
||||
Cypress.$('body').append(dialogHtml);
|
||||
|
||||
@ -802,7 +698,6 @@ describe('隆基系统全部页面验证', () => {
|
||||
// 开始测试的函数
|
||||
function startTesting(selectedMenus) {
|
||||
let processedCount = 0;
|
||||
const batchSize = 10; // 每批处理10个菜单项
|
||||
|
||||
const processMenuItems = (index = 0) => {
|
||||
if (index >= selectedMenus.length) {
|
||||
@ -822,12 +717,12 @@ describe('隆基系统全部页面验证', () => {
|
||||
}).replace(/[\/\s:]/g, '');
|
||||
|
||||
// 创建以时间戳命名的报告目录
|
||||
const reportDir = `cypress/reports/${selectedEnvironment}-report-${timestamp}`;
|
||||
const reportDir = `cypress/reports/report-${timestamp}`;
|
||||
|
||||
// 创建报告目录并生成最终报告
|
||||
cy.task('createReportDir', reportDir).then(() => {
|
||||
// 将摘要信息写入到时间戳目录中
|
||||
cy.writeFile(`${reportDir}/${selectedEnvironment}-test-summary-${timestamp}.json`, testReport.summary).then(() => {
|
||||
cy.writeFile(`${reportDir}/test-summary-${timestamp}.json`, testReport.summary).then(() => {
|
||||
generateFinalReport(reportDir, timestamp, selectedEnvironment);
|
||||
});
|
||||
});
|
||||
@ -838,31 +733,6 @@ describe('隆基系统全部页面验证', () => {
|
||||
writeReportBatch();
|
||||
}
|
||||
|
||||
// 每处理一定数量的菜单项,重新加载页面以释放内存
|
||||
if (index > 0 && index % batchSize === 0) {
|
||||
cy.log(`已处理 ${index} 个菜单项,重新加载页面以释放内存...`);
|
||||
|
||||
// 保存当前进度
|
||||
writeReportBatch();
|
||||
|
||||
// 清理内存
|
||||
cleanupMemory();
|
||||
|
||||
// 重新加载页面
|
||||
cy.reload();
|
||||
|
||||
// 等待页面加载完成
|
||||
cy.get('.ly-side-nav', { timeout: 30000 }).should('be.visible');
|
||||
|
||||
// 确保菜单展开
|
||||
cy.get('.ly-side-nav').then($nav => {
|
||||
if ($nav.css('left') !== '0px') {
|
||||
cy.get('.vab-content .toggle-icon').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 每处理3个菜单项清理一次内存
|
||||
if (index > 0 && index % 3 === 0) {
|
||||
cleanupMemory();
|
||||
}
|
||||
@ -903,178 +773,163 @@ describe('隆基系统全部页面验证', () => {
|
||||
checkTestStarted();
|
||||
});
|
||||
|
||||
// 在每个测试用例结束后清理内存
|
||||
afterEach(() => {
|
||||
cleanupMemory();
|
||||
});
|
||||
|
||||
// 修改生成HTML报告的方法,接收环境参数
|
||||
const generateFinalReport = (reportDir, timestamp, environment) => {
|
||||
// 读取所有批次报告
|
||||
cy.task('readAllReports', environment).then((allBatches) => {
|
||||
cy.log(`📊 读取到 ${allBatches.length} 个批次报告`);
|
||||
|
||||
// 使用更高效的方式合并批次数据
|
||||
// 合并所有批次数据
|
||||
const combinedReport = {
|
||||
pages: [],
|
||||
failedPages: []
|
||||
};
|
||||
|
||||
// 预计算总页面数和失败页面数,提高性能
|
||||
let totalPages = 0;
|
||||
let totalFailedPages = 0;
|
||||
|
||||
// 使用for循环替代forEach,减少函数调用和闭包
|
||||
if (Array.isArray(allBatches)) {
|
||||
for (let i = 0; i < allBatches.length; i++) {
|
||||
const batch = allBatches[i];
|
||||
if (batch.pages && Array.isArray(batch.pages)) {
|
||||
totalPages += batch.pages.length;
|
||||
}
|
||||
if (batch.failedPages && Array.isArray(batch.failedPages)) {
|
||||
totalFailedPages += batch.failedPages.length;
|
||||
allBatches.forEach(batch => {
|
||||
if (batch.pages) {
|
||||
cy.log(`合并批次报告: ${batch.pages.length} 个页面`);
|
||||
combinedReport.pages.push(...batch.pages);
|
||||
}
|
||||
if (batch.failedPages) {
|
||||
combinedReport.failedPages.push(...batch.failedPages);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加当前批次
|
||||
if (testReport.currentBatch.pages && Array.isArray(testReport.currentBatch.pages)) {
|
||||
totalPages += testReport.currentBatch.pages.length;
|
||||
}
|
||||
if (testReport.currentBatch.failedPages && Array.isArray(testReport.currentBatch.failedPages)) {
|
||||
totalFailedPages += testReport.currentBatch.failedPages.length;
|
||||
}
|
||||
|
||||
// 预分配数组大小,避免动态扩容
|
||||
combinedReport.pages = new Array(totalPages);
|
||||
combinedReport.failedPages = new Array(totalFailedPages);
|
||||
|
||||
// 填充数据,使用for循环替代forEach
|
||||
let pageIndex = 0;
|
||||
let failedPageIndex = 0;
|
||||
|
||||
if (Array.isArray(allBatches)) {
|
||||
for (let i = 0; i < allBatches.length; i++) {
|
||||
const batch = allBatches[i];
|
||||
if (batch.pages && Array.isArray(batch.pages)) {
|
||||
for (let j = 0; j < batch.pages.length; j++) {
|
||||
combinedReport.pages[pageIndex++] = batch.pages[j];
|
||||
}
|
||||
}
|
||||
if (batch.failedPages && Array.isArray(batch.failedPages)) {
|
||||
for (let j = 0; j < batch.failedPages.length; j++) {
|
||||
combinedReport.failedPages[failedPageIndex++] = batch.failedPages[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加当前批次,使用for循环
|
||||
if (testReport.currentBatch.pages && Array.isArray(testReport.currentBatch.pages)) {
|
||||
for (let i = 0; i < testReport.currentBatch.pages.length; i++) {
|
||||
combinedReport.pages[pageIndex++] = testReport.currentBatch.pages[i];
|
||||
}
|
||||
}
|
||||
if (testReport.currentBatch.failedPages && Array.isArray(testReport.currentBatch.failedPages)) {
|
||||
for (let i = 0; i < testReport.currentBatch.failedPages.length; i++) {
|
||||
combinedReport.failedPages[failedPageIndex++] = testReport.currentBatch.failedPages[i];
|
||||
// 添加当前批次的数据
|
||||
if (testReport.currentBatch.pages.length > 0) {
|
||||
cy.log(`添加当前批次: ${testReport.currentBatch.pages.length} 个页面`);
|
||||
combinedReport.pages.push(...testReport.currentBatch.pages);
|
||||
}
|
||||
if (testReport.currentBatch.failedPages.length > 0) {
|
||||
combinedReport.failedPages.push(...testReport.currentBatch.failedPages);
|
||||
}
|
||||
|
||||
cy.log(`📊 总计: ${combinedReport.pages.length} 个页面, ${testReport.summary.totalTabs} 个Tab页`);
|
||||
|
||||
// 使用字符串拼接而不是模板字符串生成HTML,提高性能
|
||||
let htmlReport = '<!DOCTYPE html>\n<html>\n<head>\n';
|
||||
htmlReport += ' <meta charset="UTF-8">\n';
|
||||
htmlReport += ' <title>系统页面可用性测试报告</title>\n';
|
||||
htmlReport += ' <style>\n';
|
||||
htmlReport += ' body { font-family: Arial, sans-serif; margin: 20px; }\n';
|
||||
htmlReport += ' .summary { margin-bottom: 20px; }\n';
|
||||
htmlReport += ' table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }\n';
|
||||
htmlReport += ' th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n';
|
||||
htmlReport += ' th { background-color: #f4f4f4; }\n';
|
||||
htmlReport += ' .success { color: green; }\n';
|
||||
htmlReport += ' .error { color: red; }\n';
|
||||
htmlReport += ' .timeout { color: orange; }\n';
|
||||
htmlReport += ' .pending { color: gray; }\n';
|
||||
htmlReport += ' .tab-row { background-color: #f9f9f9; }\n';
|
||||
htmlReport += ' .failed-pages { margin-top: 20px; }\n';
|
||||
htmlReport += ' .failed-page { background-color: #fff0f0; margin-bottom: 10px; padding: 10px; border-left: 4px solid #ff0000; }\n';
|
||||
htmlReport += ' </style>\n';
|
||||
htmlReport += '</head>\n<body>\n';
|
||||
htmlReport += ' <h1>系统页面可用性测试报告</h1>\n';
|
||||
htmlReport += ' <div class="summary">\n';
|
||||
htmlReport += ' <h2>测试摘要</h2>\n';
|
||||
htmlReport += ' <p>测试环境: ' + environment + '</p>\n';
|
||||
htmlReport += ' <p>总页面数: ' + combinedReport.pages.length + '</p>\n';
|
||||
htmlReport += ' <p>总Tab页数: ' + testReport.summary.totalTabs + '</p>\n';
|
||||
htmlReport += ' <p>失败页面数: ' + combinedReport.failedPages.length + '</p>\n';
|
||||
htmlReport += ' <p>开始时间: ' + testReport.summary.startTime + '</p>\n';
|
||||
htmlReport += ' <p>结束时间: ' + testReport.summary.endTime + '</p>\n';
|
||||
htmlReport += ' <p>总耗时: ' + calculateDuration(new Date(testReport.summary.startTime), new Date(testReport.summary.endTime)) + '秒</p>\n';
|
||||
htmlReport += ' </div>\n\n';
|
||||
const htmlReport = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>系统页面可用性测试报告</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
.summary { margin-bottom: 20px; }
|
||||
table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
|
||||
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
||||
th { background-color: #f4f4f4; }
|
||||
.success { color: green; }
|
||||
.error { color: red; }
|
||||
.timeout { color: orange; }
|
||||
.pending { color: gray; }
|
||||
.tab-row { background-color: #f9f9f9; }
|
||||
.failed-pages { margin-top: 20px; }
|
||||
.failed-page { background-color: #fff0f0; margin-bottom: 10px; padding: 10px; border-left: 4px solid #ff0000; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>系统页面可用性测试报告</h1>
|
||||
<div class="summary">
|
||||
<h2>测试摘要</h2>
|
||||
<p>测试环境: ${environment}</p>
|
||||
<p>总页面数: ${combinedReport.pages.length}</p>
|
||||
<p>总Tab页数: ${testReport.summary.totalTabs}</p>
|
||||
<p>失败页面数: ${combinedReport.failedPages.length}</p>
|
||||
<p>开始时间: ${testReport.summary.startTime}</p>
|
||||
<p>结束时间: ${testReport.summary.endTime}</p>
|
||||
<p>总耗时: ${calculateDuration(new Date(testReport.summary.startTime), new Date(testReport.summary.endTime))}秒</p>
|
||||
</div>
|
||||
|
||||
// 生成失败页面列表,使用for循环
|
||||
if (combinedReport.failedPages.length > 0) {
|
||||
htmlReport += ' <div class="failed-pages">\n';
|
||||
htmlReport += ' <h2>失败页面列表</h2>\n';
|
||||
${combinedReport.failedPages.length > 0 ? `
|
||||
<div class="failed-pages">
|
||||
<h2>失败页面列表</h2>
|
||||
${combinedReport.failedPages.map(page => `
|
||||
<div class="failed-page">
|
||||
<h3>${page.name}</h3>
|
||||
<p>失败时间: ${page.time}</p>
|
||||
<p>错误信息: ${page.error}</p>
|
||||
<p>耗时: ${page.duration}秒</p>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
for (let i = 0; i < combinedReport.failedPages.length; i++) {
|
||||
const page = combinedReport.failedPages[i];
|
||||
htmlReport += ' <div class="failed-page">\n';
|
||||
htmlReport += ' <h3>' + page.name + '</h3>\n';
|
||||
htmlReport += ' <p>失败时间: ' + page.time + '</p>\n';
|
||||
htmlReport += ' <p>错误信息: ' + page.error + '</p>\n';
|
||||
htmlReport += ' <p>耗时: ' + page.duration + '秒</p>\n';
|
||||
htmlReport += ' </div>\n';
|
||||
}
|
||||
|
||||
htmlReport += ' </div>\n';
|
||||
}
|
||||
|
||||
// 生成详细测试结果表格,使用for循环
|
||||
htmlReport += ' <h2>详细测试结果</h2>\n';
|
||||
htmlReport += ' <table>\n';
|
||||
htmlReport += ' <tr>\n';
|
||||
htmlReport += ' <th>页面名称</th>\n';
|
||||
htmlReport += ' <th>开始时间</th>\n';
|
||||
htmlReport += ' <th>Tab页名称</th>\n';
|
||||
htmlReport += ' <th>Tab开始时间</th>\n';
|
||||
htmlReport += ' <th>Tab结束时间</th>\n';
|
||||
htmlReport += ' <th>加载时长(秒)</th>\n';
|
||||
htmlReport += ' <th>状态</th>\n';
|
||||
htmlReport += ' </tr>\n';
|
||||
|
||||
// 生成表格内容,使用for循环
|
||||
for (let i = 0; i < combinedReport.pages.length; i++) {
|
||||
const page = combinedReport.pages[i];
|
||||
<h2>详细测试结果</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>页面名称</th>
|
||||
<th>开始时间</th>
|
||||
<th>Tab页名称</th>
|
||||
<th>Tab开始时间</th>
|
||||
<th>Tab结束时间</th>
|
||||
<th>加载时长(秒)</th>
|
||||
<th>状态</th>
|
||||
</tr>
|
||||
${combinedReport.pages.map(page => {
|
||||
if (!page.tabs || page.tabs.length === 0) {
|
||||
htmlReport += ' <tr>\n';
|
||||
htmlReport += ' <td>' + page.name + '</td>\n';
|
||||
htmlReport += ' <td>' + page.startTime + '</td>\n';
|
||||
htmlReport += ' <td colspan="5">无Tab页</td>\n';
|
||||
htmlReport += ' </tr>\n';
|
||||
} else {
|
||||
for (let j = 0; j < page.tabs.length; j++) {
|
||||
const tab = page.tabs[j];
|
||||
htmlReport += ' <tr class="tab-row">\n';
|
||||
htmlReport += ' <td>' + (j === 0 ? page.name : '') + '</td>\n';
|
||||
htmlReport += ' <td>' + (j === 0 ? page.startTime : '') + '</td>\n';
|
||||
htmlReport += ' <td>' + tab.name + '</td>\n';
|
||||
htmlReport += ' <td>' + tab.startTime + '</td>\n';
|
||||
htmlReport += ' <td>' + tab.endTime + '</td>\n';
|
||||
htmlReport += ' <td>' + tab.duration + '</td>\n';
|
||||
htmlReport += ' <td class="' + tab.status + '">' + tab.status + '</td>\n';
|
||||
htmlReport += ' </tr>\n';
|
||||
return `
|
||||
<tr>
|
||||
<td>${page.name}</td>
|
||||
<td>${page.startTime}</td>
|
||||
<td colspan="5">无Tab页</td>
|
||||
</tr>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
htmlReport += ' </table>\n';
|
||||
htmlReport += '</body>\n</html>';
|
||||
return page.tabs.map((tab, index) => `
|
||||
<tr class="tab-row">
|
||||
<td>${index === 0 ? page.name : ''}</td>
|
||||
<td>${index === 0 ? page.startTime : ''}</td>
|
||||
<td>${tab.name}</td>
|
||||
<td>${tab.startTime}</td>
|
||||
<td>${tab.endTime}</td>
|
||||
<td>${tab.duration}</td>
|
||||
<td class="${tab.status}">${tab.status}</td>
|
||||
</tr>`).join('')
|
||||
}).join('')}
|
||||
</table>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
// 将报告写入到时间戳目录中
|
||||
const reportFile = `${environment}-test-report-${timestamp}.html`;
|
||||
cy.writeFile(`${reportDir}/${reportFile}`, htmlReport).then(() => {
|
||||
cy.log(`✅ 已生成测试报告: ${reportDir}/${reportFile}`);
|
||||
cy.writeFile(`${reportDir}/${environment}-test-report-${timestamp}.html`, htmlReport).then(() => {
|
||||
cy.log(`✅ 已生成测试报告: ${reportDir}/${environment}-test-report-${timestamp}.html`);
|
||||
|
||||
// 显示完成对话框
|
||||
showCompletionDialog(reportDir, reportFile);
|
||||
// 添加完成提示对话框
|
||||
const completionDialogHtml = `
|
||||
<div class="el-dialog__wrapper completion-dialog" style="position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto; margin: 0; z-index: 2001; background: rgba(0, 0, 0, 0.5);">
|
||||
<div class="el-dialog" style="margin: 15vh auto 50px; width: 500px; background: #fff; border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);">
|
||||
<div class="el-dialog__header" style="padding: 20px; border-bottom: 1px solid #eee;">
|
||||
<span class="el-dialog__title" style="font-size: 18px; color: #303133;">✅ 测试完成</span>
|
||||
</div>
|
||||
<div class="el-dialog__body" style="padding: 30px 20px;">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<p style="margin: 0 0 15px 0;">测试报告已生成完成!</p>
|
||||
<p style="margin: 0; color: #666;">报告目录:<br><span style="color: #409EFF; word-break: break-all;">${reportDir}</span></p>
|
||||
<p style="margin: 10px 0 0 0; color: #666;">报告文件:<br><span style="color: #409EFF; word-break: break-all;">${environment}-test-report-${timestamp}.html</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-dialog__footer" style="padding: 20px; text-align: right; border-top: 1px solid #eee;">
|
||||
<button class="close-dialog-btn el-button el-button--primary" style="padding: 9px 15px;">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 添加对话框到页面
|
||||
cy.get('body').then($body => {
|
||||
$body.append(completionDialogHtml);
|
||||
|
||||
// 绑定关闭按钮事件
|
||||
Cypress.$('.close-dialog-btn').on('click', function() {
|
||||
Cypress.$('.completion-dialog').remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 清理批次报告文件
|
||||
@ -1086,38 +941,4 @@ describe('隆基系统全部页面验证', () => {
|
||||
after(() => {
|
||||
cleanupMemory();
|
||||
});
|
||||
|
||||
// 添加完成对话框
|
||||
const showCompletionDialog = (reportDir, reportFile) => {
|
||||
// 创建完成对话框的HTML
|
||||
const completionDialogBodyContent = `
|
||||
<div style="margin-bottom: 15px;">
|
||||
<p style="margin: 0 0 15px 0;">测试报告已生成完成!</p>
|
||||
<p style="margin: 0; color: #666;">报告目录:<br><span style="color: #409EFF; word-break: break-all;">${reportDir}</span></p>
|
||||
<p style="margin: 10px 0 0 0; color: #666;">报告文件:<br><span style="color: #409EFF; word-break: break-all;">${reportFile}</span></p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const completionDialogFooterContent = `
|
||||
<button class="close-dialog-btn el-button el-button--primary" style="padding: 9px 15px;">确定</button>
|
||||
`;
|
||||
|
||||
const completionDialogHtml = createDialogTemplate({
|
||||
dialogClass: 'completion-dialog',
|
||||
title: '✅ 测试完成',
|
||||
width: '500px',
|
||||
bodyContent: completionDialogBodyContent,
|
||||
footerContent: completionDialogFooterContent
|
||||
});
|
||||
|
||||
// 添加对话框到页面
|
||||
cy.get('body').then($body => {
|
||||
$body.append(completionDialogHtml);
|
||||
|
||||
// 绑定关闭按钮事件
|
||||
Cypress.$('.close-dialog-btn').on('click', function() {
|
||||
Cypress.$('.completion-dialog').remove();
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
@ -161,38 +161,78 @@ describe('隆基系统页面验证', () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 处理二级菜单的方法
|
||||
// 关闭活动的标签页
|
||||
const closeActiveTab = (menuText) => {
|
||||
cy.log(`尝试关闭标签页: ${menuText}`);
|
||||
cy.get('.vab-tabs .el-tabs__item').each(($tab) => {
|
||||
if ($tab.text().trim() === menuText) {
|
||||
cy.wrap($tab).find('.el-icon-close').click();
|
||||
cy.wait(500);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 处理二级菜单的方法
|
||||
const handleSecondLevelMenu = (menuItem) => {
|
||||
cy.log(`📎 处理二级菜单: ${menuItem.text}`);
|
||||
// TODO: 添加二级菜单的具体处理逻辑
|
||||
// 1. 点击菜单
|
||||
// 2. 验证页面加载
|
||||
// 3. 检查页面内容
|
||||
|
||||
// 点击菜单项
|
||||
cy.get('.el-sub-menu__title, .el-menu-item').eq(menuItem.index).then($element => {
|
||||
cy.wrap($element).click();
|
||||
cy.wait(1000);
|
||||
|
||||
// 等待页面加载
|
||||
waitForPageLoad();
|
||||
|
||||
// 检查并处理标签页
|
||||
cy.get('.vab-tabs .el-tabs__item').then($tabs => {
|
||||
if ($tabs.length > 0) {
|
||||
// 遍历所有标签页
|
||||
cy.get('.vab-tabs .el-tabs__item').each(($tab) => {
|
||||
const tabText = $tab.text().trim();
|
||||
cy.log(`处理标签页: ${tabText}`);
|
||||
|
||||
// 点击标签页
|
||||
cy.wrap($tab).click();
|
||||
cy.wait(1000);
|
||||
|
||||
// 等待页面加载
|
||||
waitForPageLoad();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 关闭当前菜单的所有标签页
|
||||
closeActiveTab(menuItem.text);
|
||||
});
|
||||
};
|
||||
|
||||
// 处理三级菜单的方法
|
||||
const handleThirdLevelMenu = (menuItem) => {
|
||||
cy.log(`📑 处理三级菜单: ${menuItem.text}`);
|
||||
|
||||
// 根据菜单索引找到对应的菜单元素
|
||||
cy.get('.el-sub-menu__title, .el-menu-item').eq(menuItem.index).then($element => {
|
||||
// 获取二级菜单元素
|
||||
cy.get('.el-sub-menu__title, .el-menu-item').eq(menuItem.index).as('secondMenu');
|
||||
|
||||
// 定义获取三级菜单的命令
|
||||
Cypress.Commands.add('getThirdMenuItems', () => {
|
||||
return cy.get('@secondMenu').click()
|
||||
.then(() => {
|
||||
return cy.get('.el-popper.is-light.el-popover', {timeout: 5000})
|
||||
.should('be.visible')
|
||||
.find('.menuTitle.canClick')
|
||||
.should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
const processThirdMenuItems = ($thirdMenuItems, currentIndex = 0) => {
|
||||
if (currentIndex >= $thirdMenuItems.length) {
|
||||
cy.log(`✅ 完成所有三级菜单处理: ${menuItem.text}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保二级菜单展开并等待三级菜单出现
|
||||
cy.wrap($element).click();
|
||||
|
||||
// 等待三级菜单弹出框出现
|
||||
cy.get('.el-popper.is-light.el-popover', {timeout: 5000})
|
||||
.should('be.visible')
|
||||
.then(() => {
|
||||
// 重新获取三级菜单项
|
||||
cy.get('.el-popper.is-light.el-popover .menuTitle.canClick')
|
||||
.should('be.visible')
|
||||
.then($updatedThirdMenus => {
|
||||
// 获取并处理当前三级菜单项
|
||||
cy.getThirdMenuItems().then($updatedThirdMenus => {
|
||||
const $currentThirdMenu = $updatedThirdMenus.eq(currentIndex);
|
||||
const thirdMenuText = $currentThirdMenu.text().trim();
|
||||
|
||||
@ -200,28 +240,38 @@ describe('隆基系统页面验证', () => {
|
||||
|
||||
// 点击三级菜单项
|
||||
cy.wrap($currentThirdMenu).click();
|
||||
waitForPageLoad();
|
||||
|
||||
// 检查并处理标签页
|
||||
cy.get('.vab-tabs .el-tabs__item').then($tabs => {
|
||||
if ($tabs.length > 0) {
|
||||
// 遍历所有标签页
|
||||
cy.get('.vab-tabs .el-tabs__item').each(($tab) => {
|
||||
const tabText = $tab.text().trim();
|
||||
cy.log(`处理标签页: ${tabText}`);
|
||||
|
||||
// 点击标签页
|
||||
cy.wrap($tab).click();
|
||||
cy.wait(1000);
|
||||
|
||||
// 等待页面加载
|
||||
waitForPageLoad();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 关闭当前菜单的标签页
|
||||
closeActiveTab(thirdMenuText);
|
||||
|
||||
// 处理下一个三级菜单项
|
||||
cy.wait(1000).then(() => {
|
||||
processThirdMenuItems($thirdMenuItems, currentIndex + 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 开始处理三级菜单
|
||||
cy.wrap($element).click();
|
||||
|
||||
// 等待三级菜单弹出框出现
|
||||
cy.get('.el-popper.is-light.el-popover', {timeout: 5000})
|
||||
.should('be.visible')
|
||||
.then(() => {
|
||||
cy.get('.el-popper.is-light.el-popover .menuTitle.canClick')
|
||||
.should('be.visible')
|
||||
.then($thirdMenuItems => {
|
||||
cy.getThirdMenuItems().then($thirdMenuItems => {
|
||||
if ($thirdMenuItems.length > 0) {
|
||||
cy.log(`发现 ${$thirdMenuItems.length} 个三级菜单项`);
|
||||
processThirdMenuItems($thirdMenuItems);
|
||||
@ -229,8 +279,6 @@ describe('隆基系统页面验证', () => {
|
||||
cy.log('没有找到三级菜单项');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
const waitForPageLoad = () => {
|
||||
cy.log('等待页面数据加载...');
|
||||
@ -302,6 +350,36 @@ describe('隆基系统页面验证', () => {
|
||||
saveMenuItemsToFile();
|
||||
};
|
||||
|
||||
// 处理菜单测试的方法
|
||||
const processMenuTests = (menuData) => {
|
||||
const {menuItems} = menuData.content;
|
||||
const totalMenus = menuItems.length;
|
||||
const untestedMenus = menuItems.filter(item => !item.tested);
|
||||
|
||||
cy.log('📊 菜单测试统计');
|
||||
cy.log(`总菜单数: ${totalMenus}`);
|
||||
cy.log(`待测试数: ${untestedMenus.length}`);
|
||||
cy.log(`已完成数: ${totalMenus - untestedMenus.length}`);
|
||||
|
||||
// 遍历每个菜单项
|
||||
menuItems.forEach((menuItem, index) => {
|
||||
// 跳过已测试的菜单项
|
||||
if (menuItem.tested) {
|
||||
cy.log(`⏭️ 跳过已测试的菜单项:${menuItem.text}`);
|
||||
return;
|
||||
}
|
||||
|
||||
cy.log(`🔄 正在处理第 ${index + 1}/${totalMenus} 个菜单项:${menuItem.text}`);
|
||||
|
||||
// 根据菜单类型调用对应的处理方法
|
||||
if (menuItem.hasThirdMenu) {
|
||||
handleThirdLevelMenu(menuItem);
|
||||
} else {
|
||||
handleSecondLevelMenu(menuItem);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 测试入口
|
||||
it('验证系统页面是否可用', () => {
|
||||
// 验证环境参数
|
||||
@ -317,32 +395,11 @@ describe('隆基系统页面验证', () => {
|
||||
|
||||
getLatestDataFileContent().then(result => {
|
||||
if (result && result.content && result.content.menuItems) {
|
||||
const totalMenus = result.content.menuItems.length;
|
||||
const untestedMenus = result.content.menuItems.filter(item => !item.tested);
|
||||
|
||||
cy.log(`菜单项统计:总数 ${totalMenus},待测试 ${untestedMenus.length},已完成 ${totalMenus - untestedMenus.length}`);
|
||||
|
||||
// 遍历每个菜单项
|
||||
result.content.menuItems.forEach((menuItem, index) => {
|
||||
// 如果菜单项已测试,则跳过
|
||||
if (menuItem.tested) {
|
||||
cy.log(`⏭️ 跳过已测试的菜单项:${menuItem.text}`);
|
||||
return;
|
||||
}
|
||||
|
||||
cy.log(`🔄 正在处理第 ${index + 1} 个菜单项:${menuItem.text}`);
|
||||
// 根据菜单层级调用不同的处理方法
|
||||
if (menuItem.hasThirdMenu) {
|
||||
handleThirdLevelMenu(menuItem);
|
||||
} else {
|
||||
handleSecondLevelMenu(menuItem);
|
||||
}
|
||||
|
||||
});
|
||||
processMenuTests(result);
|
||||
} else {
|
||||
cy.log('❌ 没有找到有效的菜单数据');
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
cy.log('✅ 系统菜单加载成功');
|
||||
cy.log(`🏁 测试完成,环境: ${SELECT_ENV}`);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user