优化分批执行点击菜单
This commit is contained in:
parent
f528c74656
commit
8d38687583
2
.env.dev
2
.env.dev
@ -7,7 +7,7 @@ IBP_PASSWORD=123456
|
|||||||
|
|
||||||
# 测试配置
|
# 测试配置
|
||||||
TEST_DATA_DIR=test-data
|
TEST_DATA_DIR=test-data
|
||||||
TEST_BATCH_SIZE=5
|
TEST_BATCH_SIZE=2
|
||||||
TEST_RETRY_COUNT=3
|
TEST_RETRY_COUNT=3
|
||||||
TEST_BATCH_INTERVAL=2000
|
TEST_BATCH_INTERVAL=2000
|
||||||
TEST_MAX_RETRY_DELAY=10000
|
TEST_MAX_RETRY_DELAY=10000
|
||||||
|
|||||||
@ -92,7 +92,7 @@ class BasePage {
|
|||||||
*/
|
*/
|
||||||
async waitForElement(selector, options = {}) {
|
async waitForElement(selector, options = {}) {
|
||||||
try {
|
try {
|
||||||
const element = options.firstOnly ? this.page.locator(selector).first() : this.page.locator(selector);
|
let element = options.firstOnly ? this.page.locator(selector).first() : this.page.locator(selector);
|
||||||
|
|
||||||
await element.waitFor({
|
await element.waitFor({
|
||||||
state: 'visible',
|
state: 'visible',
|
||||||
@ -114,7 +114,7 @@ class BasePage {
|
|||||||
* @param {Object} options 选项
|
* @param {Object} options 选项
|
||||||
*/
|
*/
|
||||||
async clickBySelector(selector, options = {}) {
|
async clickBySelector(selector, options = {}) {
|
||||||
const element = await this.waitForElement(selector, options);
|
let element = await this.waitForElement(selector, options);
|
||||||
await element.click(options);
|
await element.click(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ class BasePage {
|
|||||||
* @param {Object} options 选项
|
* @param {Object} options 选项
|
||||||
*/
|
*/
|
||||||
async fill(selector, value, options = {}) {
|
async fill(selector, value, options = {}) {
|
||||||
const element = await this.waitForElement(selector, options);
|
let element = await this.waitForElement(selector, options);
|
||||||
await element.fill(value);
|
await element.fill(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,22 +194,22 @@ class BasePage {
|
|||||||
async waitForIBPPageLoadWithRetry(pageName) {
|
async waitForIBPPageLoadWithRetry(pageName) {
|
||||||
console.log(`等待页面 ${pageName} 数据加载...`);
|
console.log(`等待页面 ${pageName} 数据加载...`);
|
||||||
|
|
||||||
const startTime = Date.now();
|
let startTime = Date.now();
|
||||||
let retryCount = 0;
|
let retryCount = 0;
|
||||||
const {maxRetries, retryInterval, stabilityDelay} = this.config.pageLoad;
|
let {maxRetries, retryInterval, stabilityDelay} = this.config.pageLoad;
|
||||||
let errorMessage = null;
|
let errorMessage = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (retryCount < maxRetries) {
|
while (retryCount < maxRetries) {
|
||||||
// 检查错误状态
|
// 检查错误状态
|
||||||
const hasError = await this.checkPageError(pageName);
|
let hasError = await this.checkPageError(pageName);
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
errorMessage = await this.getErrorMessage();
|
errorMessage = await this.getErrorMessage();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查加载状态
|
// 检查加载状态
|
||||||
const isLoading = await this.elementExistsBySelector(this.selectors.loadingMask);
|
let isLoading = await this.elementExistsBySelector(this.selectors.loadingMask);
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
await this.waitForTimeout(stabilityDelay);
|
await this.waitForTimeout(stabilityDelay);
|
||||||
console.log(`✅ 页面 ${pageName} 加载完成`);
|
console.log(`✅ 页面 ${pageName} 加载完成`);
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class LongiMainPage extends BasePage {
|
|||||||
thirdLevelIndicator: '.el-icon-arrow-right',
|
thirdLevelIndicator: '.el-icon-arrow-right',
|
||||||
subMenuIndicator: '.el-sub-menu__icon-arrow',
|
subMenuIndicator: '.el-sub-menu__icon-arrow',
|
||||||
// Tab相关
|
// Tab相关
|
||||||
tabContainer: '.workSpaceBaseTab .el-tabs__item',
|
tabContainer: '.workSpaceBaseTab>.el-tabs__header .el-tabs__item',
|
||||||
activeTab: '.vab-tabs .el-tabs--card .el-tabs__item.is-active',
|
activeTab: '.vab-tabs .el-tabs--card .el-tabs__item.is-active',
|
||||||
closeButton: '.el-icon.is-icon-close',
|
closeButton: '.el-icon.is-icon-close',
|
||||||
tabItems: '.workSpaceBaseTab .el-tabs__item',
|
tabItems: '.workSpaceBaseTab .el-tabs__item',
|
||||||
@ -388,17 +388,17 @@ class LongiMainPage extends BasePage {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async findTabInfos(menu) {
|
async findTabInfos(menu) {
|
||||||
const tabs = await this.page.locator(this.selectors.tabContainer).all();
|
let tabs = await this.page.locator(this.selectors.tabContainer).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 = [];
|
let tabInfos = [];
|
||||||
for (const tab of tabs) {
|
for (const tab of tabs) {
|
||||||
const text = await tab.textContent();
|
let text = await tab.textContent();
|
||||||
const isActive = await tab.evaluate(el => el.classList.contains('is-active'));
|
let isActive = await tab.evaluate(el => el.classList.contains('is-active'));
|
||||||
tabInfos.push({
|
tabInfos.push({
|
||||||
text: text.trim(),
|
text: text.trim(),
|
||||||
element: tab,
|
element: tab,
|
||||||
@ -416,7 +416,7 @@ class LongiMainPage extends BasePage {
|
|||||||
try {
|
try {
|
||||||
await this.waitForTimeout(1000);
|
await this.waitForTimeout(1000);
|
||||||
|
|
||||||
const tabInfos = await this.findTabInfos(menu);
|
let tabInfos = await this.findTabInfos(menu);
|
||||||
if (tabInfos.length === 0) {
|
if (tabInfos.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -441,9 +441,10 @@ class LongiMainPage extends BasePage {
|
|||||||
* @param {Object} parentMenu 父级菜单对象
|
* @param {Object} parentMenu 父级菜单对象
|
||||||
*/
|
*/
|
||||||
async handleSingleTab(tabInfo, parentMenu) {
|
async handleSingleTab(tabInfo, parentMenu) {
|
||||||
|
let menuPath, tabPath = '';
|
||||||
try {
|
try {
|
||||||
const menuPath = parentMenu.path || parentMenu.text;
|
menuPath = parentMenu.path || parentMenu.text;
|
||||||
const tabPath = `${menuPath} > ${tabInfo.text}`;
|
tabPath = `${menuPath} > ${tabInfo.text}`;
|
||||||
await tabInfo.element.click();
|
await tabInfo.element.click();
|
||||||
await this.waitForIBPPageLoadWithRetry(tabPath);
|
await this.waitForIBPPageLoadWithRetry(tabPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -456,8 +457,8 @@ class LongiMainPage extends BasePage {
|
|||||||
*/
|
*/
|
||||||
async closeActiveTab(parentMenu) {
|
async closeActiveTab(parentMenu) {
|
||||||
try {
|
try {
|
||||||
const activeTab = this.page.locator(this.selectors.activeTab);
|
let activeTab = this.page.locator(this.selectors.activeTab);
|
||||||
const closeButton = activeTab.locator(this.selectors.closeButton);
|
let closeButton = activeTab.locator(this.selectors.closeButton);
|
||||||
if (await this.canCloseTab(activeTab, closeButton)) {
|
if (await this.canCloseTab(activeTab, closeButton)) {
|
||||||
await closeButton.waitFor({state: 'visible', timeout: 5000});
|
await closeButton.waitFor({state: 'visible', timeout: 5000});
|
||||||
await this.clickByElement(closeButton);
|
await this.clickByElement(closeButton);
|
||||||
@ -478,8 +479,8 @@ class LongiMainPage extends BasePage {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async canCloseTab(activeTab, closeButton) {
|
async canCloseTab(activeTab, closeButton) {
|
||||||
const hasActiveTab = await activeTab.count() > 0;
|
let hasActiveTab = await activeTab.count() > 0;
|
||||||
const hasCloseButton = await closeButton.count() > 0;
|
let hasCloseButton = await closeButton.count() > 0;
|
||||||
return hasActiveTab && hasCloseButton;
|
return hasActiveTab && hasCloseButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +491,7 @@ class LongiMainPage extends BasePage {
|
|||||||
async cleanupMemory(context = '') {
|
async cleanupMemory(context = '') {
|
||||||
try {
|
try {
|
||||||
await this.page.evaluate((selector) => {
|
await this.page.evaluate((selector) => {
|
||||||
const elements = document.querySelectorAll(selector);
|
let elements = document.querySelectorAll(selector);
|
||||||
elements.forEach(el => el.remove());
|
elements.forEach(el => el.remove());
|
||||||
if (window.gc) window.gc();
|
if (window.gc) window.gc();
|
||||||
}, this.selectors.temporaryElements);
|
}, this.selectors.temporaryElements);
|
||||||
|
|||||||
@ -1,254 +1,8 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"text": "主数据",
|
|
||||||
"path": "主数据",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"text": "业务数据",
|
|
||||||
"path": "业务数据",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"text": "电池基础数据",
|
|
||||||
"path": "电池基础数据",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"text": "主需求计划",
|
|
||||||
"path": "主需求计划",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"text": "供需粗匹配",
|
|
||||||
"path": "供需粗匹配",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 6,
|
|
||||||
"text": "产线规划",
|
|
||||||
"path": "产线规划",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": 7,
|
"id": 7,
|
||||||
"text": "电池投放计划",
|
"text": "电池投放计划",
|
||||||
"path": "电池投放计划",
|
"path": "电池投放计划",
|
||||||
"hasThirdMenu": true
|
"hasThirdMenu": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 8,
|
|
||||||
"text": "主生产计划",
|
|
||||||
"path": "主生产计划",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 9,
|
|
||||||
"text": "基地生产计划",
|
|
||||||
"path": "基地生产计划",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 10,
|
|
||||||
"text": "ATP生成和发布",
|
|
||||||
"path": "ATP生成和发布",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 11,
|
|
||||||
"text": "ATP分配调整",
|
|
||||||
"path": "ATP分配调整",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 12,
|
|
||||||
"text": "ATP查询",
|
|
||||||
"path": "ATP查询",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 13,
|
|
||||||
"text": "产量预测",
|
|
||||||
"path": "产量预测",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 14,
|
|
||||||
"text": "入库预测",
|
|
||||||
"path": "入库预测",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 15,
|
|
||||||
"text": "硅片投入需求",
|
|
||||||
"path": "硅片投入需求",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 16,
|
|
||||||
"text": "硅片到货需求",
|
|
||||||
"path": "硅片到货需求",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 17,
|
|
||||||
"text": "硅片需求预测",
|
|
||||||
"path": "硅片需求预测",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 18,
|
|
||||||
"text": "硅片缺口审视",
|
|
||||||
"path": "硅片缺口审视",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 19,
|
|
||||||
"text": "电池需求数据",
|
|
||||||
"path": "电池需求数据",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 20,
|
|
||||||
"text": "基地产能利用率",
|
|
||||||
"path": "基地产能利用率",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 21,
|
|
||||||
"text": "电池生产计划",
|
|
||||||
"path": "电池生产计划",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 22,
|
|
||||||
"text": "入库节奏基础参数",
|
|
||||||
"path": "入库节奏基础参数",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 23,
|
|
||||||
"text": "入库节奏",
|
|
||||||
"path": "入库节奏",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 24,
|
|
||||||
"text": "电池基地生产计划",
|
|
||||||
"path": "电池基地生产计划",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 25,
|
|
||||||
"text": "电池入库比例",
|
|
||||||
"path": "电池入库比例",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 26,
|
|
||||||
"text": "电池入库计划",
|
|
||||||
"path": "电池入库计划",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 27,
|
|
||||||
"text": "电池要货计划",
|
|
||||||
"path": "电池要货计划",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 28,
|
|
||||||
"text": "电池发货计划",
|
|
||||||
"path": "电池发货计划",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 29,
|
|
||||||
"text": "jiahx测试",
|
|
||||||
"path": "jiahx测试",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 30,
|
|
||||||
"text": "业务参数",
|
|
||||||
"path": "业务参数",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 31,
|
|
||||||
"text": "计划对象",
|
|
||||||
"path": "计划对象",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 32,
|
|
||||||
"text": "排产优先级",
|
|
||||||
"path": "排产优先级",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 33,
|
|
||||||
"text": "逃生通道",
|
|
||||||
"path": "逃生通道",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 34,
|
|
||||||
"text": "主需求计划",
|
|
||||||
"path": "主需求计划",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 35,
|
|
||||||
"text": "电池投放",
|
|
||||||
"path": "电池投放",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 36,
|
|
||||||
"text": "供需粗匹配",
|
|
||||||
"path": "供需粗匹配",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 37,
|
|
||||||
"text": "ATP",
|
|
||||||
"path": "ATP",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 38,
|
|
||||||
"text": "电池要发货",
|
|
||||||
"path": "电池要发货",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 39,
|
|
||||||
"text": "主计划/基地计划",
|
|
||||||
"path": "主计划/基地计划",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 40,
|
|
||||||
"text": "基地计划",
|
|
||||||
"path": "基地计划",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 41,
|
|
||||||
"text": "产品系列(内部手工维护)",
|
|
||||||
"path": "产品系列(内部手工维护)",
|
|
||||||
"hasThirdMenu": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 42,
|
|
||||||
"text": "管理视图",
|
|
||||||
"path": "管理视图",
|
|
||||||
"hasThirdMenu": false
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1 +1,3 @@
|
|||||||
[]
|
[
|
||||||
|
7
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue
Block a user