AI_UIAutomation/scripts/sync-ones-results.ts

111 lines
3.6 KiB
TypeScript

/**
* ONES 测试计划结果同步脚本
*
* 用法:
* npx ts-node scripts/sync-ones-results.ts --plan <PLAN_UUID> [--dry-run]
*
* 流程:
* 1. 读取 reports/.results.json (自动化执行后的结果)
* 2. 从 ONES 拉取测试计划用例列表
* 3. 按用例名称匹配
* 4. 反写匹配成功的结果到 ONES
*/
import * as fs from 'fs';
import * as path from 'path';
import { TestResult } from '../utils/test-reporter';
import { fetchPlanCases, matchResults, syncResultsToOnes } from '../utils/ones-sync';
import { execSync } from 'child_process';
const ONES_CLI = '/Users/woan/local/bin/ones';
const RESULTS_FILE = path.resolve(__dirname, '../reports/.results.json');
function parseArgs() {
const args = process.argv.slice(2);
let planUUID = '';
let dryRun = false;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--plan' && args[i + 1]) {
planUUID = args[i + 1];
i++;
} else if (args[i] === '--dry-run') {
dryRun = true;
}
}
if (!planUUID) {
console.error('Usage: npx ts-node scripts/sync-ones-results.ts --plan <PLAN_UUID> [--dry-run]');
process.exit(1);
}
return { planUUID, dryRun };
}
function loadResults(): TestResult[] {
if (!fs.existsSync(RESULTS_FILE)) {
console.error(`结果文件不存在: ${RESULTS_FILE}`);
console.error('请先运行自动化测试以生成结果文件');
process.exit(1);
}
const data = JSON.parse(fs.readFileSync(RESULTS_FILE, 'utf-8'));
return data.results || [];
}
function main() {
const { planUUID, dryRun } = parseArgs();
console.log('='.repeat(60));
console.log(' ONES 测试计划结果同步');
console.log('='.repeat(60));
console.log(` 计划UUID: ${planUUID}`);
console.log(` 模式: ${dryRun ? '预览 (dry-run)' : '实际写入'}`);
console.log('-'.repeat(60));
// 1. 加载自动化结果
const testResults = loadResults();
console.log(`\n[1/4] 加载自动化结果: ${testResults.length}`);
const passed = testResults.filter(r => r.status === 'PASS').length;
const failed = testResults.filter(r => r.status === 'FAIL').length;
const skipped = testResults.filter(r => r.status === 'SKIP').length;
console.log(` PASS: ${passed} | FAIL: ${failed} | SKIP: ${skipped}`);
// 2. 从 ONES 拉取计划用例
console.log(`\n[2/4] 从 ONES 拉取测试计划用例 ...`);
const planCases = fetchPlanCases(planUUID);
console.log(` 计划共 ${planCases.length} 条用例`);
// 3. 匹配
console.log(`\n[3/4] 匹配自动化结果到 ONES 用例 ...`);
const matched = matchResults(planCases, testResults);
console.log(` 匹配成功: ${matched.size} / ${testResults.length}`);
if (matched.size > 0) {
console.log('\n 匹配详情:');
for (const [caseUUID, { result }] of matched) {
const pc = planCases.find(c => c.caseUUID === caseUUID);
const icon = result === 'passed' ? '✓' : result === 'failed' ? '✗' : '○';
console.log(` ${icon} [${result}] ${pc?.caseName || caseUUID}`);
}
}
// 4. 反写
if (dryRun) {
console.log(`\n[4/4] DRY-RUN 模式,跳过实际写入`);
console.log(` 将会更新 ${matched.size} 条用例结果`);
} else {
console.log(`\n[4/4] 反写结果到 ONES ...`);
const configStr = execSync(`${ONES_CLI} config show`, { encoding: 'utf-8' });
const config = JSON.parse(configStr);
const { success, failed: failCount } = syncResultsToOnes(planUUID, matched, config.user_id);
console.log(` 成功: ${success} | 失败: ${failCount}`);
}
console.log('\n' + '='.repeat(60));
console.log(' 同步完成');
console.log('='.repeat(60));
}
main();