提交qiming-dev-inject
This commit is contained in:
313
qiming-dev-inject/test/integration/cli.test.js
Normal file
313
qiming-dev-inject/test/integration/cli.test.js
Normal file
@@ -0,0 +1,313 @@
|
||||
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'), '<html></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'), '<html></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 = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
</body>
|
||||
</html>`;
|
||||
writeFileSync(join(testDir, 'test.html'), htmlContent);
|
||||
|
||||
const result = runCli('install --remote=/scripts/test.js --file=./test.html --dry-run', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
assert.match(result.output, /DRY RUN.*将注入脚本到.*test\.html/);
|
||||
});
|
||||
|
||||
test('应该查找多个 HTML 文件', () => {
|
||||
// 创建多个 HTML 文件
|
||||
writeFileSync(join(testDir, 'index.html'), '<html></html>');
|
||||
writeFileSync(join(testDir, 'test.html'), '<html></html>');
|
||||
|
||||
const result = runCli('install --remote=/scripts/test.js --dry-run', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
assert.match(result.output, /找到 \d+ 个 HTML 文件/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('卸载功能', () => {
|
||||
test('应该支持传统卸载', () => {
|
||||
writeFileSync(join(testDir, 'test.html'), '<html></html>');
|
||||
|
||||
const result = runCli('uninstall --file=./test.html --dry-run', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
assert.match(result.output, /卸载脚本/);
|
||||
});
|
||||
|
||||
test('应该支持框架卸载', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'module.exports = { plugins: [] }');
|
||||
|
||||
const result = runCli('uninstall --framework --dry-run', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
// 框架卸载的输出可能不同
|
||||
});
|
||||
});
|
||||
|
||||
describe('详细输出模式', () => {
|
||||
test('应该显示详细的注入信息', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'module.exports = { plugins: [] }');
|
||||
|
||||
const result = runCli('install --remote=/scripts/test.js --framework --dry-run --verbose', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
assert.match(result.output, /脚本类型:/);
|
||||
assert.match(result.output, /脚本标签:/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('错误处理', () => {
|
||||
test('应该处理不存在的文件', () => {
|
||||
const result = runCli('install --remote=/scripts/test.js --file=./nonexistent.html', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, false);
|
||||
assert.match(result.output, /未找到 HTML 文件/);
|
||||
});
|
||||
|
||||
test('应该处理权限问题', () => {
|
||||
// 创建只读目录(在某些系统上可能不支持)
|
||||
try {
|
||||
mkdirSync(join(testDir, 'readonly'), { recursive: true, mode: 0o444 });
|
||||
|
||||
const result = runCli('install --remote=/scripts/test.js --file=./readonly/test.html', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
// 应该有某种错误处理
|
||||
assert.ok(true);
|
||||
} catch (error) {
|
||||
// 忽略权限相关的错误
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('参数验证', () => {
|
||||
test('应该验证远程 URL 格式', () => {
|
||||
const result = runCli('install --remote=invalid-url --framework --dry-run', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
// 应该仍然接受,验证在实际注入时进行
|
||||
assert.strictEqual(result.success, true);
|
||||
});
|
||||
|
||||
test('应该处理空参数', () => {
|
||||
const result = runCli('install --remote= --framework --dry-run', {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
});
|
||||
|
||||
test('应该处理长参数', () => {
|
||||
const longRemote = 'https://example.com/' + 'a'.repeat(100) + '/script.js';
|
||||
const result = runCli(`install --remote=${longRemote} --framework --dry-run`, {
|
||||
cwd: testDir
|
||||
});
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('性能测试', () => {
|
||||
test('应该在合理时间内完成', () => {
|
||||
// 创建一些文件
|
||||
for (let i = 0; i < 10; i++) {
|
||||
writeFileSync(join(testDir, `test${i}.html`), '<html></html>');
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
const result = runCli('install --remote=/scripts/test.js --dry-run', {
|
||||
cwd: testDir
|
||||
});
|
||||
const endTime = Date.now();
|
||||
|
||||
assert.strictEqual(result.success, true);
|
||||
assert(endTime - startTime < 5000, 'CLI 命令应该在 5 秒内完成');
|
||||
});
|
||||
});
|
||||
});
|
||||
1
qiming-dev-inject/test/integration/fixtures/index.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/index.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test0.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test0.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test1.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test1.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test2.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test2.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test3.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test3.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test4.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test4.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test5.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test5.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test6.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test6.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test7.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test7.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test8.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test8.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/integration/fixtures/test9.html
Normal file
1
qiming-dev-inject/test/integration/fixtures/test9.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
409
qiming-dev-inject/test/integration/smartInject.test.js
Normal file
409
qiming-dev-inject/test/integration/smartInject.test.js
Normal file
@@ -0,0 +1,409 @@
|
||||
import { test, describe } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
import { existsSync, mkdirSync, writeFileSync, rmSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// 导入要测试的模块
|
||||
import { smartInject } from '../../lib/framework-inject.js';
|
||||
|
||||
describe('框架注入集成测试', () => {
|
||||
const testDir = join(__dirname, 'fixtures');
|
||||
|
||||
test.before(() => {
|
||||
if (!existsSync(testDir)) {
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
test.after(() => {
|
||||
// 清理所有测试文件
|
||||
const filesToClean = [
|
||||
'vite.config.js',
|
||||
'vite.config.ts',
|
||||
'next.config.js',
|
||||
'app/layout.tsx',
|
||||
'app/layout.js',
|
||||
'pages/_document.tsx',
|
||||
'pages/_document.js',
|
||||
'test.html'
|
||||
];
|
||||
|
||||
filesToClean.forEach(file => {
|
||||
const filePath = join(testDir, file);
|
||||
if (existsSync(filePath)) {
|
||||
rmSync(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
const dirsToClean = ['app', 'pages'];
|
||||
dirsToClean.forEach(dir => {
|
||||
const dirPath = join(testDir, dir);
|
||||
if (existsSync(dirPath)) {
|
||||
rmSync(dirPath, { recursive: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Vite 项目注入', () => {
|
||||
test('应该成功注入到 Vite 配置文件', () => {
|
||||
// 创建 Vite 配置文件
|
||||
const viteConfig = `import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
port: 3000
|
||||
}
|
||||
})`;
|
||||
writeFileSync(join(testDir, 'vite.config.js'), viteConfig);
|
||||
|
||||
// 执行注入
|
||||
const result = smartInject({
|
||||
remote: 'http://localhost:9000/dev-monitor.js',
|
||||
dryRun: true,
|
||||
verbose: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
|
||||
test('应该检查已存在的插件', () => {
|
||||
// 创建已有插件的 Vite 配置
|
||||
const viteConfigWithPlugin = `import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
// dev-inject-plugin
|
||||
{
|
||||
name: 'dev-inject-plugin',
|
||||
transformIndexHtml(html) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return html.replace('</head>', '<script src="/existing.js"></script></head>');
|
||||
}
|
||||
return html;
|
||||
}
|
||||
}
|
||||
],
|
||||
server: {
|
||||
port: 3000
|
||||
}
|
||||
})`;
|
||||
writeFileSync(join(testDir, 'vite.config.js'), viteConfigWithPlugin);
|
||||
|
||||
// 执行注入(应该检测到已存在)
|
||||
const result = smartInject({
|
||||
remote: 'http://localhost:9000/dev-monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
|
||||
test('应该处理没有 plugins 数组的情况', () => {
|
||||
// 创建没有 plugins 的配置
|
||||
const simpleConfig = `export default {
|
||||
server: {
|
||||
port: 3000
|
||||
}
|
||||
}`;
|
||||
writeFileSync(join(testDir, 'vite.config.js'), simpleConfig);
|
||||
|
||||
const result = smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
|
||||
test('应该处理 TypeScript 配置文件', () => {
|
||||
const tsConfig = `import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()]
|
||||
})`;
|
||||
writeFileSync(join(testDir, 'vite.config.ts'), tsConfig);
|
||||
|
||||
const result = smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Next.js App Router 注入', () => {
|
||||
test('应该成功注入到 app/layout.tsx', () => {
|
||||
// 创建 Next.js App Router 结构
|
||||
mkdirSync(join(testDir, 'app'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}');
|
||||
|
||||
const layoutContent = `import type { Metadata } from 'next'
|
||||
import { Inter } from 'next/font/google'
|
||||
import './globals.css'
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Next.js App',
|
||||
description: 'Generated by create next app',
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}`;
|
||||
writeFileSync(join(testDir, 'app', 'layout.tsx'), layoutContent);
|
||||
|
||||
const result = smartInject({
|
||||
remote: 'http://localhost:9000/dev-monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
|
||||
test('应该处理 app/layout.js', () => {
|
||||
mkdirSync(join(testDir, 'app'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}');
|
||||
|
||||
const jsLayout = `import './globals.css'
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}`;
|
||||
writeFileSync(join(testDir, 'app', 'layout.js'), jsLayout);
|
||||
|
||||
const result = smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Next.js Pages Router 注入', () => {
|
||||
test('应该成功注入到 pages/_document.tsx', () => {
|
||||
mkdirSync(join(testDir, 'pages'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}');
|
||||
|
||||
const documentContent = `import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}`;
|
||||
writeFileSync(join(testDir, 'pages', '_document.tsx'), documentContent);
|
||||
|
||||
const result = smartInject({
|
||||
remote: 'http://localhost:9000/dev-monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
|
||||
test('应该处理 pages/_document.js', () => {
|
||||
mkdirSync(join(testDir, 'pages'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}');
|
||||
|
||||
const jsDocument = `const { Html, Head, Main, NextScript } = require('next/document')
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<title>My App</title>
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}`;
|
||||
writeFileSync(join(testDir, 'pages', '_document.js'), jsDocument);
|
||||
|
||||
const result = smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('混合模式处理', () => {
|
||||
test('应该优先注入到 app/layout', () => {
|
||||
// 创建混合模式结构
|
||||
mkdirSync(join(testDir, 'app'), { recursive: true });
|
||||
mkdirSync(join(testDir, 'pages'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}');
|
||||
|
||||
writeFileSync(join(testDir, 'app', 'layout.tsx'), 'export default function Layout() { return <div>App Layout</div>; }');
|
||||
writeFileSync(join(testDir, 'pages', '_document.tsx'), 'export default function Document() { return <div>Document</div>; }');
|
||||
|
||||
const result = smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('错误处理', () => {
|
||||
test('应该处理不支持的框架类型', () => {
|
||||
writeFileSync(join(testDir, 'index.html'), '<html></html>');
|
||||
|
||||
try {
|
||||
smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: false
|
||||
}, testDir);
|
||||
assert.fail('应该抛出错误');
|
||||
} catch (error) {
|
||||
assert.match(error.message, /不支持的项目类型/);
|
||||
}
|
||||
});
|
||||
|
||||
test('应该处理配置文件不存在的情况', () => {
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {}');
|
||||
// 不创建 layout 文件
|
||||
|
||||
try {
|
||||
smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: false
|
||||
}, testDir);
|
||||
assert.fail('应该抛出错误');
|
||||
} catch (error) {
|
||||
assert.match(error.message, /未找到/);
|
||||
}
|
||||
});
|
||||
|
||||
test('应该处理无效的配置文件', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'invalid javascript content');
|
||||
|
||||
try {
|
||||
smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: false
|
||||
}, testDir);
|
||||
assert.fail('应该抛出错误');
|
||||
} catch (error) {
|
||||
assert.ok(error.message.length > 0); // 应该有某种错误信息
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('实际文件修改测试', () => {
|
||||
test('应该实际修改 Vite 配置文件', () => {
|
||||
const originalConfig = `import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
port: 3000
|
||||
}
|
||||
})`;
|
||||
|
||||
writeFileSync(join(testDir, 'vite.config.js'), originalConfig);
|
||||
|
||||
// 执行实际注入
|
||||
const result = smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: false,
|
||||
verbose: false
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
|
||||
// 验证文件被修改
|
||||
const modifiedContent = readFileSync(join(testDir, 'vite.config.js'), 'utf8');
|
||||
assert.match(modifiedContent, /dev-inject-plugin/);
|
||||
assert.match(modifiedContent, /scripts\/monitor\.js/);
|
||||
|
||||
// 验证原始内容保留
|
||||
assert.match(modifiedContent, /defineConfig/);
|
||||
assert.match(modifiedContent, /react\(\)/);
|
||||
});
|
||||
|
||||
test('应该能够移除注入的内容', () => {
|
||||
// 先注入
|
||||
smartInject({
|
||||
remote: '/scripts/monitor.js',
|
||||
dryRun: false
|
||||
}, testDir);
|
||||
|
||||
// 然后移除
|
||||
const result = removeInjection({
|
||||
dryRun: false,
|
||||
verbose: false
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
|
||||
// 验证插件被移除
|
||||
const cleanedContent = readFileSync(join(testDir, 'vite.config.js'), 'utf8');
|
||||
assert(!cleanedContent.includes('dev-inject-plugin'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('不同脚本类型', () => {
|
||||
test('应该处理 HTTP URL', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'export default { plugins: [] }');
|
||||
|
||||
const result = smartInject({
|
||||
remote: 'https://cdn.example.com/monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
|
||||
test('应该处理本地路径', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'export default { plugins: [] }');
|
||||
|
||||
const result = smartInject({
|
||||
remote: '/assets/dev-monitor.js',
|
||||
dryRun: true
|
||||
}, testDir);
|
||||
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user