|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
import {
|
|
|
axelSearchRowToCandidate,
|
|
|
resolveAxelMothershipCandidates,
|
|
|
} from "@/lib/axel/candidates";
|
|
|
import { AxelHttpClient } from "@/lib/axel/client";
|
|
|
|
|
|
describe("axelSearchRowToCandidate", () => {
|
|
|
it("display_label 与 axel description 一致,option_id 保留原始 placeId", () => {
|
|
|
const row = {
|
|
|
placeId: "ChIJ4cLf10jGwoARBQWdZHer2OQ",
|
|
|
description: "123 Main Street, Los Angeles, CA, USA",
|
|
|
mainText: "123 Main Street",
|
|
|
secondaryText: "Los Angeles, CA, USA",
|
|
|
};
|
|
|
const candidate = axelSearchRowToCandidate(row, {
|
|
|
street: "123 Main St",
|
|
|
city: "Los Angeles",
|
|
|
state: "CA",
|
|
|
zip: "90001",
|
|
|
});
|
|
|
expect(candidate?.option_id).toBe("ChIJ4cLf10jGwoARBQWdZHer2OQ");
|
|
|
expect(candidate?.display_label).toBe(
|
|
|
"123 Main Street, Los Angeles, CA, USA",
|
|
|
);
|
|
|
expect(candidate?.street).toContain("123");
|
|
|
});
|
|
|
});
|
|
|
|
|
|
describe("resolveAxelMothershipCandidates", () => {
|
|
|
beforeEach(() => {
|
|
|
vi.restoreAllMocks();
|
|
|
vi.stubEnv("AXEL_CANDIDATE_VERIFY_TOP_K", "3");
|
|
|
});
|
|
|
|
|
|
function makeSearchRow(suffix: string) {
|
|
|
return {
|
|
|
placeId: `ChIJ-${suffix}`,
|
|
|
description: `${suffix} Main Street, Dallas, TX, USA`,
|
|
|
mainText: `${suffix} Main Street`,
|
|
|
secondaryText: "Dallas, TX, USA",
|
|
|
};
|
|
|
}
|
|
|
|
|
|
it("仅对前 3 条候选 fetchPlace 校验,其余默认可选", async () => {
|
|
|
const fetchPlace = vi.fn().mockResolvedValue({ placeId: "ok" });
|
|
|
const searchLocation = vi
|
|
|
.fn()
|
|
|
.mockResolvedValueOnce([
|
|
|
makeSearchRow("1"),
|
|
|
makeSearchRow("2"),
|
|
|
makeSearchRow("3"),
|
|
|
makeSearchRow("4"),
|
|
|
makeSearchRow("5"),
|
|
|
])
|
|
|
.mockResolvedValueOnce([makeSearchRow("d1")]);
|
|
|
|
|
|
vi.spyOn(AxelHttpClient, "create").mockResolvedValue({
|
|
|
searchLocation,
|
|
|
fetchPlace,
|
|
|
} as unknown as AxelHttpClient);
|
|
|
|
|
|
const result = await resolveAxelMothershipCandidates({
|
|
|
pickup: {
|
|
|
street: "1 Main St",
|
|
|
city: "Dallas",
|
|
|
state: "TX",
|
|
|
zip: "75201",
|
|
|
},
|
|
|
delivery: {
|
|
|
street: "2 Oak Ave",
|
|
|
city: "Los Angeles",
|
|
|
state: "CA",
|
|
|
zip: "90001",
|
|
|
},
|
|
|
});
|
|
|
|
|
|
expect(result.pickup_candidates).toHaveLength(5);
|
|
|
expect(result.delivery_candidates).toHaveLength(1);
|
|
|
expect(fetchPlace).toHaveBeenCalledTimes(4);
|
|
|
expect(result.pickup_candidates[0]?.selectable).toBe(true);
|
|
|
expect(result.pickup_candidates[3]?.selectable).toBe(true);
|
|
|
expect(result.pickup_candidates[4]?.selectable).toBe(true);
|
|
|
});
|
|
|
|
|
|
it("前 K 条均失败时,未校验候选仍可使 assert 通过", async () => {
|
|
|
const fetchPlace = vi
|
|
|
.fn()
|
|
|
.mockRejectedValueOnce(new Error("place 404"))
|
|
|
.mockRejectedValueOnce(new Error("place 404"))
|
|
|
.mockRejectedValueOnce(new Error("place 404"))
|
|
|
.mockResolvedValueOnce({ placeId: "ChIJ-d1" });
|
|
|
const searchLocation = vi
|
|
|
.fn()
|
|
|
.mockResolvedValueOnce([
|
|
|
makeSearchRow("bad1"),
|
|
|
makeSearchRow("bad2"),
|
|
|
makeSearchRow("bad3"),
|
|
|
makeSearchRow("good-tail"),
|
|
|
])
|
|
|
.mockResolvedValueOnce([makeSearchRow("d1")]);
|
|
|
|
|
|
vi.spyOn(AxelHttpClient, "create").mockResolvedValue({
|
|
|
searchLocation,
|
|
|
fetchPlace,
|
|
|
} as unknown as AxelHttpClient);
|
|
|
|
|
|
const result = await resolveAxelMothershipCandidates({
|
|
|
pickup: {
|
|
|
street: "99 Main St",
|
|
|
city: "Dallas",
|
|
|
state: "TX",
|
|
|
zip: "75201",
|
|
|
},
|
|
|
delivery: {
|
|
|
street: "1 Oak",
|
|
|
city: "LA",
|
|
|
state: "CA",
|
|
|
zip: "90001",
|
|
|
},
|
|
|
});
|
|
|
|
|
|
expect(result.pickup_candidates[0]?.selectable).toBe(false);
|
|
|
expect(result.pickup_candidates[3]?.selectable).toBe(true);
|
|
|
expect(fetchPlace).toHaveBeenCalledTimes(4);
|
|
|
});
|
|
|
});
|