import { describe, expect, it, vi } from "vitest"; import { pollQuoteUntilDone } from "@/hooks/use-quote-polling"; import { POLL_INTERVAL_MS, POLL_TIMEOUT_MS, } from "@/lib/frontend/constants"; import type { QuoteDetail } from "@/lib/frontend/types"; function processingQuote(): QuoteDetail { return { quote_id: "QTE_test", request_id: "req-1", status: "processing", currency: "USD", }; } function doneQuote(): QuoteDetail { return { quote_id: "QTE_test", request_id: "req-1", status: "done", currency: "USD", is_realtime: true, quotes: [], }; } describe("pollQuoteUntilDone", () => { it("前 3 次网络失败第 4 次成功 → done", async () => { let calls = 0; const result = await pollQuoteUntilDone(async () => { calls += 1; if (calls < 4) { return { ok: false }; } return { ok: true, data: doneQuote() }; }); expect(result.type).toBe("done"); if (result.type === "done") { expect(result.quote.status).toBe("done"); } expect(calls).toBe(4); }); it("超过 POLL_TIMEOUT_MS 仍 processing → timeout", async () => { vi.useFakeTimers(); const promise = pollQuoteUntilDone(async () => ({ ok: true, data: processingQuote(), })); await vi.advanceTimersByTimeAsync( POLL_TIMEOUT_MS + POLL_INTERVAL_MS, ); const result = await promise; expect(result.type).toBe("timeout"); vi.useRealTimers(); }); it("failed 状态 → error 含可读文案", async () => { const result = await pollQuoteUntilDone(async () => ({ ok: true, data: { ...doneQuote(), status: "failed", error_code: "ADDRESS_SUGGESTION_NOT_FOUND", error_message: "未找到用户确认的 MotherShip 地址", }, })); expect(result.type).toBe("error"); if (result.type === "error") { expect(result.message).toBe("未找到用户确认的 MotherShip 地址"); } }); it("processing 超过 10s 后使用更短轮询间隔", async () => { vi.useFakeTimers(); let calls = 0; const intervals: number[] = []; let last = Date.now(); const promise = pollQuoteUntilDone(async () => { const now = Date.now(); if (calls > 0) { intervals.push(now - last); } last = now; calls += 1; if (calls < 7) { return { ok: true, data: processingQuote() }; } return { ok: true, data: doneQuote() }; }); for (let i = 0; i < 6; i += 1) { await vi.advanceTimersByTimeAsync(2_000); } await vi.advanceTimersByTimeAsync(800); const result = await promise; expect(result.type).toBe("done"); expect(intervals.some((gap) => gap <= 800)).toBe(true); vi.useRealTimers(); }); });