You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
2.7 KiB

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();
});
});