Handle "STOP" command failures by interpreting "lane not occupied" as a safe-to-clear state. Refactor error handling, add clearActiveWashState, and extend unit/E2E tests with this scenario.
This commit is contained in:
@@ -633,6 +633,55 @@ test.describe("Self-serve wash", () => {
|
||||
await expect(page.getByTestId("self-serve-nav-complete")).toBeVisible();
|
||||
});
|
||||
|
||||
test("already-ended stop response completes stale in-progress progress", async ({ page }) => {
|
||||
await seedSavedProgress(page, {
|
||||
washInProgress: true,
|
||||
washLaneId: 7,
|
||||
washStartTime: Date.now() - 30_000,
|
||||
currentStep: 4,
|
||||
licensePlateInput: "AB12345",
|
||||
vehicleTypeSelect: 2,
|
||||
radioLaneOption: 7,
|
||||
radioWashType: "Manual",
|
||||
customerNumberInput: "12345679",
|
||||
});
|
||||
|
||||
await mockApi(page, {
|
||||
authenticated: true,
|
||||
permissions: ["user"],
|
||||
selfServe: {
|
||||
commandResponses: [
|
||||
{
|
||||
success: false,
|
||||
data: {
|
||||
message: "Failed to execute command: Cannot stop lane: Lane is not occupied.",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
await primeSession(page, {
|
||||
token: "self-serve-stop-already-ended-token",
|
||||
permissions: ["user"],
|
||||
});
|
||||
|
||||
await page.goto("/user/wash/start");
|
||||
await expect(page.getByTestId("self-serve-live-elapsed")).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
await advanceGuidedWashToLastStep(page);
|
||||
const stopCommandRequestPromise = waitForLaneCommandRequest(page, "STOP");
|
||||
await page.getByTestId("self-serve-nav-complete").click();
|
||||
const stopCommandRequest = await stopCommandRequestPromise;
|
||||
|
||||
expect(stopCommandRequest.postDataJSON?.()).toMatchObject({
|
||||
lane_id: 7,
|
||||
command: "STOP",
|
||||
});
|
||||
await expect(page.getByTestId("self-serve-action-error")).toBeHidden();
|
||||
await expect(page.getByTestId("self-serve-completed-step")).toBeVisible();
|
||||
await expect(page.getByTestId("self-serve-live-elapsed")).toBeHidden();
|
||||
});
|
||||
|
||||
test("edge gateway preview and summary refreshes stay read-only until confirmation", async ({ page }) => {
|
||||
const requests = captureSelfServeGatewayRequests(page);
|
||||
|
||||
|
||||
@@ -279,6 +279,51 @@ describe("useWashSessionActions property gate commands", () => {
|
||||
expect(clearProgress).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clears active wash state when stop reports the lane is already unoccupied", async () => {
|
||||
const washInProgress = ref(true);
|
||||
const washLaneId = ref(7);
|
||||
const washStartTime = ref(1_000);
|
||||
const completedDurationMs = ref(null);
|
||||
const now = ref(46_000);
|
||||
const clearProgress = vi.fn();
|
||||
const stopElapsedTimer = vi.fn();
|
||||
const request = vi.fn(async (_url, _method, body) => {
|
||||
if (body.command === "STOP") {
|
||||
return {
|
||||
data: {
|
||||
success: false,
|
||||
data: {
|
||||
message: "Failed to execute command: Cannot stop lane: Lane is not occupied.",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return { data: { success: true } };
|
||||
});
|
||||
|
||||
const { actions, alertFn } = createActions({
|
||||
request,
|
||||
washInProgress,
|
||||
washLaneId,
|
||||
washStartTime,
|
||||
completedDurationMs,
|
||||
now,
|
||||
clearProgress,
|
||||
stopElapsedTimer,
|
||||
});
|
||||
|
||||
const result = await actions.onStopWash(7);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(alertFn).not.toHaveBeenCalled();
|
||||
expect(completedDurationMs.value).toBe(45_000);
|
||||
expect(washInProgress.value).toBe(false);
|
||||
expect(washLaneId.value).toBeNull();
|
||||
expect(stopElapsedTimer).toHaveBeenCalledTimes(1);
|
||||
expect(clearProgress).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("clears active wash state only after the stop command succeeds", async () => {
|
||||
const washInProgress = ref(true);
|
||||
const washLaneId = ref(7);
|
||||
|
||||
Reference in New Issue
Block a user