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.

226 lines
7.3 KiB

import { describe, expect, it, vi, beforeEach } from "vitest";
import type { Page } from "playwright";
import type { QuoteRequest } from "@/modules/providers/quote-provider";
import { fillAddressStep } from "@/workers/rpa/kernel/steps/address-step";
import type { RPAContext } from "@/workers/rpa/kernel/context";
const mockSelectAddress = vi.fn();
const mockWaitForCommit = vi.fn();
const mockGetDiagnostics = vi.fn();
const mockGetCommitState = vi.fn();
vi.mock("@/workers/rpa/address-adapter", () => ({
createAddressAdapter: vi.fn(() => ({
selectAddress: mockSelectAddress,
waitForCommit: mockWaitForCommit,
getCommittedAddress: vi.fn(),
getDiagnostics: mockGetDiagnostics,
getCommitState: mockGetCommitState,
})),
formatDiagnosticsFailure: vi.fn((d) => d.status ?? "failed"),
}));
vi.mock("@/lib/rpa/address-mode", () => ({
isRpaAddressMockMode: vi.fn().mockReturnValue(false),
getRpaAddressMode: vi.fn().mockReturnValue("real"),
}));
vi.mock("@/workers/rpa/address-commit", async (importOriginal) => {
const actual = await importOriginal<typeof import("@/workers/rpa/address-commit")>();
return {
...actual,
blurAddressEditing: vi.fn().mockResolvedValue(undefined),
dismissAddressSuggestionDropdown: vi.fn().mockResolvedValue(undefined),
settlePickupBeforeDelivery: vi.fn().mockResolvedValue(undefined),
assertDualAddressStable: vi.fn().mockResolvedValue(undefined),
ensureDualAddressCommitted: vi.fn().mockResolvedValue(undefined),
isPickupReadyForDeliveryInput: vi.fn().mockResolvedValue(true),
lockPickupIntoChip: vi.fn().mockResolvedValue(undefined),
};
});
vi.mock("@/workers/rpa/address-suggestions", () => ({
isAddressSuggestionDropdownOpen: vi.fn().mockResolvedValue(false),
getAddressConfirmationSurfaceText: vi.fn().mockResolvedValue(""),
}));
vi.mock("@/workers/rpa/address-side", () => ({
openAddressSide: vi.fn().mockResolvedValue(undefined),
visibleStreetInput: vi.fn(),
}));
vi.mock("@/workers/rpa/cargo-lock", () => ({
settleAddressFieldsForCargo: vi.fn().mockResolvedValue(undefined),
assertBothAddressesLocked: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("@/workers/rpa/kernel/step-guard", () => ({
runKernelSubStep: vi.fn(
(_step: string, _label: string, fn: () => Promise<unknown>) => fn(),
),
}));
vi.mock("@/workers/rpa/page-prep", () => ({
stabilizeQuoteLandingPage: vi.fn().mockResolvedValue(undefined),
}));
import { openAddressSide } from "@/workers/rpa/address-side";
function baseRequest(overrides?: Partial<QuoteRequest>): QuoteRequest {
return {
cargoHash: "hash",
quoteSessionId: undefined,
pickup: {
street: "1234 Warehouse Street",
city: "Farmers Branch",
state: "TX",
zip: "75234",
placeId: "p1",
formattedAddress: "1234 Warehouse Street Farmers Branch TX",
selectedFromSuggestions: true,
mothershipOptionId: "o1",
mothershipDisplayLabel: "1234 Warehouse Road Farmers Branch TX",
selectedFromMothership: true,
},
delivery: {
street: "5678 Distribution Way",
city: "Fort Worth",
state: "TX",
zip: "76106",
placeId: "d1",
formattedAddress: "5678 Distribution Way Fort Worth TX",
selectedFromSuggestions: true,
mothershipOptionId: "o2",
mothershipDisplayLabel: "5678 Distribution Drive Fort Worth TX",
selectedFromMothership: true,
},
weightLb: 500,
dimsIn: { l: 48, w: 40, h: 48 },
palletCount: 2,
cargoType: "general_freight",
...overrides,
};
}
function mockCtx(widgetText = ""): RPAContext {
const page = {
keyboard: { press: vi.fn().mockResolvedValue(undefined) },
waitForTimeout: vi.fn().mockResolvedValue(undefined),
locator: vi.fn().mockReturnValue({
innerText: vi.fn().mockResolvedValue(widgetText),
}),
url: vi.fn().mockReturnValue("https://example.com"),
} as unknown as Page;
return {
page,
selectors: {
resolve: vi.fn().mockReturnValue("#widget"),
specs: vi.fn().mockReturnValue([]),
widget: vi.fn(),
},
exec: { evaluateOnLocator: vi.fn() },
runtime: { evaluateOnLocator: vi.fn() },
getWidgetScrollAt: vi.fn().mockReturnValue(0),
setWidgetScrollAt: vi.fn(),
state: {
markAddressSide: vi.fn(),
settleAddressEditing: vi.fn().mockResolvedValue(undefined),
axelPlaceLocations: { pickup: { placeId: "ChIJ_test" } },
},
} as unknown as RPAContext;
}
describe("fillAddressStep", () => {
beforeEach(() => {
vi.clearAllMocks();
mockSelectAddress.mockImplementation(async (params) => {
params.ctx.state.axelPlaceLocations[params.side] = {
placeId: "ChIJ_test",
};
return {
success: true,
placeId: "ChIJ_test",
formattedAddress: "test",
committed: true,
};
});
mockWaitForCommit.mockResolvedValue({
success: true,
placeId: "ChIJ_test",
formattedAddress: "test",
committed: true,
});
mockGetCommitState.mockReturnValue("COMMITTED");
mockGetDiagnostics.mockReturnValue({
address: "test",
placeId: "ChIJ_test",
method: "mothership",
events: [],
placeRequestObserved: true,
status: "ok",
commitState: "COMMITTED",
});
});
it("有 quote_session 时仍走完整填表(禁止跳过)", async () => {
const ctx = mockCtx(
"1234 Warehouse Road Farmers Branch TX 5678 Distribution Drive Fort Worth TX",
);
const loc = {
isEditable: vi.fn().mockResolvedValue(true),
waitFor: vi.fn().mockResolvedValue(undefined),
click: vi.fn().mockResolvedValue(undefined),
};
const { visibleStreetInput } = await import("@/workers/rpa/address-side");
vi.mocked(visibleStreetInput).mockResolvedValue(loc as never);
await fillAddressStep(
ctx,
baseRequest({ quoteSessionId: "session-uuid" }),
);
expect(openAddressSide).toHaveBeenCalled();
expect(mockSelectAddress).toHaveBeenCalled();
});
it("无 quote_session 时走完整填表", async () => {
const ctx = mockCtx(
"1234 Warehouse Road Farmers Branch TX 5678 Distribution Drive Fort Worth TX",
);
const loc = {
isEditable: vi.fn().mockResolvedValue(true),
waitFor: vi.fn().mockResolvedValue(undefined),
click: vi.fn().mockResolvedValue(undefined),
};
const { visibleStreetInput } = await import("@/workers/rpa/address-side");
vi.mocked(visibleStreetInput).mockResolvedValue(loc as never);
await fillAddressStep(ctx, baseRequest());
expect(openAddressSide).toHaveBeenCalled();
expect(mockSelectAddress).toHaveBeenCalledTimes(2);
});
it("widget 未体现确认地址时抛错", async () => {
const { assertDualAddressStable } = await import(
"@/workers/rpa/address-commit"
);
vi.mocked(assertDualAddressStable).mockRejectedValueOnce({
code: "ADDRESS_NOT_CONFIRMED",
});
const ctx = mockCtx("999 Wrong Street Fort Worth TX");
const loc = {
isEditable: vi.fn().mockResolvedValue(true),
waitFor: vi.fn().mockResolvedValue(undefined),
click: vi.fn().mockResolvedValue(undefined),
};
const { visibleStreetInput } = await import("@/workers/rpa/address-side");
vi.mocked(visibleStreetInput).mockResolvedValue(loc as never);
await expect(fillAddressStep(ctx, baseRequest())).rejects.toMatchObject({
code: "ADDRESS_NOT_CONFIRMED",
});
});
});