提交qiming-dev-inject

This commit is contained in:
Codex
2026-06-01 12:53:19 +08:00
parent 96af3b324b
commit 9e9486b7c2
76 changed files with 6397 additions and 0 deletions

View 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);
}