初始化
Some checks failed
CI/CD Pipeline / 测试 (18.x) (push) Has been cancelled
CI/CD Pipeline / 测试 (20.x) (push) Has been cancelled
CI/CD Pipeline / 安全检查 (push) Has been cancelled
CI/CD Pipeline / 部署 (push) Has been cancelled
CI/CD Pipeline / 通知 (push) Has been cancelled

This commit is contained in:
2025-11-03 19:47:36 +08:00
parent 7a04b85667
commit f25b0307db
454 changed files with 37064 additions and 4544 deletions

263
frontend/scripts/test.js Normal file
View File

@@ -0,0 +1,263 @@
#!/usr/bin/env node
const { spawn } = require('child_process')
const path = require('path')
const fs = require('fs')
// 颜色输出函数
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m'
}
function colorLog(color, message) {
console.log(`${colors[color]}${message}${colors.reset}`)
}
// 解析命令行参数
const args = process.argv.slice(2)
const options = {
unit: args.includes('--unit'),
e2e: args.includes('--e2e'),
coverage: args.includes('--coverage'),
watch: args.includes('--watch'),
verbose: args.includes('--verbose'),
component: args.includes('--component'),
api: args.includes('--api'),
store: args.includes('--store'),
ci: args.includes('--ci')
}
// 如果没有指定测试类型,默认运行所有测试
if (!options.unit && !options.e2e && !options.component && !options.api && !options.store) {
options.unit = true
options.e2e = true
}
// 构建测试命令
function buildTestCommand(type) {
let command = 'npx'
let args = []
if (type === 'unit') {
args.push('vitest', 'run')
if (options.coverage) {
args.push('--coverage')
}
if (options.watch) {
args = args.filter(arg => arg !== 'run')
args.push('--watch')
}
if (options.verbose) {
args.push('--verbose')
}
// 添加特定的测试文件模式
if (options.component) {
args.push('--dir', 'tests/unit/components')
} else if (options.api) {
args.push('--dir', 'tests/unit/services')
} else if (options.store) {
args.push('--dir', 'tests/unit/stores')
}
} else if (type === 'e2e') {
args.push('playwright', 'test')
if (options.ci) {
args.push('--reporter=line')
} else {
args.push('--reporter=list')
args.push('--reporter=html')
}
if (options.verbose) {
args.push('--verbose')
}
}
return { command, args }
}
// 运行测试命令
function runTestCommand(type) {
return new Promise((resolve, reject) => {
const { command, args } = buildTestCommand(type)
colorLog('cyan', `运行 ${type} 测试...`)
colorLog('blue', `${command} ${args.join(' ')}`)
const testProcess = spawn(command, args, {
stdio: 'inherit',
shell: true,
cwd: path.resolve(__dirname, '..')
})
testProcess.on('close', (code) => {
if (code === 0) {
colorLog('green', `${type} 测试通过!`)
resolve(code)
} else {
colorLog('red', `${type} 测试失败!`)
reject(new Error(`${type} 测试失败,退出码: ${code}`))
}
})
testProcess.on('error', (error) => {
colorLog('red', `运行 ${type} 测试时出错: ${error.message}`)
reject(error)
})
})
}
// 运行代码质量检查
function runCodeQualityChecks() {
return new Promise((resolve, reject) => {
colorLog('cyan', '运行代码质量检查...')
// 运行ESLint
const eslintProcess = spawn('npx', ['eslint', '--ext', '.js,.vue,.ts', 'src/', 'tests/'], {
stdio: 'inherit',
shell: true,
cwd: path.resolve(__dirname, '..')
})
eslintProcess.on('close', (code) => {
if (code === 0) {
colorLog('green', 'ESLint 检查通过!')
// 运行Prettier检查
const prettierProcess = spawn('npx', ['prettier', '--check', 'src/**/*.{js,vue,ts,css,scss,json,md}'], {
stdio: 'inherit',
shell: true,
cwd: path.resolve(__dirname, '..')
})
prettierProcess.on('close', (prettierCode) => {
if (prettierCode === 0) {
colorLog('green', 'Prettier 检查通过!')
resolve()
} else {
colorLog('red', 'Prettier 检查失败!')
reject(new Error(`Prettier 检查失败,退出码: ${prettierCode}`))
}
})
prettierProcess.on('error', (error) => {
colorLog('red', `运行 Prettier 检查时出错: ${error.message}`)
reject(error)
})
} else {
colorLog('red', 'ESLint 检查失败!')
reject(new Error(`ESLint 检查失败,退出码: ${code}`))
}
})
eslintProcess.on('error', (error) => {
colorLog('red', `运行 ESLint 检查时出错: ${error.message}`)
reject(error)
})
})
}
// 生成测试报告
function generateTestReports() {
return new Promise((resolve) => {
colorLog('cyan', '生成测试报告...')
// 确保报告目录存在
const reportsDir = path.resolve(__dirname, '../reports')
if (!fs.existsSync(reportsDir)) {
fs.mkdirSync(reportsDir, { recursive: true })
}
// 创建测试报告摘要
const summaryPath = path.join(reportsDir, 'test-summary.json')
const summary = {
timestamp: new Date().toISOString(),
tests: {
unit: options.unit,
e2e: options.e2e,
component: options.component,
api: options.api,
store: options.store
},
coverage: options.coverage,
watch: options.watch,
verbose: options.verbose
}
fs.writeFileSync(summaryPath, JSON.stringify(summary, null, 2))
colorLog('green', '测试报告已生成!')
resolve()
})
}
// 主函数
async function main() {
try {
colorLog('bright', '开始运行自动化测试和代码质量检查...')
// 运行代码质量检查
await runCodeQualityChecks()
// 运行单元测试
if (options.unit) {
await runTestCommand('unit')
}
// 运行E2E测试
if (options.e2e) {
await runTestCommand('e2e')
}
// 生成测试报告
await generateTestReports()
colorLog('bright', colorLog('green', '所有测试和代码质量检查通过!'))
process.exit(0)
} catch (error) {
colorLog('red', `测试或代码质量检查失败: ${error.message}`)
process.exit(1)
}
}
// 显示帮助信息
function showHelp() {
colorLog('bright', '自动化测试和代码质量检查工具')
console.log('')
console.log('用法: node scripts/test.js [选项]')
console.log('')
console.log('选项:')
console.log(' --unit 运行单元测试')
console.log(' --e2e 运行端到端测试')
console.log(' --component 运行组件测试')
console.log(' --api 运行API服务测试')
console.log(' --store 运行状态管理测试')
console.log(' --coverage 生成测试覆盖率报告')
console.log(' --watch 监视模式运行测试')
console.log(' --verbose 详细输出')
console.log(' --ci CI模式运行测试')
console.log('')
console.log('示例:')
console.log(' node scripts/test.js --unit --coverage')
console.log(' node scripts/test.js --e2e --verbose')
console.log(' node scripts/test.js --component --watch')
}
// 检查是否需要显示帮助信息
if (args.includes('--help') || args.includes('-h')) {
showHelp()
process.exit(0)
}
// 运行主函数
main()