/** * 稿件审查API测试脚本 * 测试5个API端点的功能 */ import axios from 'axios'; import FormData from 'form-data'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const API_BASE_URL = 'http://localhost:3001/api/v1'; const TEST_FILE_PATH = path.join(__dirname, '../docs/稿约规范性评估标准.txt'); // 使用现有文本文件作为测试 // 颜色输出 const colors = { reset: '\x1b[0m', green: '\x1b[32m', red: '\x1b[31m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m', }; function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } function separator() { console.log('\n' + '='.repeat(80) + '\n'); } // 延迟函数 function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // ==================== 测试函数 ==================== /** * 测试1: 上传稿件 */ async function testUploadManuscript() { log('📤 测试1: 上传稿件 (POST /review/upload)', 'cyan'); try { // 检查测试文件是否存在 if (!fs.existsSync(TEST_FILE_PATH)) { log(`❌ 测试文件不存在: ${TEST_FILE_PATH}`, 'red'); log('💡 提示:请准备一个Word文档(.doc或.docx)作为测试文件', 'yellow'); return null; } const formData = new FormData(); formData.append('file', fs.createReadStream(TEST_FILE_PATH)); formData.append('modelType', 'deepseek-v3'); log(`📄 测试文件: ${path.basename(TEST_FILE_PATH)}`, 'blue'); log(`🤖 使用模型: deepseek-v3`, 'blue'); const response = await axios.post( `${API_BASE_URL}/review/upload`, formData, { headers: formData.getHeaders(), timeout: 30000, } ); if (response.data.success) { log('✅ 上传成功!', 'green'); console.log('返回数据:', JSON.stringify(response.data, null, 2)); return response.data.data.taskId; } else { log('❌ 上传失败', 'red'); console.log('错误信息:', response.data.message); return null; } } catch (error) { log('❌ 请求失败', 'red'); if (error.response) { console.log('状态码:', error.response.status); console.log('错误信息:', error.response.data); } else { console.log('错误:', error.message); } return null; } } /** * 测试2: 查询任务状态 */ async function testGetTaskStatus(taskId) { log('🔍 测试2: 查询任务状态 (GET /review/tasks/:taskId)', 'cyan'); try { log(`📋 任务ID: ${taskId}`, 'blue'); const response = await axios.get(`${API_BASE_URL}/review/tasks/${taskId}`, { timeout: 10000, }); if (response.data.success) { log('✅ 查询成功!', 'green'); console.log('任务状态:', JSON.stringify(response.data.data, null, 2)); return response.data.data; } else { log('❌ 查询失败', 'red'); console.log('错误信息:', response.data.message); return null; } } catch (error) { log('❌ 请求失败', 'red'); if (error.response) { console.log('状态码:', error.response.status); console.log('错误信息:', error.response.data); } else { console.log('错误:', error.message); } return null; } } /** * 测试3: 轮询任务直到完成 */ async function pollTaskUntilComplete(taskId, maxAttempts = 60) { log('⏳ 测试3: 轮询任务状态直到完成', 'cyan'); for (let i = 0; i < maxAttempts; i++) { const task = await testGetTaskStatus(taskId); if (!task) { log('❌ 查询任务失败,停止轮询', 'red'); return null; } log(`📊 当前状态: ${task.status}`, 'yellow'); if (task.status === 'completed') { log('✅ 任务已完成!', 'green'); return task; } if (task.status === 'failed') { log('❌ 任务失败', 'red'); console.log('错误信息:', task.errorMessage); return null; } log(`⏱️ 等待5秒后重试... (${i + 1}/${maxAttempts})`, 'blue'); await delay(5000); } log('⚠️ 超过最大等待时间,任务仍未完成', 'yellow'); return null; } /** * 测试4: 获取审查报告 */ async function testGetReport(taskId) { log('📊 测试4: 获取审查报告 (GET /review/tasks/:taskId/report)', 'cyan'); try { log(`📋 任务ID: ${taskId}`, 'blue'); const response = await axios.get(`${API_BASE_URL}/review/tasks/${taskId}/report`, { timeout: 10000, }); if (response.data.success) { log('✅ 获取报告成功!', 'green'); console.log('\n📄 完整报告:'); console.log(JSON.stringify(response.data.data, null, 2)); // 显示关键指标 const report = response.data.data; separator(); log('📈 评估结果摘要:', 'cyan'); log(`总分: ${report.overallScore?.toFixed(1) || 'N/A'}`, 'green'); log(`稿约规范性评分: ${report.editorialReview?.overall_score || 'N/A'}`, 'blue'); log(`方法学评分: ${report.methodologyReview?.overall_score || 'N/A'}`, 'blue'); log(`字数: ${report.wordCount || 'N/A'}`, 'blue'); log(`耗时: ${report.durationSeconds || 'N/A'}秒`, 'blue'); separator(); return response.data.data; } else { log('❌ 获取报告失败', 'red'); console.log('错误信息:', response.data.message); return null; } } catch (error) { log('❌ 请求失败', 'red'); if (error.response) { console.log('状态码:', error.response.status); console.log('错误信息:', error.response.data); } else { console.log('错误:', error.message); } return null; } } /** * 测试5: 获取任务列表 */ async function testGetTaskList() { log('📋 测试5: 获取任务列表 (GET /review/tasks)', 'cyan'); try { const response = await axios.get(`${API_BASE_URL}/review/tasks`, { params: { page: 1, limit: 10 }, timeout: 10000, }); if (response.data.success) { log('✅ 获取列表成功!', 'green'); console.log(`找到 ${response.data.data.length} 个任务`); console.log('任务列表:', JSON.stringify(response.data.data, null, 2)); console.log('分页信息:', JSON.stringify(response.data.pagination, null, 2)); return response.data.data; } else { log('❌ 获取列表失败', 'red'); console.log('错误信息:', response.data.message); return null; } } catch (error) { log('❌ 请求失败', 'red'); if (error.response) { console.log('状态码:', error.response.status); console.log('错误信息:', error.response.data); } else { console.log('错误:', error.message); } return null; } } /** * 测试6: 删除任务(可选) */ async function testDeleteTask(taskId) { log('🗑️ 测试6: 删除任务 (DELETE /review/tasks/:taskId)', 'cyan'); try { log(`📋 任务ID: ${taskId}`, 'blue'); const response = await axios.delete(`${API_BASE_URL}/review/tasks/${taskId}`, { timeout: 10000, }); if (response.data.success) { log('✅ 删除成功!', 'green'); console.log('返回数据:', JSON.stringify(response.data, null, 2)); return true; } else { log('❌ 删除失败', 'red'); console.log('错误信息:', response.data.message); return false; } } catch (error) { log('❌ 请求失败', 'red'); if (error.response) { console.log('状态码:', error.response.status); console.log('错误信息:', error.response.data); } else { console.log('错误:', error.message); } return false; } } // ==================== 主测试流程 ==================== async function runAllTests() { log('🚀 开始稿件审查API测试', 'green'); separator(); // 测试1: 上传稿件 const taskId = await testUploadManuscript(); if (!taskId) { log('❌ 上传失败,终止测试', 'red'); return; } separator(); // 等待2秒 await delay(2000); // 测试2: 查询任务状态 await testGetTaskStatus(taskId); separator(); // 测试3: 轮询直到完成 const completedTask = await pollTaskUntilComplete(taskId); if (!completedTask) { log('❌ 任务未能完成,跳过报告测试', 'red'); separator(); // 但仍然测试任务列表 await testGetTaskList(); separator(); return; } separator(); // 测试4: 获取报告 await testGetReport(taskId); separator(); // 测试5: 获取任务列表 await testGetTaskList(); separator(); // 测试6: 删除任务(可选,取消注释以启用) // log('⚠️ 是否删除测试任务?(取消注释testDeleteTask以启用)', 'yellow'); // await testDeleteTask(taskId); // separator(); log('✅ 所有测试完成!', 'green'); } // ==================== 健康检查 ==================== async function checkHealth() { log('🔍 检查后端服务健康状态...', 'cyan'); try { const response = await axios.get('http://localhost:3001/health', { timeout: 5000, }); log('✅ 后端服务正常', 'green'); console.log('健康状态:', response.data); return true; } catch (error) { log('❌ 后端服务不可用', 'red'); console.log('错误:', error.message); log('💡 请先启动后端服务: npm run dev 或 启动后端.bat', 'yellow'); return false; } } // ==================== 入口 ==================== async function main() { console.log('\n'); log('═══════════════════════════════════════════════════════════════════════════════', 'cyan'); log(' 稿件审查API自动化测试脚本 ', 'cyan'); log('═══════════════════════════════════════════════════════════════════════════════', 'cyan'); console.log('\n'); // 健康检查 const healthy = await checkHealth(); if (!healthy) { process.exit(1); } separator(); // 运行所有测试 await runAllTests(); console.log('\n'); log('═══════════════════════════════════════════════════════════════════════════════', 'cyan'); log(' 测试完成 ', 'cyan'); log('═══════════════════════════════════════════════════════════════════════════════', 'cyan'); console.log('\n'); } main().catch(error => { console.error('测试脚本执行失败:', error); process.exit(1); });