import { describe, expect, it, vi, beforeEach } from "vitest"; const prismaMock = vi.hoisted(() => ({ quoteCacheMeta: { findUnique: vi.fn(), create: vi.fn(), update: vi.fn(), }, alertLog: { create: vi.fn(), }, })); vi.mock("@/lib/prisma", () => ({ prisma: prismaMock })); import { detectDeviation } from "@/modules/alert/deviation-detector"; import type { RawQuoteTier } from "@/modules/pricing/engine"; const fourTiers = (): RawQuoteTier[] => [ { service_level: "standard", rate_option: "lowest", carrier: "A", transit_days: "3", transit_description: "3d", raw_freight: 320, surcharges: 0, raw_total: 320, }, { service_level: "standard", rate_option: "fastest", carrier: "A", transit_days: "2", transit_description: "2d", raw_freight: 380, surcharges: 0, raw_total: 380, }, { service_level: "guaranteed", rate_option: "lowest", carrier: "B", transit_days: "3", transit_description: "3d", raw_freight: 420, surcharges: 0, raw_total: 420, }, { service_level: "guaranteed", rate_option: "fastest", carrier: "B", transit_days: "2", transit_description: "2d", raw_freight: 480, surcharges: 0, raw_total: 480, }, ]; describe("detectDeviation", () => { beforeEach(() => { vi.clearAllMocks(); }); it("TC-212 首次询价不触发偏差预警", async () => { prismaMock.quoteCacheMeta.findUnique.mockResolvedValue(null); prismaMock.quoteCacheMeta.create.mockResolvedValue({}); await detectDeviation("hash1", fourTiers(), "QTE001"); expect(prismaMock.alertLog.create).not.toHaveBeenCalled(); expect(prismaMock.quoteCacheMeta.create).toHaveBeenCalled(); }); it("TC-210 偏差≥5% 写 PRICE_DEVIATION", async () => { prismaMock.quoteCacheMeta.findUnique.mockResolvedValue({ cargoHash: "hash1", rawTotalStandard: 352, }); prismaMock.quoteCacheMeta.update.mockResolvedValue({}); prismaMock.alertLog.create.mockResolvedValue({}); const quotes = fourTiers(); quotes[0].raw_total = 370; quotes[0].raw_freight = 370; await detectDeviation("hash1", quotes, "QTE002"); expect(prismaMock.alertLog.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ alertType: "PRICE_DEVIATION" }), }), ); }); it("TC-211 偏差4.9% 不触发", async () => { prismaMock.quoteCacheMeta.findUnique.mockResolvedValue({ cargoHash: "hash1", rawTotalStandard: 352, }); prismaMock.quoteCacheMeta.update.mockResolvedValue({}); const quotes = fourTiers(); quotes[0].raw_total = 369.25; quotes[0].raw_freight = 369.25; await detectDeviation("hash1", quotes, "QTE003"); expect(prismaMock.alertLog.create).not.toHaveBeenCalled(); expect(prismaMock.quoteCacheMeta.update).toHaveBeenCalled(); }); });