初始化
Some checks failed
Some checks failed
This commit is contained in:
443
frontend/scripts/quality-report.js
Normal file
443
frontend/scripts/quality-report.js
Normal file
@@ -0,0 +1,443 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { execSync } = require('child_process')
|
||||
|
||||
// 创建报告目录
|
||||
const reportDir = path.resolve(process.cwd(), 'quality-report')
|
||||
if (!fs.existsSync(reportDir)) {
|
||||
fs.mkdirSync(reportDir, { recursive: true })
|
||||
}
|
||||
|
||||
// 生成时间戳
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
||||
const reportFile = path.join(reportDir, `quality-report-${timestamp}.html`)
|
||||
|
||||
// 报告模板
|
||||
const reportTemplate = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>代码质量报告</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
color: #2c3e50;
|
||||
}
|
||||
.header {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.section {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.metric {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.metric-name {
|
||||
font-weight: 500;
|
||||
}
|
||||
.metric-value {
|
||||
font-weight: bold;
|
||||
}
|
||||
.success {
|
||||
color: #27ae60;
|
||||
}
|
||||
.warning {
|
||||
color: #f39c12;
|
||||
}
|
||||
.error {
|
||||
color: #e74c3c;
|
||||
}
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
.progress-success {
|
||||
background-color: #27ae60;
|
||||
}
|
||||
.progress-warning {
|
||||
background-color: #f39c12;
|
||||
}
|
||||
.progress-error {
|
||||
background-color: #e74c3c;
|
||||
}
|
||||
.code-block {
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
}
|
||||
.summary-card {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.summary-card h3 {
|
||||
margin-top: 0;
|
||||
color: #495057;
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eee;
|
||||
font-size: 14px;
|
||||
color: #6c757d;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>代码质量报告</h1>
|
||||
<p>生成时间: ${new Date().toLocaleString('zh-CN')}</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>概览</h2>
|
||||
<div class="summary">
|
||||
<div class="summary-card">
|
||||
<h3>测试覆盖率</h3>
|
||||
<div class="summary-value" id="test-coverage">-</div>
|
||||
<p>代码行覆盖率</p>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<h3>ESLint 问题</h3>
|
||||
<div class="summary-value" id="eslint-issues">-</div>
|
||||
<p>代码风格问题</p>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<h3>类型错误</h3>
|
||||
<div class="summary-value" id="type-errors">-</div>
|
||||
<p>TypeScript 类型错误</p>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<h3>安全漏洞</h3>
|
||||
<div class="summary-value" id="security-vulnerabilities">-</div>
|
||||
<p>npm audit 结果</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>测试覆盖率</h2>
|
||||
<div id="coverage-details"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>代码风格检查</h2>
|
||||
<div id="eslint-details"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>类型检查</h2>
|
||||
<div id="type-check-details"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>安全检查</h2>
|
||||
<div id="security-details"></div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>此报告由自动化代码质量检查工具生成</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
// 写入报告文件
|
||||
fs.writeFileSync(reportFile, reportTemplate)
|
||||
|
||||
console.log(`✅ 代码质量报告已生成: ${reportFile}`)
|
||||
|
||||
// 运行各种检查并更新报告
|
||||
async function generateQualityReport() {
|
||||
try {
|
||||
// 1. 运行测试覆盖率
|
||||
console.log('🔍 运行测试覆盖率...')
|
||||
try {
|
||||
execSync('npm run test:unit:coverage', { stdio: 'pipe' })
|
||||
const coverageSummary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'))
|
||||
updateTestCoverage(coverageSummary)
|
||||
} catch (error) {
|
||||
console.error('❌ 测试覆盖率检查失败:', error.message)
|
||||
updateTestCoverage(null, error.message)
|
||||
}
|
||||
|
||||
// 2. 运行 ESLint
|
||||
console.log('🔍 运行 ESLint...')
|
||||
try {
|
||||
const eslintOutput = execSync('npm run lint -- --format=json', { stdio: 'pipe' }).toString()
|
||||
const eslintResults = JSON.parse(eslintOutput)
|
||||
updateESLintResults(eslintResults)
|
||||
} catch (error) {
|
||||
console.error('❌ ESLint 检查失败:', error.message)
|
||||
updateESLintResults(null, error.message)
|
||||
}
|
||||
|
||||
// 3. 运行类型检查
|
||||
console.log('🔍 运行类型检查...')
|
||||
try {
|
||||
execSync('npm run type-check', { stdio: 'pipe' })
|
||||
updateTypeCheckResults(true)
|
||||
} catch (error) {
|
||||
console.error('❌ 类型检查失败:', error.message)
|
||||
updateTypeCheckResults(false, error.message)
|
||||
}
|
||||
|
||||
// 4. 运行安全审计
|
||||
console.log('🔍 运行安全审计...')
|
||||
try {
|
||||
const auditOutput = execSync('npm audit --json', { stdio: 'pipe' }).toString()
|
||||
const auditResults = JSON.parse(auditOutput)
|
||||
updateSecurityResults(auditResults)
|
||||
} catch (error) {
|
||||
console.error('❌ 安全审计失败:', error.message)
|
||||
updateSecurityResults(null, error.message)
|
||||
}
|
||||
|
||||
console.log('✅ 代码质量报告更新完成')
|
||||
} catch (error) {
|
||||
console.error('❌ 生成代码质量报告时出错:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新测试覆盖率信息
|
||||
function updateTestCoverage(coverageSummary, error) {
|
||||
let html = ''
|
||||
|
||||
if (error) {
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">状态</span>
|
||||
<span class="metric-value error">检查失败</span>
|
||||
</div>
|
||||
<div class="code-block">${error}</div>
|
||||
`
|
||||
} else {
|
||||
const { lines, functions, branches, statements } = coverageSummary.total
|
||||
const linesPercent = parseFloat(lines.pct)
|
||||
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">行覆盖率</span>
|
||||
<span class="metric-value ${linesPercent >= 80 ? 'success' : linesPercent >= 60 ? 'warning' : 'error'}">${lines.pct}%</span>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill ${linesPercent >= 80 ? 'progress-success' : linesPercent >= 60 ? 'progress-warning' : 'progress-error'}" style="width: ${lines.pct}%"></div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">函数覆盖率</span>
|
||||
<span class="metric-value">${functions.pct}%</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">分支覆盖率</span>
|
||||
<span class="metric-value">${branches.pct}%</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">语句覆盖率</span>
|
||||
<span class="metric-value">${statements.pct}%</span>
|
||||
</div>
|
||||
`
|
||||
|
||||
// 更新概览
|
||||
updateOverview('test-coverage', lines.pct + '%', linesPercent >= 80 ? 'success' : linesPercent >= 60 ? 'warning' : 'error')
|
||||
}
|
||||
|
||||
updateReportSection('coverage-details', html)
|
||||
}
|
||||
|
||||
// 更新 ESLint 结果
|
||||
function updateESLintResults(eslintResults, error) {
|
||||
let html = ''
|
||||
|
||||
if (error) {
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">状态</span>
|
||||
<span class="metric-value error">检查失败</span>
|
||||
</div>
|
||||
<div class="code-block">${error}</div>
|
||||
`
|
||||
} else {
|
||||
let totalErrors = 0
|
||||
let totalWarnings = 0
|
||||
|
||||
eslintResults.forEach(file => {
|
||||
totalErrors += file.errorCount
|
||||
totalWarnings += file.warningCount
|
||||
})
|
||||
|
||||
const status = totalErrors === 0 && totalWarnings === 0 ? 'success' : totalErrors === 0 ? 'warning' : 'error'
|
||||
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">错误</span>
|
||||
<span class="metric-value ${totalErrors === 0 ? 'success' : 'error'}">${totalErrors}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">警告</span>
|
||||
<span class="metric-value ${totalWarnings === 0 ? 'success' : 'warning'}">${totalWarnings}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">状态</span>
|
||||
<span class="metric-value ${status}">${totalErrors === 0 && totalWarnings === 0 ? '通过' : totalErrors === 0 ? '警告' : '失败'}</span>
|
||||
</div>
|
||||
`
|
||||
|
||||
// 更新概览
|
||||
updateOverview('eslint-issues', totalErrors + totalWarnings, status)
|
||||
}
|
||||
|
||||
updateReportSection('eslint-details', html)
|
||||
}
|
||||
|
||||
// 更新类型检查结果
|
||||
function updateTypeCheckResults(success, error) {
|
||||
let html = ''
|
||||
|
||||
if (success) {
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">状态</span>
|
||||
<span class="metric-value success">通过</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">类型错误</span>
|
||||
<span class="metric-value success">0</span>
|
||||
</div>
|
||||
`
|
||||
|
||||
// 更新概览
|
||||
updateOverview('type-errors', '0', 'success')
|
||||
} else {
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">状态</span>
|
||||
<span class="metric-value error">失败</span>
|
||||
</div>
|
||||
<div class="code-block">${error}</div>
|
||||
`
|
||||
|
||||
// 更新概览
|
||||
updateOverview('type-errors', '>', 'error')
|
||||
}
|
||||
|
||||
updateReportSection('type-check-details', html)
|
||||
}
|
||||
|
||||
// 更新安全检查结果
|
||||
function updateSecurityResults(auditResults, error) {
|
||||
let html = ''
|
||||
|
||||
if (error) {
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">状态</span>
|
||||
<span class="metric-value error">检查失败</span>
|
||||
</div>
|
||||
<div class="code-block">${error}</div>
|
||||
`
|
||||
|
||||
// 更新概览
|
||||
updateOverview('security-vulnerabilities', '?', 'error')
|
||||
} else {
|
||||
const { vulnerabilities } = auditResults.metadata
|
||||
const { low, moderate, high, critical } = vulnerabilities
|
||||
|
||||
const totalVulns = low + moderate + high + critical
|
||||
const status = critical > 0 || high > 0 ? 'error' : moderate > 0 ? 'warning' : 'success'
|
||||
|
||||
html = `
|
||||
<div class="metric">
|
||||
<span class="metric-name">严重</span>
|
||||
<span class="metric-value ${critical === 0 ? 'success' : 'error'}">${critical}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">高危</span>
|
||||
<span class="metric-value ${high === 0 ? 'success' : 'error'}">${high}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">中危</span>
|
||||
<span class="metric-value ${moderate === 0 ? 'success' : 'warning'}">${moderate}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">低危</span>
|
||||
<span class="metric-value ${low === 0 ? 'success' : 'warning'}">${low}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-name">总计</span>
|
||||
<span class="metric-value ${status}">${totalVulns}</span>
|
||||
</div>
|
||||
`
|
||||
|
||||
// 更新概览
|
||||
updateOverview('security-vulnerabilities', totalVulns, status)
|
||||
}
|
||||
|
||||
updateReportSection('security-details', html)
|
||||
}
|
||||
|
||||
// 更新概览
|
||||
function updateOverview(id, value, status) {
|
||||
const elementId = id
|
||||
const className = status === 'success' ? 'success' : status === 'warning' ? 'warning' : 'error'
|
||||
|
||||
// 这里需要使用 DOM 操作,但在 Node.js 环境中无法直接操作 HTML
|
||||
// 实际实现中可以使用 cheerio 或其他 HTML 解析库
|
||||
console.log(`更新概览 ${id}: ${value} (${status})`)
|
||||
}
|
||||
|
||||
// 更新报告部分
|
||||
function updateReportSection(id, html) {
|
||||
// 这里需要使用 DOM 操作,但在 Node.js 环境中无法直接操作 HTML
|
||||
// 实际实现中可以使用 cheerio 或其他 HTML 解析库
|
||||
console.log(`更新报告部分 ${id}`)
|
||||
}
|
||||
|
||||
// 运行报告生成
|
||||
generateQualityReport()
|
||||
|
||||
module.exports = {
|
||||
generateQualityReport
|
||||
}
|
||||
263
frontend/scripts/test.js
Normal file
263
frontend/scripts/test.js
Normal 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()
|
||||
Reference in New Issue
Block a user