import { describe, expect, it } from "vitest"; import { FLOCK_HOLD_DECISION_MS, FLOCK_HOLD_MSG, FLOCK_HOLD_TOTAL_MS, buildFlockQuoteHoldState, flockHoldSessionId, formatFlockHoldRemainingLabel, isFlockQuoteHoldExpired, shouldAutoDeclineFlockHold, toFlockQuoteHoldPublic, } from "@/lib/constants/flock-quote-hold"; describe("flock quote hold — 60s/5min", () => { it("构建 60s 决策窗 + 5min 总硬限", () => { const now = 1_700_000_000_000; const s = buildFlockQuoteHoldState({ quoteId: "q1", sessionId: flockHoldSessionId("q1"), customerId: "CUST_001", nowMs: now, }); expect(s.decision_deadline_ms).toBe(now + FLOCK_HOLD_DECISION_MS); expect(s.total_deadline_ms).toBe(now + FLOCK_HOLD_TOTAL_MS); expect(s.quote_session_id).toBe("flock_q1"); }); it("60s 边界:恰好到期应 auto-decline;filling 不因决策窗 decline", () => { const now = 1_000; const s = buildFlockQuoteHoldState({ quoteId: "q1", sessionId: "flock_q1", customerId: "CUST_001", nowMs: now, }); expect(shouldAutoDeclineFlockHold(s, now + FLOCK_HOLD_DECISION_MS - 1)).toBe( false, ); expect(shouldAutoDeclineFlockHold(s, now + FLOCK_HOLD_DECISION_MS)).toBe( true, ); expect( shouldAutoDeclineFlockHold( { ...s, status: "filling" }, now + FLOCK_HOLD_DECISION_MS + 10_000, ), ).toBe(false); }); it("5 分钟总硬限边界", () => { const now = 1_000; const s = buildFlockQuoteHoldState({ quoteId: "q1", sessionId: "flock_q1", customerId: "CUST_001", nowMs: now, }); expect(isFlockQuoteHoldExpired(s, now + FLOCK_HOLD_TOTAL_MS - 1)).toBe( false, ); expect(isFlockQuoteHoldExpired(s, now + FLOCK_HOLD_TOTAL_MS)).toBe(true); }); it("倒计时文案", () => { const now = 10_000; expect(formatFlockHoldRemainingLabel(now + 45_000, now)).toBe("45秒"); expect(formatFlockHoldRemainingLabel(now + 65_000, now)).toBe("1分05秒"); }); it("超时提示含保留首价语义", () => { expect(FLOCK_HOLD_MSG.decisionTimeout).toMatch(/初步报价|超时/); expect(FLOCK_HOLD_MSG.totalTimeoutApi).toMatch(/5 分钟/); }); it("public.available:awaiting 过决策窗 false;filling 仍 true 直至总硬限", () => { const now = 5_000; const s = buildFlockQuoteHoldState({ quoteId: "q1", sessionId: "flock_q1", customerId: "CUST_001", nowMs: now, }); expect(toFlockQuoteHoldPublic(s, now).available).toBe(true); expect( toFlockQuoteHoldPublic(s, now + FLOCK_HOLD_DECISION_MS).available, ).toBe(false); expect( toFlockQuoteHoldPublic( { ...s, status: "filling" }, now + FLOCK_HOLD_DECISION_MS + 1_000, ).available, ).toBe(true); expect( toFlockQuoteHoldPublic( { ...s, status: "filling" }, now + FLOCK_HOLD_TOTAL_MS, ).available, ).toBe(false); }); });