提交qiming-dev-inject
This commit is contained in:
223
qiming-dev-inject/scripts/dev-monitor.js
Normal file
223
qiming-dev-inject/scripts/dev-monitor.js
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* 开发环境监控脚本
|
||||
* 提供错误监控、性能监控、通信功能
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// 配置
|
||||
const config = {
|
||||
version: '1.0.0',
|
||||
enabled: true,
|
||||
logLevel: 'error', // 只记录错误级别日志
|
||||
maxErrors: 10, // 减少存储量
|
||||
maxLogs: 20, // 减少存储量
|
||||
};
|
||||
|
||||
// 简化的监控数据存储
|
||||
const monitorData = {
|
||||
errors: [],
|
||||
basicInfo: {
|
||||
url: window.location.href,
|
||||
userAgent: navigator.userAgent.split(' ')[0], // 只保留浏览器名称
|
||||
},
|
||||
ready: false,
|
||||
};
|
||||
|
||||
// 简化的日志函数 - 只记录错误
|
||||
const logger = {
|
||||
error: (message, details = null) => {
|
||||
console.error('[Dev-Monitor ERROR]', message, details || '');
|
||||
|
||||
const errorData = {
|
||||
message: typeof message === 'string' ? message : message.toString(),
|
||||
details: details ? JSON.stringify(details).substring(0, 200) : null, // 限制详细信息长度
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
monitorData.errors.push(errorData);
|
||||
|
||||
// 限制错误数量
|
||||
if (monitorData.errors.length > config.maxErrors) {
|
||||
monitorData.errors.shift();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// 简化的错误监控
|
||||
function setupErrorMonitoring() {
|
||||
// 全局错误捕获
|
||||
window.addEventListener('error', function (event) {
|
||||
const errorMsg = `${event.message} at ${event.filename}:${event.lineno}:${event.colno}`;
|
||||
logger.error(errorMsg);
|
||||
});
|
||||
|
||||
// Promise 错误捕获
|
||||
window.addEventListener('unhandledrejection', function (event) {
|
||||
const errorMsg = `Promise rejection: ${event.reason}`;
|
||||
logger.error(errorMsg);
|
||||
});
|
||||
|
||||
// 资源加载错误 - 只记录关键信息
|
||||
window.addEventListener(
|
||||
'error',
|
||||
function (event) {
|
||||
if (event.target !== window) {
|
||||
const source = event.target.src || event.target.href || 'unknown';
|
||||
logger.error(`Resource failed: ${source}`);
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// 移除复杂的性能监控和控制台拦截,专注于核心错误监控
|
||||
|
||||
// 简化的通信功能
|
||||
function setupCommunication() {
|
||||
// 向父窗口发送监控数据 - 只在有新错误时发送
|
||||
function sendToParent() {
|
||||
if (
|
||||
window.parent &&
|
||||
window.parent !== window &&
|
||||
monitorData.errors.length > 0
|
||||
) {
|
||||
try {
|
||||
const summary = {
|
||||
type: 'dev-monitor-summary',
|
||||
errorCount: monitorData.errors.length,
|
||||
latestError: monitorData.errors[monitorData.errors.length - 1],
|
||||
url: monitorData.basicInfo.url,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
window.parent.postMessage(summary, '*');
|
||||
} catch (e) {
|
||||
// 静默处理错误
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 监听来自父窗口的请求
|
||||
window.addEventListener('message', function (event) {
|
||||
if (event.data && event.data.type === 'dev-monitor-request') {
|
||||
const summary = {
|
||||
type: 'dev-monitor-data',
|
||||
errorCount: monitorData.errors.length,
|
||||
errors: monitorData.errors.slice(-3), // 只发送最近3个错误
|
||||
url: monitorData.basicInfo.url,
|
||||
};
|
||||
|
||||
try {
|
||||
window.parent.postMessage(summary, '*');
|
||||
} catch (e) {
|
||||
// 静默处理错误
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 降低发送频率 - 每10秒检查一次
|
||||
setInterval(sendToParent, 10000);
|
||||
}
|
||||
|
||||
// 简化的全局 API
|
||||
window.DevMonitor = {
|
||||
// 获取错误统计
|
||||
getStats: function () {
|
||||
return {
|
||||
errorCount: monitorData.errors.length,
|
||||
url: monitorData.basicInfo.url,
|
||||
userAgent: monitorData.basicInfo.userAgent,
|
||||
latestError: monitorData.errors[monitorData.errors.length - 1] || null,
|
||||
};
|
||||
},
|
||||
|
||||
// 获取所有错误(限制数量)
|
||||
getErrors: function () {
|
||||
return monitorData.errors.slice(-5); // 只返回最近5个错误
|
||||
},
|
||||
|
||||
// 清除错误
|
||||
clearErrors: function () {
|
||||
monitorData.errors = [];
|
||||
console.log('✅ DevMonitor errors cleared');
|
||||
},
|
||||
|
||||
// 显示简化监控面板
|
||||
showPanel: function () {
|
||||
// 移除现有面板
|
||||
const existingPanel = document.getElementById('dev-monitor-panel');
|
||||
if (existingPanel) {
|
||||
existingPanel.remove();
|
||||
}
|
||||
|
||||
const panel = document.createElement('div');
|
||||
panel.id = 'dev-monitor-panel';
|
||||
panel.style.cssText = `
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 280px;
|
||||
background: #1a1a1a;
|
||||
color: white;
|
||||
border: 1px solid #333;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
z-index: 999999;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
||||
`;
|
||||
|
||||
const errors = monitorData.errors.slice(-3); // 只显示最近3个错误
|
||||
|
||||
panel.innerHTML = `
|
||||
<div style="border-bottom: 1px solid #333; margin-bottom: 10px; padding-bottom: 8px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<strong style="color: #4CAF50;">DevMonitor</strong>
|
||||
<button onclick="this.parentElement.parentElement.remove()" style="background: #ff4444; border: none; color: white; padding: 2px 6px; border-radius: 3px; cursor: pointer;">×</button>
|
||||
</div>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<strong>Errors (${monitorData.errors.length}):</strong>
|
||||
</div>
|
||||
${
|
||||
errors.length
|
||||
? errors
|
||||
.map(
|
||||
e => `
|
||||
<div style="color: #ff6b6b; margin: 4px 0; padding: 4px; background: rgba(255,107,107,0.1); border-radius: 3px; font-size: 11px;">
|
||||
${e.message}
|
||||
${e.details ? `<br><small style="color: #999;">${e.details}</small>` : ''}
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.join('')
|
||||
: '<div style="color: #666; font-style: italic;">No errors</div>'
|
||||
}
|
||||
<div style="margin-top: 10px; padding-top: 10px; border-top: 1px solid #333;">
|
||||
<button onclick="DevMonitor.clearErrors(); DevMonitor.showPanel();" style="background: #333; border: none; color: white; padding: 6px 12px; border-radius: 3px; cursor: pointer; margin-right: 8px;">Clear</button>
|
||||
<button onclick="console.log('Stats:', DevMonitor.getStats())" style="background: #2196F3; border: none; color: white; padding: 6px 12px; border-radius: 3px; cursor: pointer;">Stats</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(panel);
|
||||
},
|
||||
};
|
||||
|
||||
// 简化的初始化
|
||||
function init() {
|
||||
setupErrorMonitoring();
|
||||
setupCommunication();
|
||||
monitorData.ready = true;
|
||||
|
||||
// 简化的控制台提示
|
||||
console.log(
|
||||
'%cDevMonitor v' + config.version,
|
||||
'color: #4CAF50; font-weight: bold;',
|
||||
'- DevMonitor.showPanel()'
|
||||
);
|
||||
}
|
||||
|
||||
// 立即初始化
|
||||
init();
|
||||
})();
|
||||
534
qiming-dev-inject/scripts/test-projects.js
Normal file
534
qiming-dev-inject/scripts/test-projects.js
Normal file
@@ -0,0 +1,534 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* 测试脚本 - 运行所有 test-projects 的注入和卸载测试
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const rootDir = join(__dirname, '..');
|
||||
const testProjectsDir = join(rootDir, 'test-projects');
|
||||
|
||||
// 测试项目列表
|
||||
const testProjects = [
|
||||
{ name: 'html-project', type: 'html-static' },
|
||||
{ name: 'vite-project', type: 'vite' },
|
||||
{ name: 'next-pages-project', type: 'next-pages' },
|
||||
{ name: 'next-app-project', type: 'next-app' },
|
||||
];
|
||||
|
||||
// 测试配置
|
||||
const testConfig = {
|
||||
remote: '/sdk/dev-monitor.js',
|
||||
remoteUrl: 'https://testagent.xspaceagi.com/sdk/dev-monitor.js',
|
||||
};
|
||||
|
||||
// 颜色输出
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
bright: '\x1b[1m',
|
||||
green: '\x1b[32m',
|
||||
red: '\x1b[31m',
|
||||
yellow: '\x1b[33m',
|
||||
blue: '\x1b[34m',
|
||||
cyan: '\x1b[36m',
|
||||
};
|
||||
|
||||
function log(message, color = 'reset') {
|
||||
console.log(`${colors[color]}${message}${colors.reset}`);
|
||||
}
|
||||
|
||||
function logSection(title) {
|
||||
console.log('\n' + '='.repeat(60));
|
||||
log(title, 'bright');
|
||||
console.log('='.repeat(60));
|
||||
}
|
||||
|
||||
function logTest(name) {
|
||||
log(`\n📦 测试项目: ${name}`, 'cyan');
|
||||
}
|
||||
|
||||
function runCommand(command, cwd) {
|
||||
try {
|
||||
const output = execSync(command, {
|
||||
cwd,
|
||||
encoding: 'utf8',
|
||||
stdio: 'pipe',
|
||||
});
|
||||
return { success: true, output };
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
output: error.stdout || error.stderr || error.message,
|
||||
error: error.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试单个项目的安装(注入)
|
||||
*/
|
||||
function testInstall(project, remote, testName) {
|
||||
const projectPath = join(testProjectsDir, project.name);
|
||||
|
||||
if (!existsSync(projectPath)) {
|
||||
log(` ❌ 项目目录不存在: ${projectPath}`, 'red');
|
||||
return false;
|
||||
}
|
||||
|
||||
logTest(`${project.name} (${testName})`);
|
||||
|
||||
// 1. 先清理之前的注入(可选)
|
||||
log(' 🔄 步骤 1: 清理之前的注入...', 'yellow');
|
||||
const uninstallResult = runCommand(
|
||||
`node ${join(rootDir, 'bin/index.js')} uninstall --framework`,
|
||||
projectPath
|
||||
);
|
||||
|
||||
if (!uninstallResult.success && !uninstallResult.output.includes('未找到需要清理的注入脚本')) {
|
||||
log(` ⚠️ 清理警告: ${uninstallResult.output}`, 'yellow');
|
||||
}
|
||||
|
||||
// 2. 执行注入
|
||||
log(' ➕ 步骤 2: 注入脚本...', 'yellow');
|
||||
const installResult = runCommand(
|
||||
`node ${join(rootDir, 'bin/index.js')} install --remote=${remote} --framework`,
|
||||
projectPath
|
||||
);
|
||||
|
||||
if (!installResult.success) {
|
||||
log(` ❌ 注入失败: ${installResult.error}`, 'red');
|
||||
console.log(installResult.output);
|
||||
return false;
|
||||
}
|
||||
|
||||
log(' ✅ 注入成功', 'green');
|
||||
|
||||
// 3. 验证注入结果
|
||||
log(' 🔍 步骤 3: 验证注入结果...', 'yellow');
|
||||
const verifyResult = verifyInjection(project, projectPath);
|
||||
|
||||
if (!verifyResult.success) {
|
||||
log(` ❌ 验证失败: ${verifyResult.message}`, 'red');
|
||||
return false;
|
||||
}
|
||||
|
||||
log(' ✅ 验证通过', 'green');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试单个项目的卸载
|
||||
*/
|
||||
function testUninstall(project) {
|
||||
const projectPath = join(testProjectsDir, project.name);
|
||||
|
||||
if (!existsSync(projectPath)) {
|
||||
log(` ❌ 项目目录不存在: ${projectPath}`, 'red');
|
||||
return false;
|
||||
}
|
||||
|
||||
logTest(`${project.name}`);
|
||||
|
||||
// 1. 先确保有注入内容(如果没有,先注入)
|
||||
log(' 🔍 步骤 1: 检查是否有注入内容...', 'yellow');
|
||||
const hasInjection = checkInjection(project, projectPath);
|
||||
|
||||
if (!hasInjection) {
|
||||
log(' ⚠️ 未找到注入内容,先执行注入...', 'yellow');
|
||||
const installResult = runCommand(
|
||||
`node ${join(rootDir, 'bin/index.js')} install --remote=/sdk/dev-monitor.js --framework`,
|
||||
projectPath
|
||||
);
|
||||
|
||||
if (!installResult.success) {
|
||||
log(` ❌ 预注入失败: ${installResult.error}`, 'red');
|
||||
return false;
|
||||
}
|
||||
log(' ✅ 预注入成功', 'green');
|
||||
}
|
||||
|
||||
// 2. 执行卸载
|
||||
log(' 🗑️ 步骤 2: 卸载注入...', 'yellow');
|
||||
const uninstallResult = runCommand(
|
||||
`node ${join(rootDir, 'bin/index.js')} uninstall --framework`,
|
||||
projectPath
|
||||
);
|
||||
|
||||
if (!uninstallResult.success) {
|
||||
log(` ❌ 卸载失败: ${uninstallResult.error}`, 'red');
|
||||
console.log(uninstallResult.output);
|
||||
return false;
|
||||
}
|
||||
|
||||
log(' ✅ 卸载成功', 'green');
|
||||
|
||||
// 3. 验证卸载结果
|
||||
log(' 🔍 步骤 3: 验证卸载结果...', 'yellow');
|
||||
const verifyResult = verifyUninstall(project, projectPath);
|
||||
|
||||
if (!verifyResult.success) {
|
||||
log(` ❌ 验证失败: ${verifyResult.message}`, 'red');
|
||||
return false;
|
||||
}
|
||||
|
||||
log(' ✅ 验证通过', 'green');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有注入内容
|
||||
*/
|
||||
function checkInjection(project, projectPath) {
|
||||
try {
|
||||
switch (project.type) {
|
||||
case 'html-static': {
|
||||
const htmlFile = join(projectPath, 'index.html');
|
||||
if (existsSync(htmlFile)) {
|
||||
const content = readFileSync(htmlFile, 'utf8');
|
||||
return content.includes('DEV-INJECT-START');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 'vite': {
|
||||
const configFile = join(projectPath, 'vite.config.js');
|
||||
if (existsSync(configFile)) {
|
||||
const content = readFileSync(configFile, 'utf8');
|
||||
return content.includes('DEV-INJECT-START');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 'next-pages': {
|
||||
const docFile = join(projectPath, 'pages/_document.tsx');
|
||||
if (existsSync(docFile)) {
|
||||
const content = readFileSync(docFile, 'utf8');
|
||||
return content.includes('DEV-INJECT-START');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 'next-app': {
|
||||
const layoutFile = join(projectPath, 'app/layout.tsx');
|
||||
if (existsSync(layoutFile)) {
|
||||
const content = readFileSync(layoutFile, 'utf8');
|
||||
return content.includes('DEV-INJECT-START');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证注入结果
|
||||
*/
|
||||
function verifyInjection(project, projectPath) {
|
||||
try {
|
||||
switch (project.type) {
|
||||
case 'html-static': {
|
||||
const htmlFile = join(projectPath, 'index.html');
|
||||
const content = readFileSync(htmlFile, 'utf8');
|
||||
if (!content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: 'HTML 文件中未找到注入标记' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'vite': {
|
||||
const configFile = join(projectPath, 'vite.config.js');
|
||||
const content = readFileSync(configFile, 'utf8');
|
||||
if (!content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: 'Vite 配置文件中未找到注入标记' };
|
||||
}
|
||||
// 验证逗号位置(允许多种格式)
|
||||
if (!content.includes('// <!-- DEV-INJECT-END -->')) {
|
||||
return { success: false, message: '未找到结束标记' };
|
||||
}
|
||||
// 验证 index.html 未被修改
|
||||
const htmlFile = join(projectPath, 'index.html');
|
||||
const htmlContent = readFileSync(htmlFile, 'utf8');
|
||||
if (htmlContent.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: 'index.html 不应包含注入标记' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'next-pages': {
|
||||
const docFile = join(projectPath, 'pages/_document.tsx');
|
||||
if (existsSync(docFile)) {
|
||||
const content = readFileSync(docFile, 'utf8');
|
||||
if (!content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: '_document.tsx 中未找到注入标记' };
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'next-app': {
|
||||
const layoutFile = join(projectPath, 'app/layout.tsx');
|
||||
if (existsSync(layoutFile)) {
|
||||
const content = readFileSync(layoutFile, 'utf8');
|
||||
if (!content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: 'layout.tsx 中未找到注入标记' };
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, message: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证卸载结果
|
||||
*/
|
||||
function verifyUninstall(project, projectPath) {
|
||||
try {
|
||||
switch (project.type) {
|
||||
case 'html-static': {
|
||||
const htmlFile = join(projectPath, 'index.html');
|
||||
const content = readFileSync(htmlFile, 'utf8');
|
||||
if (content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: 'HTML 文件中仍存在注入标记' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'vite': {
|
||||
const configFile = join(projectPath, 'vite.config.js');
|
||||
const content = readFileSync(configFile, 'utf8');
|
||||
if (content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: 'Vite 配置文件中仍存在注入标记' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'next-pages': {
|
||||
const docFile = join(projectPath, 'pages/_document.tsx');
|
||||
if (existsSync(docFile)) {
|
||||
const content = readFileSync(docFile, 'utf8');
|
||||
if (content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: '_document.tsx 中仍存在注入标记' };
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'next-app': {
|
||||
const layoutFile = join(projectPath, 'app/layout.tsx');
|
||||
if (existsSync(layoutFile)) {
|
||||
const content = readFileSync(layoutFile, 'utf8');
|
||||
if (content.includes('DEV-INJECT-START')) {
|
||||
return { success: false, message: 'layout.tsx 中仍存在注入标记' };
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, message: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行安装测试
|
||||
*/
|
||||
function runInstallTests() {
|
||||
logSection('🚀 开始运行安装(注入)测试');
|
||||
log(`测试目录: ${testProjectsDir}`, 'blue');
|
||||
log(`测试项目数量: ${testProjects.length}`, 'blue');
|
||||
|
||||
const results = {
|
||||
total: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
projects: [],
|
||||
};
|
||||
|
||||
// 测试本地路径注入
|
||||
logSection('📝 测试 1: 本地路径注入 (/sdk/dev-monitor.js)');
|
||||
|
||||
for (const project of testProjects) {
|
||||
results.total++;
|
||||
const success = testInstall(project, testConfig.remote, '本地路径');
|
||||
results.projects.push({ project: project.name, test: '本地路径', success });
|
||||
|
||||
if (success) {
|
||||
results.passed++;
|
||||
} else {
|
||||
results.failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试远程 URL 注入
|
||||
logSection('🌐 测试 2: 远程 URL 注入 (https://testagent.xspaceagi.com/sdk/dev-monitor.js)');
|
||||
|
||||
for (const project of testProjects) {
|
||||
results.total++;
|
||||
const success = testInstall(project, testConfig.remoteUrl, '远程URL');
|
||||
results.projects.push({ project: project.name, test: '远程URL', success });
|
||||
|
||||
if (success) {
|
||||
results.passed++;
|
||||
} else {
|
||||
results.failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// 输出测试结果
|
||||
logSection('📊 安装测试结果汇总');
|
||||
log(`总测试数: ${results.total}`, 'blue');
|
||||
log(`通过: ${results.passed}`, 'green');
|
||||
log(`失败: ${results.failed}`, results.failed > 0 ? 'red' : 'green');
|
||||
|
||||
console.log('\n详细结果:');
|
||||
results.projects.forEach(({ project, test, success }) => {
|
||||
const icon = success ? '✅' : '❌';
|
||||
const color = success ? 'green' : 'red';
|
||||
log(` ${icon} ${project} - ${test}`, color);
|
||||
});
|
||||
|
||||
// 返回退出码
|
||||
process.exit(results.failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行卸载测试
|
||||
*/
|
||||
function runUninstallTests() {
|
||||
logSection('🚀 开始运行卸载测试');
|
||||
log(`测试目录: ${testProjectsDir}`, 'blue');
|
||||
log(`测试项目数量: ${testProjects.length}`, 'blue');
|
||||
|
||||
const results = {
|
||||
total: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
projects: [],
|
||||
};
|
||||
|
||||
for (const project of testProjects) {
|
||||
results.total++;
|
||||
const success = testUninstall(project);
|
||||
results.projects.push({ project: project.name, success });
|
||||
|
||||
if (success) {
|
||||
results.passed++;
|
||||
} else {
|
||||
results.failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// 输出测试结果
|
||||
logSection('📊 卸载测试结果汇总');
|
||||
log(`总测试数: ${results.total}`, 'blue');
|
||||
log(`通过: ${results.passed}`, 'green');
|
||||
log(`失败: ${results.failed}`, results.failed > 0 ? 'red' : 'green');
|
||||
|
||||
console.log('\n详细结果:');
|
||||
results.projects.forEach(({ project, success }) => {
|
||||
const icon = success ? '✅' : '❌';
|
||||
const color = success ? 'green' : 'red';
|
||||
log(` ${icon} ${project}`, color);
|
||||
});
|
||||
|
||||
// 返回退出码
|
||||
process.exit(results.failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行所有测试(安装 + 卸载)
|
||||
*/
|
||||
function runAllTests() {
|
||||
logSection('🚀 开始运行完整测试(安装 + 卸载)');
|
||||
log(`测试目录: ${testProjectsDir}`, 'blue');
|
||||
log(`测试项目数量: ${testProjects.length}`, 'blue');
|
||||
|
||||
const results = {
|
||||
total: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
projects: [],
|
||||
};
|
||||
|
||||
// 先运行安装测试
|
||||
logSection('📝 第一部分: 安装测试');
|
||||
|
||||
for (const project of testProjects) {
|
||||
results.total++;
|
||||
const success = testInstall(project, testConfig.remote, '本地路径');
|
||||
results.projects.push({ project: project.name, test: '安装', success });
|
||||
|
||||
if (success) {
|
||||
results.passed++;
|
||||
} else {
|
||||
results.failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// 再运行卸载测试
|
||||
logSection('🗑️ 第二部分: 卸载测试');
|
||||
|
||||
for (const project of testProjects) {
|
||||
results.total++;
|
||||
const success = testUninstall(project);
|
||||
results.projects.push({ project: project.name, test: '卸载', success });
|
||||
|
||||
if (success) {
|
||||
results.passed++;
|
||||
} else {
|
||||
results.failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// 输出测试结果
|
||||
logSection('📊 完整测试结果汇总');
|
||||
log(`总测试数: ${results.total}`, 'blue');
|
||||
log(`通过: ${results.passed}`, 'green');
|
||||
log(`失败: ${results.failed}`, results.failed > 0 ? 'red' : 'green');
|
||||
|
||||
console.log('\n详细结果:');
|
||||
results.projects.forEach(({ project, test, success }) => {
|
||||
const icon = success ? '✅' : '❌';
|
||||
const color = success ? 'green' : 'red';
|
||||
log(` ${icon} ${project} - ${test}`, color);
|
||||
});
|
||||
|
||||
// 返回退出码
|
||||
process.exit(results.failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
// 解析命令行参数
|
||||
const args = process.argv.slice(2);
|
||||
const command = args[0] || 'all';
|
||||
|
||||
// 运行测试
|
||||
try {
|
||||
switch (command) {
|
||||
case 'install':
|
||||
case 'i':
|
||||
runInstallTests();
|
||||
break;
|
||||
case 'uninstall':
|
||||
case 'u':
|
||||
runUninstallTests();
|
||||
break;
|
||||
case 'all':
|
||||
default:
|
||||
runAllTests();
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
log(`\n❌ 测试执行失败: ${error.message}`, 'red');
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user