mirror of
https://gitee.com/mirrors/AllinSSL.git
synced 2026-03-12 09:40:10 +08:00
【调整】申请证书配置CA选项增加liteSSL证书
This commit is contained in:
@@ -1,314 +0,0 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { createCompressTask, compressHelpers, batchCompress } from '../src/modules/compress.js';
|
||||
import { CompressConfig } from '../src/types.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { rimraf } from 'rimraf';
|
||||
import { createReadStream } from 'fs';
|
||||
import { createGunzip } from 'zlib';
|
||||
import { extract } from 'tar-fs';
|
||||
|
||||
describe('compress module', () => {
|
||||
const testDir = './test-temp/compress';
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
beforeEach(async () => {
|
||||
await fs.promises.mkdir(srcDir, { recursive: true });
|
||||
await fs.promises.mkdir(destDir, { recursive: true });
|
||||
|
||||
// 创建测试文件
|
||||
await fs.promises.writeFile(path.join(srcDir, 'file1.txt'), 'This is test file 1');
|
||||
await fs.promises.writeFile(path.join(srcDir, 'file2.txt'), 'This is test file 2');
|
||||
|
||||
// 创建子目录和文件
|
||||
const subDir = path.join(srcDir, 'subdir');
|
||||
await fs.promises.mkdir(subDir, { recursive: true });
|
||||
await fs.promises.writeFile(path.join(subDir, 'file3.txt'), 'This is test file 3 in subdirectory');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rimraf(testDir);
|
||||
});
|
||||
|
||||
describe('createCompressTask', () => {
|
||||
it('should create ZIP archive', async () => {
|
||||
const config: CompressConfig = {
|
||||
src: path.join(srcDir, '**/*'),
|
||||
filename: 'test.zip',
|
||||
dest: destDir,
|
||||
type: 'zip'
|
||||
};
|
||||
|
||||
const task = createCompressTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const zipPath = path.join(destDir, 'test.zip');
|
||||
expect(fs.existsSync(zipPath)).toBe(true);
|
||||
|
||||
const stats = await fs.promises.stat(zipPath);
|
||||
expect(stats.size).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should create TAR archive', async () => {
|
||||
const config: CompressConfig = {
|
||||
src: path.join(srcDir, '**/*'),
|
||||
filename: 'test.tar',
|
||||
dest: destDir,
|
||||
type: 'tar'
|
||||
};
|
||||
|
||||
const task = createCompressTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const tarPath = path.join(destDir, 'test.tar');
|
||||
expect(fs.existsSync(tarPath)).toBe(true);
|
||||
|
||||
const stats = await fs.promises.stat(tarPath);
|
||||
expect(stats.size).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should create GZIP archive', async () => {
|
||||
const config: CompressConfig = {
|
||||
src: path.join(srcDir, '**/*'),
|
||||
filename: 'test.tar.gz',
|
||||
dest: destDir,
|
||||
type: 'gzip'
|
||||
};
|
||||
|
||||
const task = createCompressTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const gzipPath = path.join(destDir, 'test.tar.gz');
|
||||
expect(fs.existsSync(gzipPath)).toBe(true);
|
||||
|
||||
const stats = await fs.promises.stat(gzipPath);
|
||||
expect(stats.size).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should handle different compression levels', async () => {
|
||||
const configs: CompressConfig[] = [
|
||||
{
|
||||
src: path.join(srcDir, '**/*'),
|
||||
filename: 'fast.zip',
|
||||
dest: destDir,
|
||||
type: 'zip',
|
||||
level: 1
|
||||
},
|
||||
{
|
||||
src: path.join(srcDir, '**/*'),
|
||||
filename: 'best.zip',
|
||||
dest: destDir,
|
||||
type: 'zip',
|
||||
level: 9
|
||||
}
|
||||
];
|
||||
|
||||
for (const config of configs) {
|
||||
const task = createCompressTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const fastStats = await fs.promises.stat(path.join(destDir, 'fast.zip'));
|
||||
const bestStats = await fs.promises.stat(path.join(destDir, 'best.zip'));
|
||||
|
||||
expect(fastStats.size).toBeGreaterThan(0);
|
||||
expect(bestStats.size).toBeGreaterThan(0);
|
||||
// 通常最高压缩级别的文件应该更小,但对于小文件可能差异不大
|
||||
});
|
||||
});
|
||||
|
||||
describe('compressHelpers', () => {
|
||||
it('should create config correctly', () => {
|
||||
const config = compressHelpers.createConfig(
|
||||
'src/**/*',
|
||||
'test.zip',
|
||||
'dest',
|
||||
{ level: 8, type: 'zip' }
|
||||
);
|
||||
|
||||
expect(config.src).toBe('src/**/*');
|
||||
expect(config.filename).toBe('test.zip');
|
||||
expect(config.dest).toBe('dest');
|
||||
expect(config.level).toBe(8);
|
||||
expect(config.type).toBe('zip');
|
||||
});
|
||||
|
||||
it('should infer type from filename', () => {
|
||||
expect(compressHelpers.inferType('test.zip')).toBe('zip');
|
||||
expect(compressHelpers.inferType('test.tar')).toBe('tar');
|
||||
expect(compressHelpers.inferType('test.tar.gz')).toBe('gzip');
|
||||
expect(compressHelpers.inferType('test.tgz')).toBe('gzip');
|
||||
expect(compressHelpers.inferType('unknown.ext')).toBe('zip');
|
||||
});
|
||||
|
||||
it('should generate timestamped filename', () => {
|
||||
const filename = compressHelpers.timestampedFilename('backup');
|
||||
expect(filename).toMatch(/^backup-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.zip$/);
|
||||
|
||||
const customExt = compressHelpers.timestampedFilename('backup', 'tar.gz');
|
||||
expect(customExt).toMatch(/^backup-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.tar\.gz$/);
|
||||
});
|
||||
|
||||
it('should get compression levels', () => {
|
||||
expect(compressHelpers.getCompressionLevel('speed')).toBe(1);
|
||||
expect(compressHelpers.getCompressionLevel('size')).toBe(9);
|
||||
expect(compressHelpers.getCompressionLevel('balanced')).toBe(6);
|
||||
expect(compressHelpers.getCompressionLevel()).toBe(6); // default
|
||||
});
|
||||
|
||||
it('should validate config', () => {
|
||||
const validConfig: CompressConfig = {
|
||||
src: 'src/**/*',
|
||||
filename: 'test.zip',
|
||||
dest: 'dest'
|
||||
};
|
||||
expect(compressHelpers.validateConfig(validConfig)).toEqual([]);
|
||||
|
||||
const invalidConfig: CompressConfig = {
|
||||
src: '',
|
||||
filename: '',
|
||||
dest: '',
|
||||
level: 15
|
||||
};
|
||||
const errors = compressHelpers.validateConfig(invalidConfig);
|
||||
expect(errors).toContain('缺少源文件路径');
|
||||
expect(errors).toContain('缺少压缩包文件名');
|
||||
expect(errors).toContain('缺少输出目录');
|
||||
expect(errors).toContain('压缩级别必须在 0-9 之间');
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchCompress', () => {
|
||||
it('should handle multiple compress operations', async () => {
|
||||
const configs: CompressConfig[] = [
|
||||
{
|
||||
src: path.join(srcDir, '*.txt'),
|
||||
filename: 'texts.zip',
|
||||
dest: destDir
|
||||
},
|
||||
{
|
||||
src: path.join(srcDir, 'subdir/**/*'),
|
||||
filename: 'subdir.zip',
|
||||
dest: destDir
|
||||
}
|
||||
];
|
||||
|
||||
const results = await batchCompress(configs);
|
||||
|
||||
expect(results).toHaveLength(2);
|
||||
expect(results[0].success).toBe(true);
|
||||
expect(results[1].success).toBe(true);
|
||||
|
||||
expect(fs.existsSync(path.join(destDir, 'texts.zip'))).toBe(true);
|
||||
expect(fs.existsSync(path.join(destDir, 'subdir.zip'))).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle errors gracefully', async () => {
|
||||
const configs: CompressConfig[] = [
|
||||
{
|
||||
src: 'non-existent/**/*',
|
||||
filename: 'test.zip',
|
||||
dest: '/invalid/path'
|
||||
}
|
||||
];
|
||||
|
||||
const results = await batchCompress(configs);
|
||||
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].error).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('real-world scenarios', () => {
|
||||
it('should compress build directory', async () => {
|
||||
// 模拟构建目录结构
|
||||
const buildDir = path.join(srcDir, 'build');
|
||||
await fs.promises.mkdir(path.join(buildDir, 'js'), { recursive: true });
|
||||
await fs.promises.mkdir(path.join(buildDir, 'css'), { recursive: true });
|
||||
await fs.promises.mkdir(path.join(buildDir, 'assets'), { recursive: true });
|
||||
|
||||
await fs.promises.writeFile(path.join(buildDir, 'index.html'), '<html>...</html>');
|
||||
await fs.promises.writeFile(path.join(buildDir, 'js', 'app.js'), 'console.log("app");');
|
||||
await fs.promises.writeFile(path.join(buildDir, 'css', 'style.css'), '.app {}');
|
||||
await fs.promises.writeFile(path.join(buildDir, 'assets', 'logo.png'), 'fake-png-data');
|
||||
|
||||
const config: CompressConfig = {
|
||||
src: path.join(buildDir, '**/*'),
|
||||
filename: compressHelpers.timestampedFilename('build'),
|
||||
dest: destDir,
|
||||
level: compressHelpers.getCompressionLevel('balanced')
|
||||
};
|
||||
|
||||
const task = createCompressTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const files = await fs.promises.readdir(destDir);
|
||||
const zipFile = files.find(f => f.startsWith('build-') && f.endsWith('.zip'));
|
||||
|
||||
expect(zipFile).toBeDefined();
|
||||
|
||||
if (zipFile) {
|
||||
const stats = await fs.promises.stat(path.join(destDir, zipFile));
|
||||
expect(stats.size).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('should create release package with version', async () => {
|
||||
const version = '1.2.3';
|
||||
const config: CompressConfig = {
|
||||
src: path.join(srcDir, '**/*'),
|
||||
filename: `release-v${version}.tar.gz`,
|
||||
dest: destDir,
|
||||
type: 'gzip',
|
||||
level: 9
|
||||
};
|
||||
|
||||
const task = createCompressTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const releasePath = path.join(destDir, `release-v${version}.tar.gz`);
|
||||
expect(fs.existsSync(releasePath)).toBe(true);
|
||||
|
||||
const stats = await fs.promises.stat(releasePath);
|
||||
expect(stats.size).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,386 +0,0 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { GulpBuildTools, createBuildTools, helpers, presets } from '../src/index.js';
|
||||
import { BuildToolsConfig } from '../src/types.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { rimraf } from 'rimraf';
|
||||
|
||||
describe('index module', () => {
|
||||
const testDir = './test-temp/index';
|
||||
let buildTools: GulpBuildTools;
|
||||
|
||||
beforeEach(async () => {
|
||||
await fs.promises.mkdir(testDir, { recursive: true });
|
||||
|
||||
buildTools = createBuildTools({
|
||||
cwd: testDir,
|
||||
verbose: false,
|
||||
tempDir: path.join(testDir, 'temp')
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rimraf(testDir);
|
||||
});
|
||||
|
||||
describe('GulpBuildTools class', () => {
|
||||
it('should create instance with default config', () => {
|
||||
const tools = new GulpBuildTools();
|
||||
expect(tools).toBeInstanceOf(GulpBuildTools);
|
||||
});
|
||||
|
||||
it('should create instance with custom config', () => {
|
||||
const config: BuildToolsConfig = {
|
||||
cwd: '/custom/path',
|
||||
verbose: true,
|
||||
tempDir: '/tmp'
|
||||
};
|
||||
|
||||
const tools = new GulpBuildTools(config);
|
||||
expect(tools).toBeInstanceOf(GulpBuildTools);
|
||||
});
|
||||
|
||||
it('should have all required methods', () => {
|
||||
expect(buildTools.renameFiles).toBeDefined();
|
||||
expect(buildTools.replaceContent).toBeDefined();
|
||||
expect(buildTools.uploadFiles).toBeDefined();
|
||||
expect(buildTools.compressFiles).toBeDefined();
|
||||
expect(buildTools.gitOperation).toBeDefined();
|
||||
expect(buildTools.sshExecution).toBeDefined();
|
||||
expect(buildTools.createBuildPipeline).toBeDefined();
|
||||
expect(buildTools.createParallelTasks).toBeDefined();
|
||||
expect(buildTools.createSeriesTasks).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createBuildTools function', () => {
|
||||
it('should create build tools instance', () => {
|
||||
const tools = createBuildTools();
|
||||
expect(tools).toBeInstanceOf(GulpBuildTools);
|
||||
});
|
||||
|
||||
it('should pass config to instance', () => {
|
||||
const config: BuildToolsConfig = {
|
||||
verbose: true,
|
||||
tempDir: './custom-temp'
|
||||
};
|
||||
|
||||
const tools = createBuildTools(config);
|
||||
expect(tools).toBeInstanceOf(GulpBuildTools);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createBuildPipeline', () => {
|
||||
it('should create empty pipeline', () => {
|
||||
const pipeline = buildTools.createBuildPipeline({});
|
||||
expect(pipeline).toBeDefined();
|
||||
expect(typeof pipeline).toBe('function');
|
||||
});
|
||||
|
||||
it('should create pipeline with single task', () => {
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
const pipeline = buildTools.createBuildPipeline({
|
||||
replace: [{
|
||||
src: path.join(srcDir, '**/*.js'),
|
||||
replacements: [
|
||||
{ search: 'test', replace: 'production' }
|
||||
],
|
||||
dest: destDir
|
||||
}]
|
||||
});
|
||||
|
||||
expect(pipeline).toBeDefined();
|
||||
expect(typeof pipeline).toBe('function');
|
||||
expect(pipeline.displayName).toBe('build-pipeline');
|
||||
});
|
||||
|
||||
it('should create pipeline with multiple task types', () => {
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
const pipeline = buildTools.createBuildPipeline({
|
||||
replace: [{
|
||||
src: path.join(srcDir, '**/*.js'),
|
||||
replacements: [{ search: 'dev', replace: 'prod' }],
|
||||
dest: destDir
|
||||
}],
|
||||
rename: [{
|
||||
src: path.join(destDir, '**/*.js'),
|
||||
rename: helpers.rename.addSuffix('.min'),
|
||||
dest: destDir
|
||||
}],
|
||||
compress: {
|
||||
src: path.join(destDir, '**/*'),
|
||||
filename: 'bundle.zip',
|
||||
dest: path.join(testDir, 'releases')
|
||||
}
|
||||
});
|
||||
|
||||
expect(pipeline).toBeDefined();
|
||||
expect(typeof pipeline).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createParallelTasks', () => {
|
||||
it('should create parallel tasks', () => {
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
const tasks = {
|
||||
'task1': buildTools.renameFiles({
|
||||
src: path.join(srcDir, '*.js'),
|
||||
rename: 'bundle1.js',
|
||||
dest: destDir
|
||||
}),
|
||||
'task2': buildTools.renameFiles({
|
||||
src: path.join(srcDir, '*.css'),
|
||||
rename: 'bundle2.css',
|
||||
dest: destDir
|
||||
})
|
||||
};
|
||||
|
||||
const parallelTask = buildTools.createParallelTasks(tasks);
|
||||
|
||||
expect(parallelTask).toBeDefined();
|
||||
expect(typeof parallelTask).toBe('function');
|
||||
expect(parallelTask.displayName).toBe('parallel-tasks');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createSeriesTasks', () => {
|
||||
it('should create series tasks', () => {
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
const tasks = {
|
||||
'step1': buildTools.replaceContent({
|
||||
src: path.join(srcDir, '**/*.js'),
|
||||
replacements: [{ search: 'old', replace: 'new' }],
|
||||
dest: destDir
|
||||
}),
|
||||
'step2': buildTools.compressFiles({
|
||||
src: path.join(destDir, '**/*'),
|
||||
filename: 'result.zip',
|
||||
dest: path.join(testDir, 'output')
|
||||
})
|
||||
};
|
||||
|
||||
const seriesTask = buildTools.createSeriesTasks(tasks);
|
||||
|
||||
expect(seriesTask).toBeDefined();
|
||||
expect(typeof seriesTask).toBe('function');
|
||||
expect(seriesTask.displayName).toBe('series-tasks');
|
||||
});
|
||||
});
|
||||
|
||||
describe('helpers export', () => {
|
||||
it('should export all helper modules', () => {
|
||||
expect(helpers).toBeDefined();
|
||||
expect(helpers.rename).toBeDefined();
|
||||
expect(helpers.replace).toBeDefined();
|
||||
expect(helpers.upload).toBeDefined();
|
||||
expect(helpers.compress).toBeDefined();
|
||||
expect(helpers.git).toBeDefined();
|
||||
expect(helpers.ssh).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have working rename helpers', () => {
|
||||
expect(helpers.rename.addPrefix).toBeDefined();
|
||||
expect(helpers.rename.addSuffix).toBeDefined();
|
||||
expect(helpers.rename.changeExtension).toBeDefined();
|
||||
expect(helpers.rename.addTimestamp).toBeDefined();
|
||||
expect(helpers.rename.toLowerCase).toBeDefined();
|
||||
expect(helpers.rename.toUpperCase).toBeDefined();
|
||||
expect(helpers.rename.replaceInName).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have working replace helpers', () => {
|
||||
expect(helpers.replace.version).toBeDefined();
|
||||
expect(helpers.replace.apiBaseUrl).toBeDefined();
|
||||
expect(helpers.replace.envVariable).toBeDefined();
|
||||
expect(helpers.replace.htmlTitle).toBeDefined();
|
||||
expect(helpers.replace.copyright).toBeDefined();
|
||||
expect(helpers.replace.timestamp).toBeDefined();
|
||||
expect(helpers.replace.buildNumber).toBeDefined();
|
||||
expect(helpers.replace.cssColor).toBeDefined();
|
||||
expect(helpers.replace.jsConfig).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have working compress helpers', () => {
|
||||
expect(helpers.compress.createConfig).toBeDefined();
|
||||
expect(helpers.compress.inferType).toBeDefined();
|
||||
expect(helpers.compress.timestampedFilename).toBeDefined();
|
||||
expect(helpers.compress.getCompressionLevel).toBeDefined();
|
||||
expect(helpers.compress.validateConfig).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('presets export', () => {
|
||||
it('should export all preset modules', () => {
|
||||
expect(presets).toBeDefined();
|
||||
expect(presets.frontend).toBeDefined();
|
||||
expect(presets.backend).toBeDefined();
|
||||
expect(presets.general).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have frontend presets', () => {
|
||||
expect(presets.frontend.vueDeploy).toBeDefined();
|
||||
expect(presets.frontend.optimize).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have backend presets', () => {
|
||||
expect(presets.backend.nodeDeploy).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have general presets', () => {
|
||||
expect(presets.general.backupAndDeploy).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create valid vue deploy config', () => {
|
||||
const config = presets.frontend.vueDeploy({
|
||||
buildDir: 'dist',
|
||||
serverConfig: {
|
||||
type: 'sftp',
|
||||
host: 'example.com',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
remotePath: '/var/www',
|
||||
src: 'dist/**/*'
|
||||
}
|
||||
});
|
||||
|
||||
expect(config).toBeDefined();
|
||||
expect(config.replace).toBeDefined();
|
||||
expect(config.compress).toBeDefined();
|
||||
expect(config.upload).toBeDefined();
|
||||
expect(Array.isArray(config.replace)).toBe(true);
|
||||
});
|
||||
|
||||
it('should create valid optimization config', () => {
|
||||
const config = presets.frontend.optimize('dist');
|
||||
|
||||
expect(config).toBeDefined();
|
||||
expect(config.replace).toBeDefined();
|
||||
expect(Array.isArray(config.replace)).toBe(true);
|
||||
expect(config.replace![0].src).toContain('dist');
|
||||
});
|
||||
|
||||
it('should create valid node deploy config', () => {
|
||||
const config = presets.backend.nodeDeploy({
|
||||
appPath: '/var/www/app',
|
||||
serverConfig: {
|
||||
type: 'sftp',
|
||||
host: 'server.com',
|
||||
username: 'deploy',
|
||||
password: 'pass',
|
||||
remotePath: '/var/www',
|
||||
src: 'dist/**/*'
|
||||
},
|
||||
sshConfig: {
|
||||
host: 'server.com',
|
||||
username: 'deploy',
|
||||
password: 'pass',
|
||||
commands: []
|
||||
}
|
||||
});
|
||||
|
||||
expect(config).toBeDefined();
|
||||
expect(config.git).toBeDefined();
|
||||
expect(config.upload).toBeDefined();
|
||||
expect(config.ssh).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('integration tests', () => {
|
||||
it('should work with real file operations', async () => {
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
await fs.promises.mkdir(srcDir, { recursive: true });
|
||||
await fs.promises.mkdir(destDir, { recursive: true });
|
||||
|
||||
// 创建测试文件
|
||||
await fs.promises.writeFile(
|
||||
path.join(srcDir, 'test.js'),
|
||||
'const version = "{{VERSION}}";'
|
||||
);
|
||||
|
||||
// 创建简单的替换任务
|
||||
const task = buildTools.replaceContent({
|
||||
src: path.join(srcDir, '*.js'),
|
||||
replacements: [
|
||||
{ search: '{{VERSION}}', replace: '1.0.0' }
|
||||
],
|
||||
dest: destDir
|
||||
});
|
||||
|
||||
// 执行任务
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// 验证结果
|
||||
const content = await fs.promises.readFile(path.join(destDir, 'test.js'), 'utf8');
|
||||
expect(content).toBe('const version = "1.0.0";');
|
||||
});
|
||||
|
||||
it('should work with build pipeline', async () => {
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const buildDir = path.join(testDir, 'build');
|
||||
const releaseDir = path.join(testDir, 'releases');
|
||||
|
||||
await fs.promises.mkdir(srcDir, { recursive: true });
|
||||
await fs.promises.mkdir(buildDir, { recursive: true });
|
||||
await fs.promises.mkdir(releaseDir, { recursive: true });
|
||||
|
||||
// 创建测试文件
|
||||
await fs.promises.writeFile(
|
||||
path.join(srcDir, 'app.js'),
|
||||
'const env = "development"; const version = "{{VERSION}}";'
|
||||
);
|
||||
|
||||
// 创建构建流水线
|
||||
const pipeline = buildTools.createBuildPipeline({
|
||||
replace: [{
|
||||
src: path.join(srcDir, '*.js'),
|
||||
replacements: [
|
||||
{ search: 'development', replace: 'production' },
|
||||
{ search: '{{VERSION}}', replace: '2.0.0' }
|
||||
],
|
||||
dest: buildDir
|
||||
}],
|
||||
rename: [{
|
||||
src: path.join(buildDir, '*.js'),
|
||||
rename: helpers.rename.addSuffix('.min'),
|
||||
dest: buildDir
|
||||
}],
|
||||
compress: {
|
||||
src: path.join(buildDir, '**/*'),
|
||||
filename: 'release.zip',
|
||||
dest: releaseDir
|
||||
}
|
||||
});
|
||||
|
||||
// 执行流水线
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
pipeline((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// 验证结果
|
||||
const buildContent = await fs.promises.readFile(path.join(buildDir, 'app.min.js'), 'utf8');
|
||||
expect(buildContent).toContain('production');
|
||||
expect(buildContent).toContain('2.0.0');
|
||||
|
||||
const releaseFiles = await fs.promises.readdir(releaseDir);
|
||||
expect(releaseFiles).toContain('release.zip');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,165 +0,0 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { createRenameTask, renameHelpers, batchRename } from '../src/modules/rename.js';
|
||||
import { RenameConfig } from '../src/types.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { rimraf } from 'rimraf';
|
||||
|
||||
describe('rename module', () => {
|
||||
const testDir = './test-temp/rename';
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
beforeEach(async () => {
|
||||
// 创建测试目录和文件
|
||||
await fs.promises.mkdir(srcDir, { recursive: true });
|
||||
await fs.promises.mkdir(destDir, { recursive: true });
|
||||
|
||||
// 创建测试文件
|
||||
await fs.promises.writeFile(path.join(srcDir, 'test1.js'), 'console.log("test1");');
|
||||
await fs.promises.writeFile(path.join(srcDir, 'test2.js'), 'console.log("test2");');
|
||||
await fs.promises.writeFile(path.join(srcDir, 'style.css'), '.test { color: red; }');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// 清理测试目录
|
||||
await rimraf(testDir);
|
||||
});
|
||||
|
||||
describe('createRenameTask', () => {
|
||||
it('should rename files with string', async () => {
|
||||
const config: RenameConfig = {
|
||||
src: path.join(srcDir, '*.js'),
|
||||
rename: 'bundle.js',
|
||||
dest: destDir
|
||||
};
|
||||
|
||||
const task = createRenameTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// 检查文件是否被重命名
|
||||
const files = await fs.promises.readdir(destDir);
|
||||
expect(files).toContain('bundle.js');
|
||||
});
|
||||
|
||||
it('should rename files with function', async () => {
|
||||
const config: RenameConfig = {
|
||||
src: path.join(srcDir, '*.js'),
|
||||
rename: (path) => {
|
||||
path.basename = path.basename + '.min';
|
||||
},
|
||||
dest: destDir
|
||||
};
|
||||
|
||||
const task = createRenameTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// 检查文件是否被重命名
|
||||
const files = await fs.promises.readdir(destDir);
|
||||
expect(files).toContain('test1.min.js');
|
||||
expect(files).toContain('test2.min.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('renameHelpers', () => {
|
||||
it('should add prefix correctly', () => {
|
||||
const mockPath = { basename: 'test', extname: '.js' };
|
||||
renameHelpers.addPrefix('prefix-')(mockPath);
|
||||
expect(mockPath.basename).toBe('prefix-test');
|
||||
});
|
||||
|
||||
it('should add suffix correctly', () => {
|
||||
const mockPath = { basename: 'test', extname: '.js' };
|
||||
renameHelpers.addSuffix('-suffix')(mockPath);
|
||||
expect(mockPath.basename).toBe('test-suffix');
|
||||
});
|
||||
|
||||
it('should change extension correctly', () => {
|
||||
const mockPath = { basename: 'test', extname: '.js' };
|
||||
renameHelpers.changeExtension('.min.js')(mockPath);
|
||||
expect(mockPath.extname).toBe('.min.js');
|
||||
});
|
||||
|
||||
it('should convert to lowercase', () => {
|
||||
const mockPath = { basename: 'TEST', extname: '.js' };
|
||||
renameHelpers.toLowerCase()(mockPath);
|
||||
expect(mockPath.basename).toBe('test');
|
||||
});
|
||||
|
||||
it('should convert to uppercase', () => {
|
||||
const mockPath = { basename: 'test', extname: '.js' };
|
||||
renameHelpers.toUpperCase()(mockPath);
|
||||
expect(mockPath.basename).toBe('TEST');
|
||||
});
|
||||
|
||||
it('should replace characters in name', () => {
|
||||
const mockPath = { basename: 'old-name', extname: '.js' };
|
||||
renameHelpers.replaceInName('old', 'new')(mockPath);
|
||||
expect(mockPath.basename).toBe('new-name');
|
||||
});
|
||||
|
||||
it('should add timestamp', () => {
|
||||
const mockPath = { basename: 'test', extname: '.js' };
|
||||
const originalBasename = mockPath.basename;
|
||||
renameHelpers.addTimestamp()(mockPath);
|
||||
|
||||
expect(mockPath.basename).toMatch(new RegExp(`^${originalBasename}-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}`));
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchRename', () => {
|
||||
it('should handle multiple rename operations', async () => {
|
||||
const configs: RenameConfig[] = [
|
||||
{
|
||||
src: path.join(srcDir, '*.js'),
|
||||
rename: renameHelpers.addPrefix('js-'),
|
||||
dest: destDir
|
||||
},
|
||||
{
|
||||
src: path.join(srcDir, '*.css'),
|
||||
rename: renameHelpers.addPrefix('css-'),
|
||||
dest: destDir
|
||||
}
|
||||
];
|
||||
|
||||
const results = await batchRename(configs);
|
||||
|
||||
expect(results).toHaveLength(2);
|
||||
expect(results[0].success).toBe(true);
|
||||
expect(results[1].success).toBe(true);
|
||||
|
||||
const files = await fs.promises.readdir(destDir);
|
||||
expect(files).toContain('js-test1.js');
|
||||
expect(files).toContain('js-test2.js');
|
||||
expect(files).toContain('css-style.css');
|
||||
});
|
||||
|
||||
it('should handle errors gracefully', async () => {
|
||||
const configs: RenameConfig[] = [
|
||||
{
|
||||
src: 'non-existent/**/*.js',
|
||||
rename: 'test.js',
|
||||
dest: '/invalid/path'
|
||||
}
|
||||
];
|
||||
|
||||
const results = await batchRename(configs);
|
||||
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].error).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,280 +0,0 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { createReplaceTask, replacePatterns, batchReplace } from '../src/modules/replace.js';
|
||||
import { ReplaceConfig } from '../src/types.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { rimraf } from 'rimraf';
|
||||
|
||||
describe('replace module', () => {
|
||||
const testDir = './test-temp/replace';
|
||||
const srcDir = path.join(testDir, 'src');
|
||||
const destDir = path.join(testDir, 'dest');
|
||||
|
||||
beforeEach(async () => {
|
||||
await fs.promises.mkdir(srcDir, { recursive: true });
|
||||
await fs.promises.mkdir(destDir, { recursive: true });
|
||||
|
||||
// 创建测试文件
|
||||
await fs.promises.writeFile(
|
||||
path.join(srcDir, 'config.js'),
|
||||
`const API_URL = "{{API_URL}}";
|
||||
const VERSION = "{{VERSION}}";
|
||||
const DEBUG = true;`
|
||||
);
|
||||
|
||||
await fs.promises.writeFile(
|
||||
path.join(srcDir, 'index.html'),
|
||||
`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{TITLE}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{TITLE}}</h1>
|
||||
<p>Version: {{VERSION}}</p>
|
||||
</body>
|
||||
</html>`
|
||||
);
|
||||
|
||||
await fs.promises.writeFile(
|
||||
path.join(srcDir, 'package.json'),
|
||||
`{
|
||||
"name": "test-app",
|
||||
"version": "1.0.0",
|
||||
"description": "Test application"
|
||||
}`
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rimraf(testDir);
|
||||
});
|
||||
|
||||
describe('createReplaceTask', () => {
|
||||
it('should replace content with string', async () => {
|
||||
const config: ReplaceConfig = {
|
||||
src: path.join(srcDir, 'config.js'),
|
||||
replacements: [
|
||||
{
|
||||
search: '{{API_URL}}',
|
||||
replace: 'https://api.example.com'
|
||||
},
|
||||
{
|
||||
search: '{{VERSION}}',
|
||||
replace: '2.0.0'
|
||||
}
|
||||
],
|
||||
dest: destDir
|
||||
};
|
||||
|
||||
const task = createReplaceTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const content = await fs.promises.readFile(path.join(destDir, 'config.js'), 'utf8');
|
||||
expect(content).toContain('https://api.example.com');
|
||||
expect(content).toContain('2.0.0');
|
||||
expect(content).not.toContain('{{API_URL}}');
|
||||
expect(content).not.toContain('{{VERSION}}');
|
||||
});
|
||||
|
||||
it('should replace content with regex', async () => {
|
||||
const config: ReplaceConfig = {
|
||||
src: path.join(srcDir, 'config.js'),
|
||||
replacements: [
|
||||
{
|
||||
search: /const\s+DEBUG\s*=\s*true/g,
|
||||
replace: 'const DEBUG = false'
|
||||
}
|
||||
],
|
||||
dest: destDir
|
||||
};
|
||||
|
||||
const task = createReplaceTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const content = await fs.promises.readFile(path.join(destDir, 'config.js'), 'utf8');
|
||||
expect(content).toContain('const DEBUG = false');
|
||||
expect(content).not.toContain('const DEBUG = true');
|
||||
});
|
||||
|
||||
it('should replace content with function', async () => {
|
||||
const config: ReplaceConfig = {
|
||||
src: path.join(srcDir, 'config.js'),
|
||||
replacements: [
|
||||
{
|
||||
search: /{{([A-Z_]+)}}/g,
|
||||
replace: (match, varName) => {
|
||||
const replacements: Record<string, string> = {
|
||||
'API_URL': 'https://api.production.com',
|
||||
'VERSION': '3.0.0'
|
||||
};
|
||||
return replacements[varName] || match;
|
||||
}
|
||||
}
|
||||
],
|
||||
dest: destDir
|
||||
};
|
||||
|
||||
const task = createReplaceTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const content = await fs.promises.readFile(path.join(destDir, 'config.js'), 'utf8');
|
||||
expect(content).toContain('https://api.production.com');
|
||||
expect(content).toContain('3.0.0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('replacePatterns', () => {
|
||||
it('should create version replacement pattern', () => {
|
||||
const pattern = replacePatterns.version('2.5.0');
|
||||
expect(pattern.search).toBeInstanceOf(RegExp);
|
||||
expect(pattern.replace).toBe('"version": "2.5.0"');
|
||||
});
|
||||
|
||||
it('should create API base URL replacement pattern', () => {
|
||||
const pattern = replacePatterns.apiBaseUrl('https://new-api.com');
|
||||
expect(pattern.search).toBeInstanceOf(RegExp);
|
||||
expect(pattern.replace).toBe("const API_BASE_URL = 'https://new-api.com'");
|
||||
});
|
||||
|
||||
it('should create environment variable replacement pattern', () => {
|
||||
const pattern = replacePatterns.envVariable('NODE_ENV', 'production');
|
||||
expect(pattern.search).toBeInstanceOf(RegExp);
|
||||
expect(pattern.replace).toBe('NODE_ENV=production');
|
||||
});
|
||||
|
||||
it('should create HTML title replacement pattern', () => {
|
||||
const pattern = replacePatterns.htmlTitle('My New App');
|
||||
expect(pattern.search).toBeInstanceOf(RegExp);
|
||||
expect(pattern.replace).toBe('<title>My New App</title>');
|
||||
});
|
||||
|
||||
it('should create timestamp replacement pattern', () => {
|
||||
const pattern = replacePatterns.timestamp();
|
||||
expect(pattern.search).toBeInstanceOf(RegExp);
|
||||
expect(pattern.replace).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchReplace', () => {
|
||||
it('should handle multiple replace operations', async () => {
|
||||
const configs: ReplaceConfig[] = [
|
||||
{
|
||||
src: path.join(srcDir, 'config.js'),
|
||||
replacements: [
|
||||
{ search: '{{API_URL}}', replace: 'https://api1.com' }
|
||||
],
|
||||
dest: destDir
|
||||
},
|
||||
{
|
||||
src: path.join(srcDir, 'index.html'),
|
||||
replacements: [
|
||||
{ search: '{{TITLE}}', replace: 'Test App' },
|
||||
{ search: '{{VERSION}}', replace: '1.5.0' }
|
||||
],
|
||||
dest: destDir
|
||||
}
|
||||
];
|
||||
|
||||
const results = await batchReplace(configs);
|
||||
|
||||
expect(results).toHaveLength(2);
|
||||
expect(results[0].success).toBe(true);
|
||||
expect(results[1].success).toBe(true);
|
||||
|
||||
const configContent = await fs.promises.readFile(path.join(destDir, 'config.js'), 'utf8');
|
||||
const htmlContent = await fs.promises.readFile(path.join(destDir, 'index.html'), 'utf8');
|
||||
|
||||
expect(configContent).toContain('https://api1.com');
|
||||
expect(htmlContent).toContain('Test App');
|
||||
expect(htmlContent).toContain('1.5.0');
|
||||
});
|
||||
|
||||
it('should handle errors gracefully', async () => {
|
||||
const configs: ReplaceConfig[] = [
|
||||
{
|
||||
src: 'non-existent.js',
|
||||
replacements: [
|
||||
{ search: 'test', replace: 'replacement' }
|
||||
],
|
||||
dest: '/invalid/path'
|
||||
}
|
||||
];
|
||||
|
||||
const results = await batchReplace(configs);
|
||||
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].error).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('real-world scenarios', () => {
|
||||
it('should handle package.json version update', async () => {
|
||||
const config: ReplaceConfig = {
|
||||
src: path.join(srcDir, 'package.json'),
|
||||
replacements: [
|
||||
replacePatterns.version('2.0.0')
|
||||
],
|
||||
dest: destDir
|
||||
};
|
||||
|
||||
const task = createReplaceTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const content = await fs.promises.readFile(path.join(destDir, 'package.json'), 'utf8');
|
||||
const packageJson = JSON.parse(content);
|
||||
expect(packageJson.version).toBe('2.0.0');
|
||||
});
|
||||
|
||||
it('should handle HTML template replacement', async () => {
|
||||
const config: ReplaceConfig = {
|
||||
src: path.join(srcDir, 'index.html'),
|
||||
replacements: [
|
||||
replacePatterns.htmlTitle('Production App'),
|
||||
{ search: /{{VERSION}}/g, replace: '2.1.0' },
|
||||
{ search: /<h1>{{TITLE}}<\/h1>/g, replace: '<h1>Production App</h1>' }
|
||||
],
|
||||
dest: destDir
|
||||
};
|
||||
|
||||
const task = createReplaceTask(config);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
task((error?: Error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const content = await fs.promises.readFile(path.join(destDir, 'index.html'), 'utf8');
|
||||
expect(content).toContain('<title>Production App</title>');
|
||||
expect(content).toContain('<h1>Production App</h1>');
|
||||
expect(content).toContain('Version: 2.1.0');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user