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
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",
|
|
});
|
|
});
|
|
});
|