import { test, describe } from 'node:test'; import assert from 'node:assert'; import { execSync } from 'child_process'; import { existsSync, mkdirSync, writeFileSync, rmSync } from 'fs'; import { join } from 'path'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); describe('CLI 功能集成测试', () => { const testDir = join(__dirname, 'fixtures'); const cliPath = join(__dirname, '..', '..', 'bin', 'index.js'); const projectRoot = join(__dirname, '..', '..'); test.before(() => { if (!existsSync(testDir)) { mkdirSync(testDir, { recursive: true }); } }); test.after(() => { // 清理测试文件 const filesToClean = [ 'vite.config.js', 'next.config.js', 'app/layout.tsx', 'pages/_document.tsx', 'test.html', 'public/index.html' ]; filesToClean.forEach(file => { const filePath = join(testDir, file); if (existsSync(filePath)) { rmSync(filePath); } }); const dirsToClean = ['app', 'pages', 'public']; dirsToClean.forEach(dir => { const dirPath = join(testDir, dir); if (existsSync(dirPath)) { rmSync(dirPath, { recursive: true }); } }); }); function runCli(args, options = {}) { try { const result = execSync(`node ${cliPath} ${args}`, { encoding: 'utf8', cwd: options.cwd || projectRoot, stdio: ['ignore', 'pipe', 'pipe'] }); return { success: true, output: result }; } catch (error) { return { success: false, output: error.stdout || error.message, code: error.status }; } } describe('基本 CLI 命令', () => { test('应该显示帮助信息', () => { const result = runCli('--help'); assert.strictEqual(result.success, true); assert.match(result.output, /dev-inject.*开发环境脚本注入工具/); assert.match(result.output, /--framework.*使用框架感知注入模式/); assert.match(result.output, /--remote.*脚本地址/); }); test('应该显示版本信息', () => { const result = runCli('--version'); assert.strictEqual(result.success, true); assert.match(result.output, /dev-inject v\d+\.\d+\.\d+/); }); test('应该处理无效参数', () => { const result = runCli('--invalid-option'); // 应该仍然成功(忽略未知选项) assert.strictEqual(result.success, true); }); test('应该在缺少参数时显示错误', () => { const result = runCli('install'); assert.strictEqual(result.success, false); assert.match(result.output, /install 命令需要 --remote 参数/); }); }); describe('框架感知命令', () => { test('应该检测到 Vite 项目', () => { // 创建 Vite 项目 writeFileSync(join(testDir, 'vite.config.js'), 'module.exports = { plugins: [] }'); const result = runCli('install --remote=/scripts/test.js --framework --dry-run', { cwd: testDir }); assert.strictEqual(result.success, true); assert.match(result.output, /检测到项目类型: vite/); assert.match(result.output, /DRY RUN/); }); test('应该检测到 Next.js App Router', () => { // 创建 Next.js App Router writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}'); mkdirSync(join(testDir, 'app'), { recursive: true }); writeFileSync(join(testDir, 'app', 'layout.tsx'), 'export default function Layout() {}'); const result = runCli('install --remote=/scripts/test.js --framework --dry-run', { cwd: testDir }); assert.strictEqual(result.success, true); assert.match(result.output, /检测到项目类型: next-app/); }); test('应该检测到 Next.js Pages Router', () => { // 创建 Next.js Pages Router writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}'); mkdirSync(join(testDir, 'pages'), { recursive: true }); writeFileSync(join(testDir, 'pages', '_document.tsx'), 'export default function Document() {}'); const result = runCli('install --remote=/scripts/test.js --framework --dry-run', { cwd: testDir }); assert.strictEqual(result.success, true); assert.match(result.output, /检测到项目类型: next-pages/); }); test('应该检测到 Create React App', () => { // Create React App mkdirSync(join(testDir, 'public'), { recursive: true }); writeFileSync(join(testDir, 'public', 'index.html'), ''); const result = runCli('install --remote=/scripts/test.js --framework --dry-run', { cwd: testDir }); assert.strictEqual(result.success, true); assert.match(result.output, /检测到项目类型: create-react-app/); }); test('应该检测到 HTML 项目', () => { writeFileSync(join(testDir, 'index.html'), ''); const result = runCli('install --remote=/scripts/test.js --framework --dry-run', { cwd: testDir }); assert.strictEqual(result.success, true); assert.match(result.output, /检测到项目类型: html-static/); }); }); describe('传统注入模式', () => { test('应该注入到 HTML 文件', () => { // 创建 HTML 文件 const htmlContent = `