/** * 真实 RPA 冒烟:POST /api/quotes → 轮询至 done/failed/超时 * 前置:RPA_MOCK_MODE=false,worker:rpa 已启动 */ import { randomUUID } from "node:crypto"; const BASE = process.env.SMOKE_BASE_URL ?? "http://localhost:3000"; const TOKEN = "demo-host-token"; const POLL_MS = 2_000; const TIMEOUT_MS = 90_000; const body = { request_id: randomUUID(), customer_id: "CUST_001", pickup_address: { street: "1234 Warehouse Blvd", city: "Los Angeles", state: "CA", zip: "90001", place_id: "place_la_90001", formatted_address: "1234 Warehouse Blvd, Los Angeles, CA 90001", selected_from_suggestions: true, }, delivery_address: { street: "5678 Distribution Dr", city: "Dallas", state: "TX", zip: "75201", place_id: "place_dallas_75201", formatted_address: "5678 Distribution Dr, Dallas, TX 75201", selected_from_suggestions: true, }, weight: { value: 500, unit: "lb" as const }, dimensions: { length: 48, width: 40, height: 48, unit: "in" as const }, pallet_count: 2, cargo_type: "general_freight", }; async function main(): Promise { if (process.env.RPA_MOCK_MODE === "true") { console.error("[FAIL] RPA_MOCK_MODE=true,请设为 false 后再跑真实冒烟"); process.exit(1); } const headers = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }; console.log("[1/3] POST /api/quotes ..."); const createRes = await fetch(`${BASE}/api/quotes`, { method: "POST", headers, body: JSON.stringify(body), }); const created = (await createRes.json()) as { code: number; message: string; data?: { quote_id: string; status: string; source_type?: string }; }; if (created.code !== 0 || !created.data?.quote_id) { console.error("[FAIL] 创建询价失败:", created); process.exit(1); } const { quote_id: quoteId, status: createStatus } = created.data; console.log(` quote_id=${quoteId} status=${createStatus}`); if (createStatus === "done") { console.log("[2/3] L2 缓存命中,跳过 RPA"); } else { console.log("[2/3] 轮询 RPA 结果(最长 90s)..."); } const started = Date.now(); let lastStatus = createStatus; while (Date.now() - started < TIMEOUT_MS) { const detailRes = await fetch( `${BASE}/api/quotes/${quoteId}?customer_id=CUST_001`, { headers: { Authorization: `Bearer ${TOKEN}` } }, ); const detail = (await detailRes.json()) as { code: number; data?: { status: string; source_type?: string; is_realtime?: boolean; quotes?: Array<{ service_level: string; rate_option: string; final_total: number }>; error_code?: string; }; }; if (detail.code !== 0 || !detail.data) { console.error("[FAIL] 查询失败:", detail); process.exit(1); } lastStatus = detail.data.status; if (lastStatus === "processing") { process.stdout.write("."); await sleep(POLL_MS); continue; } console.log(""); console.log("[3/3] 结果:"); console.log( JSON.stringify( { status: detail.data.status, source_type: detail.data.source_type, is_realtime: detail.data.is_realtime, error_code: detail.data.error_code, quotes: detail.data.quotes?.map((q) => ({ tier: `${q.service_level}/${q.rate_option}`, final_total: q.final_total, })), }, null, 2, ), ); if (lastStatus === "done") { const count = detail.data.quotes?.length ?? 0; if (count === 4) { console.log("[PASS] 真实 RPA 四档报价返回"); process.exit(0); } console.error(`[FAIL] 报价档位数=${count},期望 4`); process.exit(1); } console.error(`[FAIL] 询价终态=${lastStatus}`); process.exit(1); } console.error(`\n[FAIL] 轮询超时,最后状态=${lastStatus}`); process.exit(1); } function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } main().catch((err) => { console.error("[FAIL]", err); process.exit(1); });