|
|
import { Prisma } from "@prisma/client";
|
|
|
import type { QuoteRecord } from "@prisma/client";
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
import {
|
|
|
serializeQuoteDetail,
|
|
|
serializeQuoteSummary,
|
|
|
} from "@/modules/quote/quote-serializer";
|
|
|
|
|
|
const BASE_RECORD: QuoteRecord = {
|
|
|
id: BigInt(1),
|
|
|
quoteId: "QTE_20260616_0001",
|
|
|
requestId: "550e8400-e29b-41d4-a716-446655440000",
|
|
|
customerId: "CUST_001",
|
|
|
cargoHash: "abc123",
|
|
|
status: "done",
|
|
|
sourceType: "cache",
|
|
|
isRealtime: true,
|
|
|
confidenceScore: null,
|
|
|
currency: "USD",
|
|
|
pickupJson: {},
|
|
|
deliveryJson: {},
|
|
|
weightLb: new Prisma.Decimal(500),
|
|
|
dimLIn: new Prisma.Decimal(48),
|
|
|
dimWIn: new Prisma.Decimal(40),
|
|
|
dimHIn: new Prisma.Decimal(48),
|
|
|
palletCount: 2,
|
|
|
cargoType: "general_freight",
|
|
|
quotesJson: [{ service_level: "standard" }],
|
|
|
markupPercent: new Prisma.Decimal(0),
|
|
|
validUntil: new Date(Date.now() + 60_000),
|
|
|
errorCode: null,
|
|
|
errorMessage: null,
|
|
|
ccCustomerId: null,
|
|
|
forecastId: null,
|
|
|
isDeleted: false,
|
|
|
createdAt: new Date(),
|
|
|
updatedAt: new Date(),
|
|
|
};
|
|
|
|
|
|
describe("serializeQuoteDetail", () => {
|
|
|
it("done + cache → confidence_score=0.95 + quotes", () => {
|
|
|
const result = serializeQuoteDetail(BASE_RECORD);
|
|
|
expect(result.status).toBe("done");
|
|
|
expect(result.confidence_score).toBe(0.95);
|
|
|
expect(result.source_type).toBe("cache");
|
|
|
expect(result.quotes).toHaveLength(1);
|
|
|
});
|
|
|
|
|
|
it("stale → confidence_score=0.70", () => {
|
|
|
const result = serializeQuoteDetail({
|
|
|
...BASE_RECORD,
|
|
|
sourceType: "stale",
|
|
|
isRealtime: false,
|
|
|
});
|
|
|
expect(result.confidence_score).toBe(0.7);
|
|
|
expect(result.is_realtime).toBe(false);
|
|
|
});
|
|
|
|
|
|
it("valid_until 过期 → status=expired,不含 quotes", () => {
|
|
|
const result = serializeQuoteDetail({
|
|
|
...BASE_RECORD,
|
|
|
validUntil: new Date(Date.now() - 1_000),
|
|
|
});
|
|
|
expect(result.status).toBe("expired");
|
|
|
expect(result.quotes).toBeUndefined();
|
|
|
});
|
|
|
|
|
|
it("processing → 仅基础字段", () => {
|
|
|
const result = serializeQuoteDetail({
|
|
|
...BASE_RECORD,
|
|
|
status: "processing",
|
|
|
quotesJson: null,
|
|
|
validUntil: null,
|
|
|
});
|
|
|
expect(result.status).toBe("processing");
|
|
|
expect(result.quotes).toBeUndefined();
|
|
|
});
|
|
|
|
|
|
it("failed → error_code + error_message", () => {
|
|
|
const result = serializeQuoteDetail({
|
|
|
...BASE_RECORD,
|
|
|
status: "failed",
|
|
|
errorCode: "QUOTE_TIMEOUT",
|
|
|
errorMessage: null,
|
|
|
});
|
|
|
expect(result.status).toBe("failed");
|
|
|
expect(result.error_code).toBe("QUOTE_TIMEOUT");
|
|
|
expect(result.error_message).toContain("420 秒");
|
|
|
});
|
|
|
|
|
|
it("failed → 优先返回库内 error_message", () => {
|
|
|
const result = serializeQuoteDetail({
|
|
|
...BASE_RECORD,
|
|
|
status: "failed",
|
|
|
errorCode: "QUOTE_UNAVAILABLE",
|
|
|
errorMessage: "MotherShip 页面加载失败",
|
|
|
});
|
|
|
expect(result.error_message).toBe("MotherShip 页面加载失败");
|
|
|
});
|
|
|
});
|
|
|
|
|
|
describe("serializeQuoteSummary", () => {
|
|
|
it("历史摘要含关键字段", () => {
|
|
|
const result = serializeQuoteSummary(BASE_RECORD);
|
|
|
expect(result.quote_id).toBe("QTE_20260616_0001");
|
|
|
expect(result.pallet_count).toBe(2);
|
|
|
expect(result.created_at).toBeTruthy();
|
|
|
});
|
|
|
});
|