提交qiming-dev-inject
This commit is contained in:
160
qiming-dev-inject/test/unit/detectProjectType.test.js
Normal file
160
qiming-dev-inject/test/unit/detectProjectType.test.js
Normal file
@@ -0,0 +1,160 @@
|
||||
import { test, describe } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
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);
|
||||
|
||||
// 导入要测试的模块
|
||||
import { detectProjectType } 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',
|
||||
'pages/_document.tsx',
|
||||
'public/index.html',
|
||||
'index.html'
|
||||
];
|
||||
|
||||
filesToClean.forEach(file => {
|
||||
const filePath = join(testDir, file);
|
||||
if (existsSync(filePath)) {
|
||||
rmSync(filePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Vite 项目检测', () => {
|
||||
test('应该检测到 Vite 项目 (js)', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'module.exports = {};');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'vite');
|
||||
});
|
||||
|
||||
test('应该检测到 Vite 项目 (ts)', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.ts'), 'export default {};');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'vite');
|
||||
});
|
||||
|
||||
test('优先检测 Vite 而不是其他配置', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'module.exports = {};');
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {};');
|
||||
writeFileSync(join(testDir, 'public/index.html'), '<html></html>');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'vite');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Next.js App Router 检测', () => {
|
||||
test('应该检测到 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 type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'next-app');
|
||||
});
|
||||
|
||||
test('应该检测到 Next.js App Router (js)', () => {
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {};');
|
||||
mkdirSync(join(testDir, 'app'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'app', 'layout.js'), 'export default function Layout() {}');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'next-app');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Next.js Pages Router 检测', () => {
|
||||
test('应该检测到 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 type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'next-pages');
|
||||
});
|
||||
|
||||
test('应该检测到 Next.js Pages Router (js)', () => {
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {};');
|
||||
mkdirSync(join(testDir, 'pages'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'pages', '_document.js'), 'export default function Document() {}');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'next-pages');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Next.js 混合模式检测', () => {
|
||||
test('应该检测到 Next.js 混合模式', () => {
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {};');
|
||||
mkdirSync(join(testDir, 'app'), { recursive: true });
|
||||
mkdirSync(join(testDir, 'pages'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'app', 'layout.tsx'), 'export default function Layout() {}');
|
||||
writeFileSync(join(testDir, 'pages', '_document.tsx'), 'export default function Document() {}');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'next-hybrid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Create React App 检测', () => {
|
||||
test('应该检测到 Create React App', () => {
|
||||
mkdirSync(join(testDir, 'public'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'public', 'index.html'), '<html></html>');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'create-react-app');
|
||||
});
|
||||
});
|
||||
|
||||
describe('HTML 静态项目检测', () => {
|
||||
test('应该检测到 HTML 静态项目', () => {
|
||||
writeFileSync(join(testDir, 'index.html'), '<html></html>');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'html-static');
|
||||
});
|
||||
});
|
||||
|
||||
describe('未知项目检测', () => {
|
||||
test('应该返回 unknown 对于空目录', () => {
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'unknown');
|
||||
});
|
||||
|
||||
test('应该返回 unknown 对于不存在的目录', () => {
|
||||
const type = detectProjectType('/non-existent-directory');
|
||||
assert.strictEqual(type, 'unknown');
|
||||
});
|
||||
});
|
||||
|
||||
describe('优先级检测', () => {
|
||||
test('Next.js 优先于 HTML', () => {
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {};');
|
||||
writeFileSync(join(testDir, 'index.html'), '<html></html>');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'next-app'); // 默认是 app 模式
|
||||
});
|
||||
|
||||
test('Vite 优先于 Next.js', () => {
|
||||
writeFileSync(join(testDir, 'vite.config.js'), 'module.exports = {};');
|
||||
writeFileSync(join(testDir, 'next.config.js'), 'module.exports = {};');
|
||||
const type = detectProjectType(testDir);
|
||||
assert.strictEqual(type, 'vite');
|
||||
});
|
||||
});
|
||||
});
|
||||
1
qiming-dev-inject/test/unit/fixtures/app/layout.js
Normal file
1
qiming-dev-inject/test/unit/fixtures/app/layout.js
Normal file
@@ -0,0 +1 @@
|
||||
export default function Layout() {}
|
||||
1
qiming-dev-inject/test/unit/fixtures/index.html
Normal file
1
qiming-dev-inject/test/unit/fixtures/index.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
1
qiming-dev-inject/test/unit/fixtures/pages/_document.js
Normal file
1
qiming-dev-inject/test/unit/fixtures/pages/_document.js
Normal file
@@ -0,0 +1 @@
|
||||
export default function Document() {}
|
||||
1
qiming-dev-inject/test/unit/fixtures/test.html
Normal file
1
qiming-dev-inject/test/unit/fixtures/test.html
Normal file
@@ -0,0 +1 @@
|
||||
<html></html>
|
||||
161
qiming-dev-inject/test/unit/parseArgs.test.js
Normal file
161
qiming-dev-inject/test/unit/parseArgs.test.js
Normal file
@@ -0,0 +1,161 @@
|
||||
import { test, describe } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
|
||||
// 导入要测试的模块
|
||||
import { parseArgs } from '../../lib/args.js';
|
||||
|
||||
describe('CLI 参数解析', () => {
|
||||
describe('基本命令解析', () => {
|
||||
test('应该解析 install 命令', () => {
|
||||
const result = parseArgs(['install', '--remote', '/scripts/test.js']);
|
||||
assert.strictEqual(result.command, 'install');
|
||||
assert.strictEqual(result.options.remote, '/scripts/test.js');
|
||||
});
|
||||
|
||||
test('应该解析 uninstall 命令', () => {
|
||||
const result = parseArgs(['uninstall']);
|
||||
assert.strictEqual(result.command, 'uninstall');
|
||||
});
|
||||
|
||||
test('应该处理空参数', () => {
|
||||
const result = parseArgs([]);
|
||||
assert.strictEqual(result.command, null);
|
||||
assert.deepStrictEqual(result.options, {});
|
||||
});
|
||||
});
|
||||
|
||||
describe('--remote 参数解析', () => {
|
||||
test('应该解析 --remote=value 格式', () => {
|
||||
const result = parseArgs(['install', '--remote=http://localhost:9000/monitor.js']);
|
||||
assert.strictEqual(result.options.remote, 'http://localhost:9000/monitor.js');
|
||||
});
|
||||
|
||||
test('应该解析 --remote value 格式', () => {
|
||||
const result = parseArgs(['install', '--remote', '/scripts/dev-monitor.js']);
|
||||
assert.strictEqual(result.options.remote, '/scripts/dev-monitor.js');
|
||||
});
|
||||
|
||||
test('应该处理多个 --remote 参数(使用最后一个)', () => {
|
||||
const result = parseArgs(['install', '--remote', '/first.js', '--remote', '/second.js']);
|
||||
assert.strictEqual(result.options.remote, '/second.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('--file 参数解析', () => {
|
||||
test('应该解析 --file=value 格式', () => {
|
||||
const result = parseArgs(['install', '--remote=/test.js', '--file=public/index.html']);
|
||||
assert.strictEqual(result.options.file, 'public/index.html');
|
||||
});
|
||||
|
||||
test('应该解析 --file value 格式', () => {
|
||||
const result = parseArgs(['install', '--remote=/test.js', '--file', './public/index.html']);
|
||||
assert.strictEqual(result.options.file, './public/index.html');
|
||||
});
|
||||
});
|
||||
|
||||
describe('--framework 参数解析', () => {
|
||||
test('应该解析 --framework 选项', () => {
|
||||
const result = parseArgs(['install', '--remote=/test.js', '--framework']);
|
||||
assert.strictEqual(result.options.framework, true);
|
||||
});
|
||||
|
||||
test('应该解析 -f 简写选项', () => {
|
||||
const result = parseArgs(['install', '--remote=/test.js', '-f']);
|
||||
assert.strictEqual(result.options.framework, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('--dry-run 参数解析', () => {
|
||||
test('应该解析 --dry-run 选项', () => {
|
||||
const result = parseArgs(['install', '--remote=/test.js', '--dry-run']);
|
||||
assert.strictEqual(result.options.dryRun, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('--verbose 参数解析', () => {
|
||||
test('应该解析 --verbose 选项', () => {
|
||||
const result = parseArgs(['install', '--remote=/test.js', '--verbose']);
|
||||
assert.strictEqual(result.options.verbose, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('复合选项解析', () => {
|
||||
test('应该解析多个选项', () => {
|
||||
const result = parseArgs([
|
||||
'install',
|
||||
'--remote', 'http://localhost:9000/monitor.js',
|
||||
'--framework',
|
||||
'--dry-run',
|
||||
'--verbose',
|
||||
'--file', './test.html'
|
||||
]);
|
||||
|
||||
assert.strictEqual(result.command, 'install');
|
||||
assert.strictEqual(result.options.remote, 'http://localhost:9000/monitor.js');
|
||||
assert.strictEqual(result.options.framework, true);
|
||||
assert.strictEqual(result.options.dryRun, true);
|
||||
assert.strictEqual(result.options.verbose, true);
|
||||
assert.strictEqual(result.options.file, './test.html');
|
||||
});
|
||||
});
|
||||
|
||||
describe('错误处理', () => {
|
||||
test('install 命令缺少 --remote 参数应该抛出错误', () => {
|
||||
assert.throws(() => {
|
||||
parseArgs(['install']);
|
||||
}, /install 命令需要 --remote 参数/);
|
||||
});
|
||||
|
||||
test('uninstall 命令不需要 --remote 参数', () => {
|
||||
const result = parseArgs(['uninstall']);
|
||||
assert.strictEqual(result.command, 'uninstall');
|
||||
assert.deepStrictEqual(result.options, {});
|
||||
});
|
||||
});
|
||||
|
||||
describe('无效参数处理', () => {
|
||||
test('应该忽略未知参数', () => {
|
||||
// 使用 mock console.warn 来捕获警告
|
||||
const originalWarn = console.warn;
|
||||
let warnCalled = false;
|
||||
console.warn = () => { warnCalled = true; };
|
||||
|
||||
const result = parseArgs(['install', '--remote=/test.js', '--unknown-option']);
|
||||
|
||||
console.warn = originalWarn;
|
||||
|
||||
// 应该仍然正确解析已知参数
|
||||
assert.strictEqual(result.options.remote, '/test.js');
|
||||
// 应该标记未知参数被忽略(通过 console.warn)
|
||||
assert.ok(warnCalled); // 如果有警告输出则测试通过
|
||||
});
|
||||
});
|
||||
|
||||
describe('参数顺序无关性', () => {
|
||||
test('应该正确处理不同顺序的参数', () => {
|
||||
const result1 = parseArgs(['install', '--remote=/test.js', '--framework', '--dry-run']);
|
||||
const result2 = parseArgs(['install', '--dry-run', '--framework', '--remote=/test.js']);
|
||||
|
||||
assert.deepStrictEqual(result1.options, result2.options);
|
||||
});
|
||||
});
|
||||
|
||||
describe('边界情况', () => {
|
||||
test('应该处理空的 --remote 值', () => {
|
||||
const result = parseArgs(['install', '--remote', '']);
|
||||
assert.strictEqual(result.options.remote, '');
|
||||
});
|
||||
|
||||
test('应该处理包含特殊字符的路径', () => {
|
||||
const complexPath = '/path with spaces/file.js';
|
||||
const result = parseArgs(['install', '--remote', complexPath]);
|
||||
assert.strictEqual(result.options.remote, complexPath);
|
||||
});
|
||||
|
||||
test('应该处理长参数值', () => {
|
||||
const longValue = 'a'.repeat(1000);
|
||||
const result = parseArgs(['install', '--remote', longValue]);
|
||||
assert.strictEqual(result.options.remote, longValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
304
qiming-dev-inject/test/unit/utils.test.js
Normal file
304
qiming-dev-inject/test/unit/utils.test.js
Normal file
@@ -0,0 +1,304 @@
|
||||
import { test, describe } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
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);
|
||||
|
||||
// 导入要测试的模块
|
||||
import {
|
||||
parseRemoteType,
|
||||
generateScriptTag,
|
||||
lookupFiles,
|
||||
injectScriptToHtml,
|
||||
removeInjectedScripts
|
||||
} from '../../lib/utils.js';
|
||||
|
||||
describe('工具函数', () => {
|
||||
const testDir = join(__dirname, 'fixtures');
|
||||
|
||||
test.before(() => {
|
||||
if (!existsSync(testDir)) {
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
test.after(() => {
|
||||
const filesToClean = [
|
||||
'test1.html',
|
||||
'test2.html',
|
||||
'subdir/test3.html',
|
||||
'subdir/test4.html'
|
||||
];
|
||||
|
||||
filesToClean.forEach(file => {
|
||||
const filePath = join(testDir, file);
|
||||
if (existsSync(filePath)) {
|
||||
rmSync(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
const subDir = join(testDir, 'subdir');
|
||||
if (existsSync(subDir)) {
|
||||
rmSync(subDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe('parseRemoteType', () => {
|
||||
test('应该识别 HTTP URL', () => {
|
||||
assert.strictEqual(parseRemoteType('http://localhost:9000/monitor.js'), 'url');
|
||||
assert.strictEqual(parseRemoteType('http://example.com/script.js'), 'url');
|
||||
});
|
||||
|
||||
test('应该识别 HTTPS URL', () => {
|
||||
assert.strictEqual(parseRemoteType('https://cdn.example.com/monitor.js'), 'url');
|
||||
assert.strictEqual(parseRemoteType('https://localhost:3000/dev-monitor.js'), 'url');
|
||||
});
|
||||
|
||||
test('应该识别绝对路径', () => {
|
||||
assert.strictEqual(parseRemoteType('/scripts/monitor.js'), 'absolute-path');
|
||||
assert.strictEqual(parseRemoteType('/assets/dev-monitor.js'), 'absolute-path');
|
||||
assert.strictEqual(parseRemoteType('/path/to/script.js'), 'absolute-path');
|
||||
});
|
||||
|
||||
test('应该处理相对路径', () => {
|
||||
try {
|
||||
parseRemoteType('./script.js');
|
||||
assert.fail('应该抛出错误');
|
||||
} catch (error) {
|
||||
assert.match(error.message, /不支持的远程路径格式/);
|
||||
}
|
||||
});
|
||||
|
||||
test('应该处理空字符串', () => {
|
||||
try {
|
||||
parseRemoteType('');
|
||||
assert.fail('应该抛出错误');
|
||||
} catch (error) {
|
||||
assert.match(error.message, /不支持的远程路径格式/);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateScriptTag', () => {
|
||||
test('应该生成 URL 类型的脚本标签', () => {
|
||||
const tag = generateScriptTag('http://localhost:9000/monitor.js', 'url');
|
||||
assert.strictEqual(tag, '<script src="http://localhost:9000/monitor.js"></script>');
|
||||
});
|
||||
|
||||
test('应该生成绝对路径类型的脚本标签', () => {
|
||||
const tag = generateScriptTag('/scripts/monitor.js', 'absolute-path');
|
||||
assert.strictEqual(tag, '<script src="/scripts/monitor.js"></script>');
|
||||
});
|
||||
|
||||
test('应该处理不同的路径格式', () => {
|
||||
const testCases = [
|
||||
'https://cdn.example.com/monitor.js',
|
||||
'http://localhost:3000/dev-monitor.js',
|
||||
'/assets/scripts/dev-monitor.js',
|
||||
'/scripts/monitor.js'
|
||||
];
|
||||
|
||||
testCases.forEach(path => {
|
||||
const type = parseRemoteType(path);
|
||||
const tag = generateScriptTag(path, type);
|
||||
assert.match(tag, /^<script src="[^"]*"><\/script>$/);
|
||||
assert(tag.includes(path));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('lookupFiles', () => {
|
||||
test('应该查找指定目录中的 HTML 文件', () => {
|
||||
// 创建测试文件
|
||||
writeFileSync(join(testDir, 'test1.html'), '<html></html>');
|
||||
writeFileSync(join(testDir, 'test2.html'), '<html></html>');
|
||||
mkdirSync(join(testDir, 'subdir'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'subdir', 'test3.html'), '<html></html>');
|
||||
|
||||
const files = lookupFiles(testDir);
|
||||
|
||||
// 应该找到所有 HTML 文件
|
||||
assert(files.length >= 3);
|
||||
assert(files.some(f => f.includes('test1.html')));
|
||||
assert(files.some(f => f.includes('test2.html')));
|
||||
assert(files.some(f => f.includes('test3.html')));
|
||||
});
|
||||
|
||||
test('应该优先返回 index.html', () => {
|
||||
// 创建测试文件
|
||||
writeFileSync(join(testDir, 'test.html'), '<html></html>');
|
||||
writeFileSync(join(testDir, 'index.html'), '<html></html>');
|
||||
|
||||
const files = lookupFiles(testDir);
|
||||
|
||||
// 应该优先返回 index.html
|
||||
assert.strictEqual(files.length, 1);
|
||||
assert(files[0].includes('index.html'));
|
||||
});
|
||||
|
||||
test('应该处理空目录', () => {
|
||||
const files = lookupFiles(testDir);
|
||||
assert.deepStrictEqual(files, []);
|
||||
});
|
||||
|
||||
test('应该处理不存在的目录', () => {
|
||||
const files = lookupFiles('/non-existent-directory');
|
||||
assert.deepStrictEqual(files, []);
|
||||
});
|
||||
|
||||
test('应该跳过 node_modules 目录', () => {
|
||||
// 创建测试文件和 node_modules 目录
|
||||
writeFileSync(join(testDir, 'test.html'), '<html></html>');
|
||||
mkdirSync(join(testDir, 'node_modules'), { recursive: true });
|
||||
writeFileSync(join(testDir, 'node_modules', 'index.html'), '<html></html>');
|
||||
|
||||
const files = lookupFiles(testDir);
|
||||
|
||||
// 不应该包含 node_modules 中的文件
|
||||
assert(files.length === 1);
|
||||
assert(files[0].includes('test.html'));
|
||||
assert(!files.some(f => f.includes('node_modules')));
|
||||
});
|
||||
});
|
||||
|
||||
describe('injectScriptToHtml', () => {
|
||||
test('应该注入脚本到 HTML 的 </head> 标签之前', () => {
|
||||
const html = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const scriptTag = '<script src="/scripts/monitor.js"></script>';
|
||||
const result = injectScriptToHtml(html, scriptTag);
|
||||
|
||||
assert.match(result, /<script src="\/scripts\/monitor\.js"><\/script>\s*<\/head>/);
|
||||
assert.match(result, /dev-inject/);
|
||||
});
|
||||
|
||||
test('应该添加 dev-inject 标识注释', () => {
|
||||
const html = `<html><head></head><body></body></html>`;
|
||||
const scriptTag = '<script src="/test.js"></script>';
|
||||
const result = injectScriptToHtml(html, scriptTag);
|
||||
|
||||
assert.match(result, /<!-- injected by dev-inject -->/);
|
||||
});
|
||||
|
||||
test('应该处理没有 </head> 标签的情况', () => {
|
||||
const html = `<html><head><title>Test</title></head><body>content</body></html>`;
|
||||
const scriptTag = '<script src="/test.js"></script>';
|
||||
const result = injectScriptToHtml(html, scriptTag);
|
||||
|
||||
assert.match(result, /<script src="\/test\.js"><\/script>/);
|
||||
});
|
||||
|
||||
test('应该处理没有 <head> 标签的情况', () => {
|
||||
const html = `<html><body>content</body></html>`;
|
||||
const scriptTag = '<script src="/test.js"></script>';
|
||||
const result = injectScriptToHtml(html, scriptTag);
|
||||
|
||||
assert.match(result, /<script src="\/test\.js"><\/script>/);
|
||||
});
|
||||
|
||||
test('应该处理空 HTML', () => {
|
||||
const html = '';
|
||||
const scriptTag = '<script src="/test.js"></script>';
|
||||
const result = injectScriptToHtml(html, scriptTag);
|
||||
|
||||
assert.match(result, /<script src="\/test\.js"><\/script>/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeInjectedScripts', () => {
|
||||
test('应该移除注入的脚本和注释', () => {
|
||||
const htmlWithInjection = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test</title>
|
||||
<script src="/scripts/monitor.js"></script> <!-- injected by dev-inject -->
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const result = removeInjectedScripts(htmlWithInjection);
|
||||
|
||||
assert.match(result, /<head>\s*<meta charset="UTF-8">\s*<title>Test<\/title>\s*<\/head>/);
|
||||
assert(!result.includes('dev-monitor.js'));
|
||||
assert(!result.includes('injected by dev-inject'));
|
||||
});
|
||||
|
||||
test('应该处理多个注入的脚本', () => {
|
||||
const htmlWithMultiple = `<html><head>
|
||||
<script src="/script1.js"></script> <!-- injected by dev-inject -->
|
||||
<title>Test</title>
|
||||
<script src="/script2.js"></script> <!-- injected by dev-inject -->
|
||||
</head></html>`;
|
||||
|
||||
const result = removeInjectedScripts(htmlWithMultiple);
|
||||
|
||||
assert(!result.includes('script1.js'));
|
||||
assert(!result.includes('script2.js'));
|
||||
assert(!result.includes('injected by dev-inject'));
|
||||
});
|
||||
|
||||
test('应该保留非注入的脚本', () => {
|
||||
const htmlWithMixed = `<html><head>
|
||||
<script src="/normal-script.js"></script>
|
||||
<script src="/injected-script.js"></script> <!-- injected by dev-inject -->
|
||||
<title>Test</title>
|
||||
</head></html>`;
|
||||
|
||||
const result = removeInjectedScripts(htmlWithMixed);
|
||||
|
||||
assert(result.includes('normal-script.js'));
|
||||
assert(!result.includes('injected-script.js'));
|
||||
assert(!result.includes('injected by dev-inject'));
|
||||
});
|
||||
|
||||
test('应该处理没有注入脚本的 HTML', () => {
|
||||
const normalHtml = `<html><head><title>Test</title></head><body>content</body></html>`;
|
||||
const result = removeInjectedScripts(normalHtml);
|
||||
|
||||
assert.strictEqual(result, normalHtml);
|
||||
});
|
||||
});
|
||||
|
||||
describe('边界情况和错误处理', () => {
|
||||
test('应该处理特殊字符', () => {
|
||||
const html = '<html><head><title>Test & "Special" Characters</title></head></html>';
|
||||
const scriptTag = '<script src="/path/with spaces/script.js"></script>';
|
||||
const result = injectScriptToHtml(html, scriptTag);
|
||||
|
||||
assert(result.includes('script.js'));
|
||||
});
|
||||
|
||||
test('应该处理非常长的 HTML', () => {
|
||||
const longHtml = '<html><head>' + '<meta charset="UTF-8">'.repeat(1000) + '</head></html>';
|
||||
const scriptTag = '<script src="/test.js"></script>';
|
||||
const result = injectScriptToHtml(longHtml, scriptTag);
|
||||
|
||||
assert(result.length > longHtml.length);
|
||||
assert(result.includes('test.js'));
|
||||
});
|
||||
|
||||
test('应该处理格式不规范的 HTML', () => {
|
||||
const malformedHtml = '<html><HEAD><title>Test</Title></HEAD><BODY>content</BODY></HTML>';
|
||||
const scriptTag = '<script src="/test.js"></script>';
|
||||
const result = injectScriptToHtml(malformedHtml, scriptTag);
|
||||
|
||||
assert(result.includes('test.js'));
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user