|
|
import { describe, expect, it } from "vitest";
|
|
|
import {
|
|
|
computeFreightDensity,
|
|
|
densityPcfToFreightClass,
|
|
|
formatFreightClassDensityTip,
|
|
|
formatNmfcDensityClassChartZh,
|
|
|
freightClassDensityMismatchMessage,
|
|
|
NMFC_DENSITY_CLASS_BANDS,
|
|
|
NMFC_NON_DENSITY_FREIGHT_CLASSES,
|
|
|
} from "@/lib/flock/freight-class-density";
|
|
|
|
|
|
describe("freight-class-density(NMFTA 2025 十三档,对齐 Flock)", () => {
|
|
|
it("官网样例:6×48×40×48、2000lb → 320 ft³ / 6.25 PCF → Class 125", () => {
|
|
|
const d = computeFreightDensity({
|
|
|
lengthIn: 48,
|
|
|
widthIn: 40,
|
|
|
heightIn: 48,
|
|
|
quantity: 6,
|
|
|
totalWeightLb: 2000,
|
|
|
});
|
|
|
expect(d).not.toBeNull();
|
|
|
expect(d!.cubicFeet).toBeCloseTo(320, 2);
|
|
|
expect(d!.densityPcf).toBeCloseTo(6.25, 2);
|
|
|
expect(d!.suggestedClass).toBe("125");
|
|
|
expect(d!.rangeLabelZh).toBe("6 – <8");
|
|
|
expect(formatFreightClassDensityTip(d)).toContain("基于密度的货运等级:125");
|
|
|
});
|
|
|
|
|
|
it("官网样例:2×48×40×48、5000lb → ~46.88 PCF → Class 55", () => {
|
|
|
const d = computeFreightDensity({
|
|
|
lengthIn: 48,
|
|
|
widthIn: 40,
|
|
|
heightIn: 48,
|
|
|
quantity: 2,
|
|
|
totalWeightLb: 5000,
|
|
|
});
|
|
|
expect(d!.suggestedClass).toBe("55");
|
|
|
expect(d!.densityPcf).toBeCloseTo(46.875, 2);
|
|
|
});
|
|
|
|
|
|
it("十三档边界全部对齐 NMFTA「X but less than Y」", () => {
|
|
|
const cases: Array<[number, string]> = [
|
|
|
[0.5, "400"],
|
|
|
[0.999, "400"],
|
|
|
[1, "300"],
|
|
|
[1.999, "300"],
|
|
|
[2, "250"],
|
|
|
[3.999, "250"],
|
|
|
[4, "175"],
|
|
|
[5.999, "175"],
|
|
|
[6, "125"],
|
|
|
[7.999, "125"],
|
|
|
[8, "100"],
|
|
|
[9.999, "100"],
|
|
|
[10, "92.5"],
|
|
|
[11.999, "92.5"],
|
|
|
[12, "85"],
|
|
|
[14.999, "85"],
|
|
|
[15, "70"],
|
|
|
[22.499, "70"],
|
|
|
[22.5, "65"],
|
|
|
[29.999, "65"],
|
|
|
[30, "60"],
|
|
|
[34.999, "60"],
|
|
|
[35, "55"],
|
|
|
[49.999, "55"],
|
|
|
[50, "50"],
|
|
|
[100, "50"],
|
|
|
];
|
|
|
for (const [pcf, expected] of cases) {
|
|
|
expect(densityPcfToFreightClass(pcf), `pcf=${pcf}`).toBe(expected);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
it("密度推算绝不会落到商品条件档 77.5/110/150/200/500", () => {
|
|
|
const densClasses = new Set(
|
|
|
NMFC_DENSITY_CLASS_BANDS.map((b) => b.freightClass),
|
|
|
);
|
|
|
for (const c of NMFC_NON_DENSITY_FREIGHT_CLASSES) {
|
|
|
expect(densClasses.has(c)).toBe(false);
|
|
|
}
|
|
|
// 扫一圈常见 PCF,结果必须在十三档内
|
|
|
for (let p = 0.1; p <= 60; p += 0.37) {
|
|
|
const c = densityPcfToFreightClass(p);
|
|
|
expect(c).not.toBeNull();
|
|
|
expect(densClasses.has(c!)).toBe(true);
|
|
|
expect(
|
|
|
(NMFC_NON_DENSITY_FREIGHT_CLASSES as readonly string[]).includes(c!),
|
|
|
).toBe(false);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
it("体积↑或重量↓ → 等级数字↑(用户感知:参数越「稀」等级越高)", () => {
|
|
|
const base = {
|
|
|
lengthIn: 48,
|
|
|
widthIn: 40,
|
|
|
heightIn: 48,
|
|
|
quantity: 1,
|
|
|
totalWeightLb: 1000,
|
|
|
};
|
|
|
const dense = computeFreightDensity(base)!; // ~18.75 → 70
|
|
|
const bulkier = computeFreightDensity({ ...base, heightIn: 96 })!; // 体积翻倍
|
|
|
const lighter = computeFreightDensity({ ...base, totalWeightLb: 200 })!;
|
|
|
expect(Number(bulkier.suggestedClass)).toBeGreaterThan(
|
|
|
Number(dense.suggestedClass),
|
|
|
);
|
|
|
expect(Number(lighter.suggestedClass)).toBeGreaterThan(
|
|
|
Number(dense.suggestedClass),
|
|
|
);
|
|
|
});
|
|
|
|
|
|
it("分档表文案含全部十三档与非密度档说明", () => {
|
|
|
const chart = formatNmfcDensityClassChartZh();
|
|
|
for (const b of NMFC_DENSITY_CLASS_BANDS) {
|
|
|
expect(chart).toContain(`等级 ${b.freightClass}`);
|
|
|
}
|
|
|
expect(chart).toContain("77.5");
|
|
|
expect(formatFreightClassDensityTip(null)).toContain("总体积");
|
|
|
});
|
|
|
|
|
|
it("手选与推算不一致才提示", () => {
|
|
|
const d = computeFreightDensity({
|
|
|
lengthIn: 48,
|
|
|
widthIn: 40,
|
|
|
heightIn: 48,
|
|
|
quantity: 6,
|
|
|
totalWeightLb: 2000,
|
|
|
});
|
|
|
expect(freightClassDensityMismatchMessage("100", d)).toMatch(
|
|
|
/请选择货运等级 125/,
|
|
|
);
|
|
|
expect(freightClassDensityMismatchMessage("125", d)).toBeNull();
|
|
|
expect(freightClassDensityMismatchMessage("density", d)).toBeNull();
|
|
|
});
|
|
|
});
|