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.

584 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { describe, expect, it } from "vitest";
import {
AXEL_QUOTE_BODY,
AXEL_QUOTE_URL,
} from "@/__tests__/fixtures/axel-quote";
import {
decodeAxelQuoteBodyLenient,
decodeQuoteDetailsParam,
decodeQuotePayloads,
decodeEmbeddedJsonBodies,
} from "@/workers/rpa/quote-capture/payload-decode";
import {
formatPinnedTelemetry,
isJsonNetworkCandidate,
parsePinnedQuoteApiPatterns,
} from "@/workers/rpa/quote-capture/constants";
import {
assertQuoteContract,
inspectQuoteContract,
satisfiesQuoteContract,
} from "@/workers/rpa/quote-capture/quote-contract-guard";
import { validateQuoteSchema } from "@/workers/rpa/quote-capture/quote-schema-validator";
import type { QuoteCaptureSignals } from "@/workers/rpa/quote-capture/types";
import { RpaError } from "@/modules/rpa/errors";
const validRatesBody = {
rates: {
standard: {
lowest: { price: 612.72, transitDays: "5 business days" },
fastest: { price: 694.02, transitDays: "3 business days" },
},
guaranteed: {
lowest: { price: 800, transitDays: "5 business days" },
fastest: { price: 900, transitDays: "2 business days" },
},
},
};
describe("quote contract guard", () => {
it("满足 rates.standard.lowest + rates.standard.fastest + rates.guaranteed", () => {
expect(satisfiesQuoteContract(validRatesBody)).toBe(true);
});
it("缺少 rates.guaranteed 时 fail", () => {
const result = inspectQuoteContract({
rates: {
standard: {
lowest: { price: 1 },
fastest: { price: 2 },
},
},
});
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.violations.some((v) => v.path.includes("guaranteed"))).toBe(
true,
);
}
});
it("缺少 fastest 时 fail", () => {
const result = inspectQuoteContract({
rates: {
standard: { lowest: { price: 1 } },
guaranteed: { lowest: { price: 2 } },
},
});
expect(result.ok).toBe(false);
});
it("assertQuoteContract 抛 RPA_DATA_INVALID", () => {
expect(() => assertQuoteContract({ foo: 1 }, "test-url")).toThrow(RpaError);
});
it("接受 rates.fastest 顶层", () => {
expect(
satisfiesQuoteContract({
rates: {
standard: { lowest: { price: 10 } },
fastest: { price: 20, transitDays: "2d" },
guaranteed: { lowest: { price: 30 } },
},
}),
).toBe(true);
});
it("接受 axel guaranteed.bestValue 作为 guaranteed 定价阶段0 录证)", () => {
expect(satisfiesQuoteContract(AXEL_QUOTE_BODY)).toBe(true);
});
});
describe("isJsonNetworkCandidate", () => {
it("JSON 响应通过(与 URL 路径无关)", () => {
expect(
isJsonNetworkCandidate(
"https://any-host.example/unknown-path",
"application/json",
),
).toBe(true);
});
it("忽略 segment 静态埋点", () => {
expect(
isJsonNetworkCandidate(
"https://api.segment.io/v1/track",
"application/json",
),
).toBe(false);
});
});
describe("pinned telemetry", () => {
it("parsePinnedQuoteApiPatterns 仅用于校准日志", () => {
process.env.MOTHERSHIP_QUOTE_API_URL_PATTERNS = "api.mothership.com/quotes";
expect(
formatPinnedTelemetry("https://api.mothership.com/quotes/x"),
).toBe("pinned=match");
expect(formatPinnedTelemetry("https://other.example/x")).toBe("pinned=miss");
delete process.env.MOTHERSHIP_QUOTE_API_URL_PATTERNS;
});
it("未配置 pinned 时 telemetry 提示未配置", () => {
delete process.env.MOTHERSHIP_QUOTE_API_URL_PATTERNS;
expect(formatPinnedTelemetry("https://x")).toBe("pinned=未配置");
});
});
describe("decodeQuoteDetailsParam", () => {
it("解码 URL 编码 JSON诊断用非报价路径", () => {
const inner = JSON.stringify({
pickupLocation: { city: "Denver", zip: "80203" },
freight: { quantity: 2, weightLbs: 500 },
});
const encoded = encodeURIComponent(inner);
expect(decodeQuoteDetailsParam(encoded)).toMatchObject({
pickupLocation: { city: "Denver" },
});
});
});
describe("decodeQuotePayloads", () => {
function signals(overrides: Partial<QuoteCaptureSignals>): QuoteCaptureSignals {
return {
contractPayloads: [],
jsonPayloads: [],
resultUrl: "https://www.mothership.com/",
...overrides,
};
}
it("data.rates 嵌套解析标准 Tab 档位", () => {
const result = decodeQuotePayloads(
signals({
contractPayloads: [
{
url: "https://api.example/graphql",
body: { data: { rates: validRatesBody.rates } },
},
],
}),
);
expect(result?.items).toHaveLength(4);
});
it("契约响应解析标准 Tab 档位", () => {
const result = decodeQuotePayloads(
signals({
contractPayloads: [
{ url: "https://any.example/rates", body: validRatesBody },
],
}),
);
expect(result?.source).toBe("contract");
expect(result?.items).toHaveLength(4);
expect(
result?.items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "lowest",
)?.rawFreight,
).toBe(612.72);
});
it("axel/quote 响应解析全部档位(标准 3 + guaranteed.bestValue", () => {
const decoded = decodeQuotePayloads(
signals({
contractPayloads: [{ url: AXEL_QUOTE_URL, body: AXEL_QUOTE_BODY }],
}),
);
const items = validateQuoteSchema(decoded!.items);
expect(items).toHaveLength(4);
expect(
items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "bestValue",
)?.rawFreight,
).toBe(576.24);
expect(
items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "lowest",
)?.rawFreight,
).toBe(428.48);
expect(
items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "fastest",
)?.transitDays,
).toBe("Est. 3 business days");
expect(
items.find(
(i) => i.serviceLevel === "guaranteed" && i.rateOption === "bestValue",
)?.rawFreight,
).toBe(814.15);
});
it("2+2 动态档位:仅返回 API 存在的四档", () => {
const body = {
data: {
rates: {
standard: {
lowest: { finalPrice: 100, days: 4, serviceType: "lowest" },
fastest: { finalPrice: 120, days: 2, serviceType: "fastest" },
},
guaranteed: {
lowest: { finalPrice: 200, days: 3, serviceType: "lowest" },
bestValue: { finalPrice: 220, days: 2, serviceType: "bestValue" },
},
},
},
};
const items = validateQuoteSchema(
decodeQuotePayloads(
signals({
contractPayloads: [{ url: AXEL_QUOTE_URL, body }],
}),
)!.items,
);
expect(items).toHaveLength(4);
});
it("基线 UI 截图五档:标准 3 + 保证送达 2finalPrice", () => {
const body = {
data: {
rates: {
standard: {
lowest: { finalPrice: 287.23, days: 4, serviceType: "lowest" },
bestValue: { finalPrice: 345, days: 3, serviceType: "bestValue" },
fastest: { finalPrice: 369.72, days: 2, serviceType: "fastest" },
},
guaranteed: {
lowest: { finalPrice: 457.36, days: 3, serviceType: "lowest" },
bestValue: { finalPrice: 480.37, days: 2, serviceType: "bestValue" },
},
},
availableRates: {},
},
};
const decoded = decodeQuotePayloads(
signals({
contractPayloads: [{ url: AXEL_QUOTE_URL, body }],
}),
);
const items = validateQuoteSchema(decoded!.items);
expect(items).toHaveLength(5);
expect(items.find((i) => i.serviceLevel === "standard" && i.rateOption === "lowest")?.rawFreight).toBe(287.23);
expect(items.find((i) => i.serviceLevel === "standard" && i.rateOption === "bestValue")?.rawFreight).toBe(345);
expect(items.find((i) => i.serviceLevel === "standard" && i.rateOption === "fastest")?.rawFreight).toBe(369.72);
expect(items.find((i) => i.serviceLevel === "guaranteed" && i.rateOption === "lowest")?.rawFreight).toBe(457.36);
expect(items.find((i) => i.serviceLevel === "guaranteed" && i.rateOption === "bestValue")?.rawFreight).toBe(480.37);
});
it("availableRates extended 不覆盖 UI 叶节点 finalPrice", () => {
const body = {
data: {
rates: {
standard: {
lowest: {
id: "rate_x",
finalPrice: 287.23,
price: 478.46,
days: 4,
serviceType: "lowest",
},
fastest: {
id: "rate_y",
finalPrice: 369.72,
price: 2069.46,
days: 2,
serviceType: "fastest",
},
bestValue: {
id: "rate_z",
finalPrice: 345,
price: 500,
days: 3,
serviceType: "bestValue",
},
},
guaranteed: {
lowest: { finalPrice: 457.36, days: 3, serviceType: "lowest" },
bestValue: { finalPrice: 480.37, days: 2, serviceType: "bestValue" },
},
},
availableRates: {
rate_x: {
price: 478.46,
serviceType: "customRate",
serviceLevel: "standard",
},
},
},
};
const decoded = decodeQuotePayloads(
signals({
contractPayloads: [{ url: "https://services.mothership.com/axel/quote", body }],
}),
);
const items = validateQuoteSchema(decoded!.items);
expect(items).toHaveLength(5);
expect(
items.find((i) => i.serviceLevel === "standard" && i.rateOption === "lowest")?.rawFreight,
).toBe(287.23);
expect(
items.find((i) => i.serviceLevel === "standard" && i.rateOption === "fastest")?.rawFreight,
).toBe(369.72);
expect(
items.find((i) => i.serviceLevel === "standard" && i.rateOption === "bestValue")?.rawFreight,
).toBe(345);
expect(
items.find((i) => i.serviceLevel === "guaranteed" && i.rateOption === "lowest")?.rawFreight,
).toBe(457.36);
});
it("rates 已声明 UI 槽位时禁止 customRate 推断伪档位3+1", () => {
const body = {
data: {
rates: {
standard: {
lowest: { finalPrice: 310.01, days: 8, serviceType: "lowest" },
bestValue: { finalPrice: 566.33, days: 5, serviceType: "bestValue" },
fastest: { finalPrice: 768.88, days: 4, serviceType: "fastest" },
},
guaranteed: {
bestValue: { finalPrice: 698.81, days: 5, serviceType: "bestValue" },
},
},
availableRates: {
junk_g1: {
finalPrice: 704.38,
days: 5,
serviceLevel: "guaranteed",
serviceType: "customRate",
carrierInfo: { name: "TForce" },
},
junk_g2: {
finalPrice: 566.33,
days: 2,
serviceLevel: "standard",
serviceType: "customRate",
carrierInfo: { name: "Daylight Transport" },
},
junk_g3: {
finalPrice: 650.99,
days: 6,
serviceLevel: "standard",
serviceType: "customRate",
carrierInfo: { name: "Roadrunner Transportation Service" },
},
},
},
};
const items = validateQuoteSchema(decodeAxelQuoteBodyLenient(body)!);
expect(items).toHaveLength(4);
expect(
items.find(
(i) => i.serviceLevel === "guaranteed" && i.rateOption === "lowest",
),
).toBeUndefined();
expect(
items.find(
(i) => i.serviceLevel === "guaranteed" && i.rateOption === "fastest",
),
).toBeUndefined();
expect(
items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "lowest",
)?.rawFreight,
).toBe(310.01);
});
it("rates 声明 bestValue 槽位且叶节点为空时从 availableRates 补全", () => {
const body = {
data: {
rates: {
standard: {
lowest: { finalPrice: 503.98, days: 4, serviceType: "lowest" },
fastest: { finalPrice: 597.89, days: 2, serviceType: "fastest" },
bestValue: {},
},
guaranteed: {
bestValue: { finalPrice: 954.25, days: 2, serviceType: "bestValue" },
},
},
availableRates: {
rate_bv: {
finalPrice: 545.5,
days: 3,
serviceLevel: "standard",
serviceType: "bestValue",
},
},
},
};
const items = validateQuoteSchema(decodeAxelQuoteBodyLenient(body)!);
expect(items).toHaveLength(4);
expect(
items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "bestValue",
)?.rawFreight,
).toBe(545.5);
});
it("rates.standard.fastest 为 id 引用时从 availableRates 解析", () => {
const body = {
data: {
rates: {
standard: {
lowest: { finalPrice: 310.01, days: 8, serviceType: "lowest" },
bestValue: { finalPrice: 566.33, days: 5, serviceType: "bestValue" },
fastest: { id: "rate_fast" },
},
guaranteed: {
bestValue: { finalPrice: 698.81, days: 5, serviceType: "bestValue" },
},
},
availableRates: {
rate_fast: {
finalPrice: 768.88,
days: 4,
serviceLevel: "standard",
serviceType: "fastest",
carrierInfo: { name: "XPO Logistics" },
},
},
},
};
const items = validateQuoteSchema(decodeAxelQuoteBodyLenient(body)!);
expect(items).toHaveLength(4);
expect(
items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "fastest",
)?.rawFreight,
).toBe(768.88);
});
it("standard 缺 fastest 键时从 availableRates 显式 serviceType 补档", () => {
const body = {
data: {
rates: {
standard: {
lowest: { finalPrice: 310.01, days: 8, serviceType: "lowest" },
bestValue: { finalPrice: 566.33, days: 5, serviceType: "bestValue" },
},
guaranteed: {
bestValue: { finalPrice: 698.81, days: 5, serviceType: "bestValue" },
},
},
availableRates: {
rate_fast: {
finalPrice: 768.88,
days: 4,
serviceLevel: "standard",
serviceType: "fastest",
},
},
},
};
const items = validateQuoteSchema(decodeAxelQuoteBodyLenient(body)!);
expect(
items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "fastest",
)?.rawFreight,
).toBe(768.88);
});
it("无契约响应返回 null", () => {
expect(decodeQuotePayloads(signals({}))).toBeNull();
});
it("不满足契约且无法 lenient 解码时返回 null", () => {
expect(
decodeQuotePayloads(
signals({
contractPayloads: [
{ url: "https://x", body: { rates: { standard: { lowest: { price: 1 } } } } },
],
}),
),
).toBeNull();
});
it("sign-up-quote 页 axel/quote 契约不全时走 lenient", () => {
const body = {
data: {
rates: { standard: {}, guaranteed: {}, dedicated: {} },
availableRates: {
rate_a: {
finalPrice: 612.72,
price: 600,
days: 3,
serviceLevel: "standard",
serviceType: "customRate",
},
rate_b: {
finalPrice: 890.12,
price: 880,
days: 2,
serviceLevel: "standard",
serviceType: "customRate",
},
},
},
};
const decoded = decodeQuotePayloads(
signals({
resultUrl: "https://www.mothership.com/sign-up-quote?quote-details=abc",
contractPayloads: [
{ url: "https://services.mothership.com/axel/quote", body },
],
}),
);
expect(decoded?.source).toBe("lenient");
expect(
decoded?.items.find(
(i) => i.serviceLevel === "standard" && i.rateOption === "lowest",
)?.rawFreight,
).toBe(612.72);
});
});
describe("decodeEmbeddedJsonBodies", () => {
it("已废弃,始终返回 null", () => {
expect(decodeEmbeddedJsonBodies([{ rates: validRatesBody }])).toBeNull();
});
});
describe("decodeAxelQuoteBodyLenient", () => {
it("rates 缺 standard/lowest 时从 availableRates customRate 推断", () => {
const body = {
data: {
rates: {
standard: {},
guaranteed: {},
dedicated: {},
},
availableRates: {
rate_a: {
finalPrice: 927.48,
price: 922.49,
days: 3,
serviceLevel: "standard",
serviceType: "customRate",
carrierInfo: { name: "ABF Freight" },
},
rate_b: {
finalPrice: 1100.12,
price: 1095.13,
days: 2,
serviceLevel: "standard",
serviceType: "customRate",
carrierInfo: { name: "Saia" },
},
},
},
};
const items = decodeAxelQuoteBodyLenient(body);
expect(items).not.toBeNull();
expect(
items!.find((i) => i.serviceLevel === "standard" && i.rateOption === "lowest")
?.rawTotal,
).toBe(927.48);
expect(
items!.find((i) => i.serviceLevel === "standard" && i.rateOption === "fastest")
?.rawTotal,
).toBe(1100.12);
});
});