Files
his/zentao_bug_fetch.js

154 lines
5.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { chromium } = require('playwright');
const fs = require('fs');
async function fetchBug(bugId) {
const browser = await chromium.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const context = await browser.newContext({
viewport: { width: 1920, height: 2000 }
});
const page = await context.newPage();
try {
const zentaoUrl = 'https://zentao.gentronhealth.com';
// Step 1: 访问登录页面
console.log('[Step 1] 访问登录页面...');
await page.goto(zentaoUrl + '/user-login.html', {
waitUntil: 'networkidle',
timeout: 60000
});
// Step 2: 登录
console.log('[Step 2] 登录...');
await page.waitForSelector('#account', { timeout: 10000 });
await page.fill('#account', 'admin');
await page.fill('input[name="password"]', 'Jchl1528');
await Promise.all([
page.click('#submit'),
page.waitForNavigation({ waitUntil: 'networkidle', timeout: 60000 })
]);
console.log('[Step 3] 登录成功');
await page.waitForTimeout(2000);
// Step 4: 访问BUG详情页面
console.log(`[Step 4] 访问 BUG #${bugId} ...`);
const bugUrl = zentaoUrl + '/index.php?m=bug&f=view&bugID=' + bugId;
await page.goto(bugUrl, {
waitUntil: 'networkidle',
timeout: 60000
});
await page.waitForTimeout(3000);
// Step 5: 关键使用frameLocator获取iframe内容
console.log('[Step 5] 获取iframe内容...');
const frame = page.frameLocator('iframe[name="app-qa"]');
const bodyElement = frame.locator('body');
// 等待iframe内容加载
await bodyElement.waitFor({ state: 'visible', timeout: 10000 }).catch(() => {});
// Step 6: 提取BUG信息
const bugData = await bodyElement.evaluate(() => {
const info = {
title: '',
description: '',
steps: '',
expected: '',
actual: '',
priority: '',
status: '',
module: '',
assignedTo: '',
openedBy: '',
bugType: '',
severity: '',
allText: document.body.innerText
};
// 获取标题
const titleEl = document.querySelector('.page-title, h1, h2, .title');
if (titleEl) {
info.title = titleEl.textContent.replace(/^\d+\s*/, '').trim();
}
// 获取表格数据
const rows = document.querySelectorAll('table.table-form tr');
rows.forEach(row => {
const th = row.querySelector('th');
const td = row.querySelector('td');
if (th && td) {
const label = th.textContent.trim();
const value = td.textContent.trim();
if (label.includes('所属模块')) info.module = value;
else if (label.includes('优先级')) info.priority = value;
else if (label.includes('Bug状态') || label.includes('状态')) info.status = value;
else if (label.includes('指派给')) info.assignedTo = value;
else if (label.includes('创建')) info.openedBy = value;
else if (label.includes('Bug类型')) info.bugType = value;
else if (label.includes('严重程度')) info.severity = value;
}
});
return info;
});
// 从完整文本提取描述和步骤
const fullText = bugData.allText;
const descMatch = fullText.match(/\[步骤\]([\s\S]*?)\[结果\]/);
if (descMatch) bugData.steps = descMatch[1].trim();
const actualMatch = fullText.match(/\[结果\]([\s\S]*?)\[期望\]/);
if (actualMatch) bugData.actual = actualMatch[1].trim();
const expectedMatch = fullText.match(/\[期望\]([\s\S]*?)(?=历史记录|$)/);
if (expectedMatch) bugData.expected = expectedMatch[1].trim();
// 输出结果
console.log('\n==== BUG #' + bugId + ' 详细信息 ====');
console.log(JSON.stringify(bugData, null, 2));
// 保存到文件
fs.writeFileSync(`zentao_bug_${bugId}_parsed.json`, JSON.stringify(bugData, null, 2));
// 保存截图
await page.screenshot({ path: `zentao_bug_${bugId}.png`, fullPage: true });
return { success: true, data: bugData };
} catch (error) {
console.error('[Error]', error.message);
await page.screenshot({ path: `zentao_bug_${bugId}_error.png`, fullPage: true });
return { success: false, error: error.message };
} finally {
await browser.close();
}
}
// 主函数
async function main() {
const bugId = 320;
console.log(`开始获取禅道 BUG #${bugId}...`);
const result = await fetchBug(bugId);
if (!result.success) {
console.log('\n❌ 获取失败!');
process.exit(1);
}
console.log('\n✅ 获取成功!');
}
main();