/** * Deep Research V2.0 — 冒烟测试(Smoke Test) * * 仅测试 API 接口连通性和基本参数校验, * 不调用 LLM / Unifuncs,无外部依赖,几秒完成。 * * 运行方式: * npx tsx src/modules/asl/__tests__/deep-research-v2-smoke.ts * * 前置条件: * - 后端服务运行在 localhost:3001 * - PostgreSQL 运行中 */ const BASE_URL = process.env.TEST_BASE_URL || 'http://localhost:3001'; const API_PREFIX = `${BASE_URL}/api/v1`; const TEST_PHONE = process.env.TEST_PHONE || '13800000001'; const TEST_PASSWORD = process.env.TEST_PASSWORD || '123456'; let authToken = ''; let passed = 0; let failed = 0; async function api(path: string, options: RequestInit = {}): Promise<{ status: number; data: any }> { const res = await fetch(`${API_PREFIX}${path}`, { ...options, headers: { 'Content-Type': 'application/json', ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}), ...(options.headers || {}), }, }); const contentType = res.headers.get('content-type') || ''; const data = contentType.includes('json') ? await res.json() : await res.text(); return { status: res.status, data }; } function check(ok: boolean, label: string) { if (ok) { console.log(` ✅ ${label}`); passed++; } else { console.log(` ❌ ${label}`); failed++; } } async function run() { console.log('🔥 Deep Research V2.0 冒烟测试\n'); // ─── 1. 登录 ─── console.log('[1] 登录'); try { const res = await api('/auth/login/password', { method: 'POST', body: JSON.stringify({ phone: TEST_PHONE, password: TEST_PASSWORD }), }); const ok = res.status === 200 && res.data.success; check(ok, `POST /auth/login/password → ${res.status}`); if (ok) { authToken = res.data.data.tokens?.accessToken || res.data.data.accessToken || res.data.data.token; } else { console.log(' ⚠️ 登录失败,后续需要认证的测试将跳过'); console.log(` 返回: ${JSON.stringify(res.data).slice(0, 200)}`); } } catch (e: any) { check(false, `连接后端失败: ${e.message}`); console.log('\n💡 请先启动后端: cd backend && npm run dev\n'); process.exit(1); } // ─── 2. GET /data-sources ─── console.log('\n[2] GET /asl/research/data-sources'); { const res = await api('/asl/research/data-sources'); check(res.status === 200, `HTTP ${res.status} === 200`); check(res.data.success === true, 'success=true'); check(Array.isArray(res.data.data) && res.data.data.length >= 3, `返回 ${res.data.data?.length} 个数据源`); const hasPubmed = res.data.data?.some((s: any) => s.id === 'pubmed'); check(hasPubmed, 'PubMed 存在于数据源列表'); const defaultChecked = res.data.data?.filter((s: any) => s.defaultChecked); check(defaultChecked?.length >= 1, `默认选中 ${defaultChecked?.length} 个`); } // ─── 3. POST /generate-requirement (参数校验) ─── console.log('\n[3] POST /asl/research/generate-requirement — 参数校验'); { const res = await api('/asl/research/generate-requirement', { method: 'POST', body: JSON.stringify({ originalQuery: '' }), }); check(res.status === 400, `空 query → HTTP ${res.status} === 400`); } { const res = await api('/asl/research/generate-requirement', { method: 'POST', body: JSON.stringify({}), }); check(res.status === 400, `缺少 query → HTTP ${res.status} === 400`); } // ─── 4. PUT /tasks/:taskId/execute (参数校验) ─── console.log('\n[4] PUT /asl/research/tasks/:taskId/execute — 参数校验'); { const res = await api('/asl/research/tasks/nonexistent-id/execute', { method: 'PUT', body: JSON.stringify({ confirmedRequirement: 'test' }), }); check(res.status === 404, `不存在的 taskId → HTTP ${res.status} === 404`); } { const res = await api('/asl/research/tasks/some-id/execute', { method: 'PUT', body: JSON.stringify({ confirmedRequirement: '' }), }); check(res.status === 400, `空 confirmedRequirement → HTTP ${res.status} === 400`); } // ─── 5. GET /tasks/:taskId (不存在) ─── console.log('\n[5] GET /asl/research/tasks/:taskId — 不存在'); { const res = await api('/asl/research/tasks/nonexistent-id'); check(res.status === 404, `不存在 → HTTP ${res.status} === 404`); } // ─── 6. GET /tasks/:taskId/export-word (不存在) ─── console.log('\n[6] GET /asl/research/tasks/:taskId/export-word — 不存在'); { const res = await api('/asl/research/tasks/nonexistent-id/export-word'); check(res.status === 500 || res.status === 404, `不存在 → HTTP ${res.status}`); } // ─── 7. 未认证访问 ─── console.log('\n[7] 未认证访问(无 Token)'); { const savedToken = authToken; authToken = ''; const res = await api('/asl/research/data-sources'); check(res.status === 401, `无 Token → HTTP ${res.status} === 401`); authToken = savedToken; } // ─── 结果汇总 ─── console.log(`\n${'═'.repeat(50)}`); console.log(` 🏁 冒烟测试完成: ${passed} 通过, ${failed} 失败 (共 ${passed + failed})`); console.log(`${'═'.repeat(50)}\n`); if (failed > 0) { process.exit(1); } } run();