|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
import type { Page } from "playwright";
|
|
|
import { fillCargoStep } from "@/workers/rpa/kernel/steps/cargo-step";
|
|
|
|
|
|
vi.mock("@/workers/rpa/fill-cargo-in-drawer", () => ({
|
|
|
fillCargoInDrawer: vi.fn().mockResolvedValue({
|
|
|
weightDisplay: {
|
|
|
displayValue: "500",
|
|
|
unit: "lb",
|
|
|
weightLbPerPallet: 500,
|
|
|
},
|
|
|
expected: {
|
|
|
palletCount: 2,
|
|
|
weight: {
|
|
|
displayValue: "500",
|
|
|
unit: "lb",
|
|
|
weightLbPerPallet: 500,
|
|
|
palletCount: 2,
|
|
|
},
|
|
|
},
|
|
|
}),
|
|
|
}));
|
|
|
|
|
|
vi.mock("@/workers/rpa/cargo-lock", () => ({
|
|
|
assertBothAddressesLocked: vi.fn().mockResolvedValue(undefined),
|
|
|
settleAddressFieldsForCargo: vi.fn().mockResolvedValue(undefined),
|
|
|
waitForCargoCommittedState: vi.fn().mockResolvedValue({
|
|
|
hasSummaryChip: true,
|
|
|
visibleEditableCargoInputs: 0,
|
|
|
editorOpen: false,
|
|
|
internalPalletCount: 2,
|
|
|
internalWeight: 500,
|
|
|
widgetTextPreview: "",
|
|
|
}),
|
|
|
}));
|
|
|
|
|
|
const stateCalls: string[] = [];
|
|
|
|
|
|
function mockCtx() {
|
|
|
const page = {
|
|
|
waitForTimeout: vi.fn().mockResolvedValue(undefined),
|
|
|
locator: vi.fn().mockReturnValue({
|
|
|
last: vi.fn().mockReturnValue({
|
|
|
locator: vi.fn().mockReturnValue({ first: vi.fn() }),
|
|
|
}),
|
|
|
filter: vi.fn().mockReturnValue({ nth: vi.fn() }),
|
|
|
first: vi.fn(),
|
|
|
}),
|
|
|
url: vi.fn().mockReturnValue("https://example.com"),
|
|
|
} as unknown as Page;
|
|
|
|
|
|
return {
|
|
|
page,
|
|
|
selectors: {
|
|
|
specs: vi.fn().mockReturnValue(["input"]),
|
|
|
optionalEnv: vi.fn().mockReturnValue(undefined),
|
|
|
resolve: vi.fn().mockReturnValue("#widget"),
|
|
|
widget: vi.fn(),
|
|
|
},
|
|
|
exec: {
|
|
|
evaluateOnLocator: vi.fn().mockResolvedValue(false),
|
|
|
},
|
|
|
runtime: {
|
|
|
evaluateOnLocator: vi.fn(),
|
|
|
},
|
|
|
getWidgetScrollAt: vi.fn().mockReturnValue(0),
|
|
|
setWidgetScrollAt: vi.fn(),
|
|
|
state: {
|
|
|
triggerCargoSection: vi.fn().mockResolvedValue(undefined),
|
|
|
settleAddressEditing: vi.fn(async () => {
|
|
|
stateCalls.push("settle");
|
|
|
}),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
|
|
|
describe("fillCargoStep UI flow", () => {
|
|
|
it("顺序:fillCargoInDrawer → waitForCargoCommittedState", async () => {
|
|
|
const { fillCargoInDrawer } = await import("@/workers/rpa/fill-cargo-in-drawer");
|
|
|
const { waitForCargoCommittedState } = await import("@/workers/rpa/cargo-lock");
|
|
|
|
|
|
const ctx = mockCtx() as never;
|
|
|
await fillCargoStep(ctx, {
|
|
|
cargoHash: "t",
|
|
|
pickup: {} as never,
|
|
|
delivery: {} as never,
|
|
|
weightLb: 500,
|
|
|
dimsIn: { l: 48, w: 40, h: 48 },
|
|
|
palletCount: 2,
|
|
|
cargoType: "general_freight",
|
|
|
});
|
|
|
|
|
|
expect(fillCargoInDrawer).toHaveBeenCalled();
|
|
|
expect(waitForCargoCommittedState).toHaveBeenCalled();
|
|
|
});
|
|
|
|
|
|
it("fillCargoInDrawer 失败时向上抛出", async () => {
|
|
|
const { fillCargoInDrawer } = await import("@/workers/rpa/fill-cargo-in-drawer");
|
|
|
const { RpaError } = await import("@/modules/rpa/errors");
|
|
|
vi.mocked(fillCargoInDrawer).mockRejectedValueOnce(
|
|
|
new RpaError("STRUCT_CHANGE", "货物 drawer 内未找到任何重量输入框", {
|
|
|
retryable: true,
|
|
|
}),
|
|
|
);
|
|
|
const ctx = mockCtx() as never;
|
|
|
await expect(
|
|
|
fillCargoStep(ctx, {
|
|
|
cargoHash: "t",
|
|
|
pickup: {} as never,
|
|
|
delivery: {} as never,
|
|
|
weightLb: 500,
|
|
|
dimsIn: { l: 48, w: 40, h: 48 },
|
|
|
palletCount: 2,
|
|
|
cargoType: "general_freight",
|
|
|
}),
|
|
|
).rejects.toMatchObject({ code: "STRUCT_CHANGE" });
|
|
|
});
|
|
|
});
|