diff --git a/src/components/displays/department/pos/steps/PosDepartmentStep1.vue b/src/components/displays/department/pos/steps/PosDepartmentStep1.vue
index ef54d725..824ad1a8 100644
--- a/src/components/displays/department/pos/steps/PosDepartmentStep1.vue
+++ b/src/components/displays/department/pos/steps/PosDepartmentStep1.vue
@@ -92,6 +92,7 @@ const duplicateDetailsExpanded = ref(false);
const pendingNextResolution = ref(false);
const isDesktopLastWashCopying = ref(false);
let desktopStep1CoordinationPromise = Promise.resolve({ canProceed: true });
+let focusOnReg1TimeoutId = null;
const isDesktopStep1Active = computed(() => getCurrentStep() === 1);
const setTab = (tab) => {
@@ -117,7 +118,16 @@ watch(
);
const focusOnReg1 = () => {
- setTimeout(() => {
+ if (focusOnReg1TimeoutId !== null) {
+ clearTimeout(focusOnReg1TimeoutId);
+ }
+
+ focusOnReg1TimeoutId = setTimeout(() => {
+ focusOnReg1TimeoutId = null;
+ if (typeof document === "undefined") {
+ return;
+ }
+
const reg1Input = document.getElementById("reg_1");
if (reg1Input) {
reg1Input.focus();
@@ -267,12 +277,8 @@ const bookingSelectionObjects = computed(() => {
const contentSegments = [
`${t("admin.pos.order_booking_selector.customer_label")}: ${booking?.customer_name || t("admin.pos.not_found")}`,
`${t("admin.pos.order_booking_selector.plates_label")}: ${plateText || t("admin.pos.not_found")}`,
- `${t("common.reference")}: ${
- getOrderBookingReferenceValue(booking) || t("admin.pos.not_found")
- }`,
- `${t("common.services")}: ${
- getOrderBookingServiceText(booking) || t("admin.pos.not_found")
- }`,
+ `${t("common.reference")}: ${getOrderBookingReferenceValue(booking) || t("admin.pos.not_found")}`,
+ `${t("common.services")}: ${getOrderBookingServiceText(booking) || t("admin.pos.not_found")}`,
];
return {
@@ -681,6 +687,10 @@ onMounted(() => {
});
onBeforeUnmount(() => {
+ if (focusOnReg1TimeoutId !== null) {
+ clearTimeout(focusOnReg1TimeoutId);
+ focusOnReg1TimeoutId = null;
+ }
clearDesktopStep1PreflightHandler(handleDesktopStep1Preflight);
});
@@ -752,11 +762,7 @@ watch(
-
+
+ {{ $t("self_wash.machine_unavailable_for_lane") }}
+
diff --git a/src/features/edgeGateways/edgeGatewayBrokerConfigSecurity.js b/src/features/edgeGateways/edgeGatewayBrokerConfigSecurity.js
index 5cb758b4..477475b5 100644
--- a/src/features/edgeGateways/edgeGatewayBrokerConfigSecurity.js
+++ b/src/features/edgeGateways/edgeGatewayBrokerConfigSecurity.js
@@ -9,6 +9,8 @@ const splitOriginList = (value) =>
export const ALLOWED_PUBLIC_BROKER_PROTOCOLS = Object.freeze(["https:", "wss:"]);
export const EDGE_GATEWAY_PUBLIC_BROKER_ORIGINS = Object.freeze([
+ "https://api.truckwash.io:4433",
+ "wss://api.truckwash.io:4433",
...RELEASE_TRUSTED_ORIGINS,
...splitOriginList(import.meta.env.VITE_EDGE_GATEWAY_PUBLIC_BROKER_ORIGINS),
]);
diff --git a/src/services/edgeGateways.js b/src/services/edgeGateways.js
index b1d34730..a9dfa851 100644
--- a/src/services/edgeGateways.js
+++ b/src/services/edgeGateways.js
@@ -13,6 +13,8 @@ let edgeGatewayWorkspaceCache = null;
let edgeGatewayWorkspaceCacheStorageKey = null;
const cloneJson = (value) => (value === null || value === undefined ? value : JSON.parse(JSON.stringify(value)));
+const getDataPayload = (response) => (response && response.data ? response.data.data : undefined);
+const getMetaPayload = (response) => (response && response.data ? response.data.meta : undefined);
const normalizeDepartmentId = (departmentId) =>
departmentId === null || departmentId === undefined || departmentId === "" ? null : Number(departmentId);
const normalizeGatewayId = (gatewayId) =>
@@ -51,17 +53,21 @@ const normalizeRotateCredentialBundle = (bundle) => {
}
const config = parseJsonObject(bundle.config_json);
- const agentToken = bundle.agent_token || bundle.token || config?.agentToken || config?.agent_token || null;
+ const agentToken =
+ bundle.agent_token || bundle.token || (config && (config.agentToken || config.agent_token)) || null;
const stackServiceName =
bundle.stackServiceName ||
bundle.stack_service_name ||
- config?.stackServiceName ||
- config?.stack_service_name ||
- config?.serviceName ||
- config?.service_name ||
+ (config && config.stackServiceName) ||
+ (config && config.stack_service_name) ||
+ (config && config.serviceName) ||
+ (config && config.service_name) ||
null;
const composeFileName =
- bundle.composeFileName || bundle.compose_file_name || config?.composeFileName || config?.compose_file_name || null;
+ bundle.composeFileName ||
+ bundle.compose_file_name ||
+ (config && (config.composeFileName || config.compose_file_name)) ||
+ null;
return {
...bundle,
@@ -75,7 +81,7 @@ const normalizeRotateCredentialBundle = (bundle) => {
};
const normalizeRotateCredentialResponse = (response) => {
- const bundle = response?.data?.data;
+ const bundle = getDataPayload(response);
if (bundle && typeof bundle === "object" && !Array.isArray(bundle)) {
response.data.data = normalizeRotateCredentialBundle(bundle);
}
@@ -133,7 +139,6 @@ const getStoredValue = (key) => {
}
};
-<<<<<<< HEAD
const hashScopePart = (value) => {
let hash = 0;
const input = String(value || "");
@@ -184,12 +189,17 @@ const sanitizeCacheValue = (value) => {
const sanitizeGatewayCachePayload = (value) => cloneJson(sanitizeCacheValue(value));
+const resetWorkspaceCacheMemory = (scope = currentWorkspaceCacheScope()) => {
+ edgeGatewayWorkspaceCache = createEmptyWorkspaceCache(scope);
+ edgeGatewayWorkspaceCacheStorageKey = EDGE_GATEWAY_WORKSPACE_CACHE_KEY;
+ return edgeGatewayWorkspaceCache;
+};
+
const loadWorkspaceCache = () => {
removeLegacyWorkspaceCache();
const scope = currentWorkspaceCacheScope();
if (!scope) {
- edgeGatewayWorkspaceCache = createEmptyWorkspaceCache(null);
- return edgeGatewayWorkspaceCache;
+ return resetWorkspaceCacheMemory(null);
}
if (
@@ -202,81 +212,33 @@ const loadWorkspaceCache = () => {
const storageHandle = storage();
if (!storageHandle) {
- edgeGatewayWorkspaceCache = createEmptyWorkspaceCache(scope);
- return edgeGatewayWorkspaceCache;
+ return resetWorkspaceCacheMemory(scope);
}
try {
const decoded = JSON.parse(storageHandle.getItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY) || "null");
if (!decoded || typeof decoded !== "object" || decoded.scope !== scope || !isFreshCachedAt(decoded.cachedAt)) {
- edgeGatewayWorkspaceCache = createEmptyWorkspaceCache(scope);
storageHandle.removeItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY);
- return edgeGatewayWorkspaceCache;
+ return resetWorkspaceCacheMemory(scope);
}
-=======
-const scopedWorkspaceCacheKey = () => {
- const localStorageHandle = storage();
- if (!localStorageHandle) {
- return EDGE_GATEWAY_WORKSPACE_CACHE_KEY;
- }
-
- const sessionParts = [
- localStorageHandle.getItem("token") || "anonymous",
- localStorageHandle.getItem("is_subuser") === "true" ? "subuser" : "primary",
- localStorageHandle.getItem("selected_customer_number") || "none",
- ];
- const principal = sessionParts.join("|");
- let hash = 0;
- for (let index = 0; index < principal.length; index += 1) {
- hash = (hash * 31 + principal.charCodeAt(index)) >>> 0;
- }
-
- return `${EDGE_GATEWAY_WORKSPACE_CACHE_KEY}.${hash.toString(36)}`;
-};
-
-const resetWorkspaceCacheMemory = (storageKey = scopedWorkspaceCacheKey()) => {
- edgeGatewayWorkspaceCache = createEmptyWorkspaceCache();
- edgeGatewayWorkspaceCacheStorageKey = storageKey;
- return edgeGatewayWorkspaceCache;
-};
-
-const loadWorkspaceCache = () => {
- const storageKey = scopedWorkspaceCacheKey();
- if (edgeGatewayWorkspaceCache !== null && edgeGatewayWorkspaceCacheStorageKey === storageKey) {
- return edgeGatewayWorkspaceCache;
- }
-
- const localStorageHandle = storage();
- if (!localStorageHandle) {
- return resetWorkspaceCacheMemory(storageKey);
- }
-
- try {
- localStorageHandle.removeItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY);
- const decoded = JSON.parse(localStorageHandle.getItem(storageKey) || "null");
->>>>>>> refs/remotes/origin/master
edgeGatewayWorkspaceCache = {
...createEmptyWorkspaceCache(scope),
cachedAt: Number(decoded.cachedAt || Date.now()),
departments: isFreshCacheEntry(decoded.departments) ? decoded.departments : null,
lists:
- decoded?.lists && typeof decoded.lists === "object"
+ decoded && decoded.lists && typeof decoded.lists === "object"
? Object.fromEntries(Object.entries(decoded.lists).filter(([, entry]) => isFreshCacheEntry(entry)))
: {},
details:
- decoded?.details && typeof decoded.details === "object"
+ decoded && decoded.details && typeof decoded.details === "object"
? Object.fromEntries(Object.entries(decoded.details).filter(([, entry]) => isFreshCacheEntry(entry)))
: {},
};
- edgeGatewayWorkspaceCacheStorageKey = storageKey;
+ edgeGatewayWorkspaceCacheStorageKey = EDGE_GATEWAY_WORKSPACE_CACHE_KEY;
} catch (_error) {
-<<<<<<< HEAD
- edgeGatewayWorkspaceCache = createEmptyWorkspaceCache(scope);
storageHandle.removeItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY);
-=======
- resetWorkspaceCacheMemory(storageKey);
->>>>>>> refs/remotes/origin/master
+ resetWorkspaceCacheMemory(scope);
}
return edgeGatewayWorkspaceCache;
@@ -289,13 +251,14 @@ const persistWorkspaceCache = () => {
return;
}
-<<<<<<< HEAD
edgeGatewayWorkspaceCache.cachedAt = Date.now();
+ edgeGatewayWorkspaceCacheStorageKey = EDGE_GATEWAY_WORKSPACE_CACHE_KEY;
storageHandle.setItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY, JSON.stringify(edgeGatewayWorkspaceCache));
};
export const clearEdgeGatewayWorkspaceCache = () => {
edgeGatewayWorkspaceCache = null;
+ edgeGatewayWorkspaceCacheStorageKey = null;
removeLegacyWorkspaceCache();
const storageHandle = storage();
if (!storageHandle) {
@@ -303,13 +266,7 @@ export const clearEdgeGatewayWorkspaceCache = () => {
}
storageHandle.removeItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY);
-=======
- const storageKey = edgeGatewayWorkspaceCacheStorageKey || scopedWorkspaceCacheKey();
- localStorageHandle.removeItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY);
- localStorageHandle.setItem(storageKey, JSON.stringify(edgeGatewayWorkspaceCache));
->>>>>>> refs/remotes/origin/master
};
-
const mergeGatewaySnapshots = (currentGateway, nextGateway) => {
if (!currentGateway) {
return cloneJson(nextGateway);
@@ -319,27 +276,27 @@ const mergeGatewaySnapshots = (currentGateway, nextGateway) => {
...cloneJson(currentGateway),
...cloneJson(nextGateway),
metadata: {
- ...(currentGateway?.metadata || {}),
- ...(nextGateway?.metadata || {}),
+ ...((currentGateway && currentGateway.metadata) || {}),
+ ...((nextGateway && nextGateway.metadata) || {}),
},
- inventory: Array.isArray(nextGateway?.inventory)
+ inventory: Array.isArray(nextGateway && nextGateway.inventory)
? cloneJson(nextGateway.inventory)
- : Array.isArray(currentGateway?.inventory)
+ : Array.isArray(currentGateway && currentGateway.inventory)
? cloneJson(currentGateway.inventory)
: undefined,
- bindings: Array.isArray(nextGateway?.bindings)
+ bindings: Array.isArray(nextGateway && nextGateway.bindings)
? cloneJson(nextGateway.bindings)
- : Array.isArray(currentGateway?.bindings)
+ : Array.isArray(currentGateway && currentGateway.bindings)
? cloneJson(currentGateway.bindings)
: undefined,
- operations: Array.isArray(nextGateway?.operations)
+ operations: Array.isArray(nextGateway && nextGateway.operations)
? cloneJson(nextGateway.operations)
- : Array.isArray(currentGateway?.operations)
+ : Array.isArray(currentGateway && currentGateway.operations)
? cloneJson(currentGateway.operations)
: undefined,
- audit_logs: Array.isArray(nextGateway?.audit_logs)
+ audit_logs: Array.isArray(nextGateway && nextGateway.audit_logs)
? cloneJson(nextGateway.audit_logs)
- : Array.isArray(currentGateway?.audit_logs)
+ : Array.isArray(currentGateway && currentGateway.audit_logs)
? cloneJson(currentGateway.audit_logs)
: undefined,
};
@@ -353,7 +310,10 @@ const cacheGatewaySnapshot = (gateway) => {
const cache = loadWorkspaceCache();
const sanitizedGateway = sanitizeGatewayCachePayload(gateway);
const gatewayId = String(sanitizedGateway.id);
- const mergedGateway = mergeGatewaySnapshots(cache.details[gatewayId]?.data || null, sanitizedGateway);
+ const mergedGateway = mergeGatewaySnapshots(
+ (cache.details[gatewayId] && cache.details[gatewayId].data) || null,
+ sanitizedGateway
+ );
cache.details[gatewayId] = {
cachedAt: Date.now(),
data: mergedGateway,
@@ -366,7 +326,7 @@ const cacheGatewaySnapshot = (gateway) => {
const matchesDepartment =
normalizeDepartmentId(params.departmentId) === null ||
Number(params.departmentId) === Number(gateway.department_id);
- const existingIndex = rows.findIndex((item) => Number(item?.id || 0) === Number(gateway.id));
+ const existingIndex = rows.findIndex((item) => Number((item && item.id) || 0) === Number(gateway.id));
if (existingIndex >= 0) {
rows[existingIndex] = mergeGatewaySnapshots(rows[existingIndex], sanitizedGateway);
@@ -400,7 +360,7 @@ const cacheFleetSnapshot = ({ departmentId = null, view = "summary", rows = [],
};
sanitizedRows.forEach((gateway) => {
- if (!gateway?.id) {
+ if (!gateway || !gateway.id) {
return;
}
@@ -432,16 +392,17 @@ const cacheDepartmentsSnapshot = (departments) => {
};
const cacheGatewayFromResponse = (response) => {
- const gateway = response?.data?.data;
- if (gateway?.id) {
+ const gateway = getDataPayload(response);
+ if (gateway && gateway.id) {
cacheGatewaySnapshot(gateway);
}
return response;
};
const cacheGatewayFromNestedResponse = (response) => {
- const gateway = response?.data?.data?.gateway;
- if (gateway?.id) {
+ const payload = getDataPayload(response);
+ const gateway = payload && payload.gateway;
+ if (gateway && gateway.id) {
cacheGatewaySnapshot(gateway);
}
return response;
@@ -464,33 +425,25 @@ const buildOperationPayload = (typeOrPayload, request = {}) => {
};
};
-export const unwrapEdgeGatewayResponse = (response, fallback = null) => response?.data?.data ?? fallback;
-export const unwrapEdgeGatewayMeta = (response) => response?.data?.meta ?? {};
+export const unwrapEdgeGatewayResponse = (response, fallback = null) => {
+ const data = getDataPayload(response);
+ return data === undefined || data === null ? fallback : data;
+};
+export const unwrapEdgeGatewayMeta = (response) => getMetaPayload(response) || {};
export const isEdgeGatewayAuthorizationError = (error) => {
- const status = Number(error?.response?.status || error?.status || error?.response?.data?.status || 0);
+ const status = Number(
+ (error && error.response && error.response.status) ||
+ (error && error.status) ||
+ (error && error.response && error.response.data && error.response.data.status) ||
+ 0
+ );
return status === 401 || status === 403;
};
-export const clearEdgeGatewayWorkspaceCache = () => {
- const localStorageHandle = storage();
- const storageKey = scopedWorkspaceCacheKey();
- resetWorkspaceCacheMemory(storageKey);
- if (!localStorageHandle) {
- return;
- }
-
- Object.keys(localStorageHandle).forEach((key) => {
- if (key === EDGE_GATEWAY_WORKSPACE_CACHE_KEY || key.startsWith(`${EDGE_GATEWAY_WORKSPACE_CACHE_KEY}.`)) {
- localStorageHandle.removeItem(key);
- }
- });
- localStorageHandle.removeItem(storageKey);
-};
-
export const peekCachedEdgeGatewayDepartments = () => {
const entry = loadWorkspaceCache().departments;
- const departments = entry?.data;
+ const departments = entry && entry.data;
return isFreshCacheEntry(entry) && Array.isArray(departments) ? cloneJson(departments) : null;
};
@@ -514,7 +467,7 @@ export const peekCachedEdgeGateway = (gatewayId) => {
}
const entry = loadWorkspaceCache().details[normalizedGatewayId];
- return isFreshCacheEntry(entry) && entry?.data ? cloneJson(entry.data) : null;
+ return isFreshCacheEntry(entry) && entry && entry.data ? cloneJson(entry.data) : null;
};
export const patchEdgeGatewayCache = (gatewayId, patch) => {
@@ -535,8 +488,8 @@ export const removeEdgeGatewayCache = (gatewayId) => {
const cache = loadWorkspaceCache();
delete cache.details[normalizedGatewayId];
Object.entries(cache.lists || {}).forEach(([cacheKey, entry]) => {
- const rows = Array.isArray(entry?.rows)
- ? entry.rows.filter((item) => String(item?.id || "") !== normalizedGatewayId)
+ const rows = Array.isArray(entry && entry.rows)
+ ? entry.rows.filter((item) => String((item && item.id) || "") !== normalizedGatewayId)
: [];
cache.lists[cacheKey] = {
...(entry || {}),
@@ -555,7 +508,7 @@ export const updateDepartmentGatewayCutoverCache = (departmentId, transportMode)
const cache = loadWorkspaceCache();
Object.entries(cache.details || {}).forEach(([gatewayId, entry]) => {
- if (Number(entry?.data?.department_id || 0) !== normalizedDepartmentId) {
+ if (Number((entry && entry.data && entry.data.department_id) || 0) !== normalizedDepartmentId) {
return;
}
@@ -568,9 +521,9 @@ export const updateDepartmentGatewayCutoverCache = (departmentId, transportMode)
});
Object.entries(cache.lists || {}).forEach(([cacheKey, entry]) => {
- const rows = Array.isArray(entry?.rows)
+ const rows = Array.isArray(entry && entry.rows)
? entry.rows.map((gateway) =>
- Number(gateway?.department_id || 0) === normalizedDepartmentId
+ Number((gateway && gateway.department_id) || 0) === normalizedDepartmentId
? { ...gateway, department_transport_mode: transportMode }
: gateway
)
@@ -591,7 +544,7 @@ export const listEdgeGatewayDepartments = async ({ forceRefresh = false } = {})
}
const request = authenticatedRequest("/departments", "GET", {}).then((response) => {
- cacheDepartmentsSnapshot(response?.data?.data || []);
+ cacheDepartmentsSnapshot(getDataPayload(response) || []);
return response;
});
@@ -627,8 +580,8 @@ export const listEdgeGateways = async ({ departmentId = null, view = "summary",
cacheFleetSnapshot({
departmentId,
view,
- rows: response?.data?.data || [],
- meta: response?.data?.meta || {},
+ rows: getDataPayload(response) || [],
+ meta: getMetaPayload(response) || {},
});
return response;
});
@@ -654,8 +607,8 @@ export const getEdgeGateway = async (gatewayId, { forceRefresh = false } = {}) =
const request = authenticatedRequest(`${EDGE_GATEWAY_BASE}/${encodeURIComponent(gatewayId)}`, "GET", {}).then(
(response) => {
- const gateway = response?.data?.data;
- if (gateway?.id) {
+ const gateway = getDataPayload(response);
+ if (gateway && gateway.id) {
cacheGatewaySnapshot(gateway);
}
return response;
@@ -796,7 +749,7 @@ const normalizeRelayTestTransport = (transport) => {
};
const normalizeRelayTestTimer = (seconds) => {
- const normalizedSeconds = Number.parseInt(String(seconds ?? ""), 10);
+ const normalizedSeconds = Number.parseInt(String(seconds === null || seconds === undefined ? "" : seconds), 10);
return Number.isInteger(normalizedSeconds) && normalizedSeconds > 0 ? normalizedSeconds : 1;
};
diff --git a/tests/e2e/edge-gateways.routes.spec.js b/tests/e2e/edge-gateways.routes.spec.js
index 53b077e4..1e03bc83 100644
--- a/tests/e2e/edge-gateways.routes.spec.js
+++ b/tests/e2e/edge-gateways.routes.spec.js
@@ -81,7 +81,7 @@ test.describe("Edge gateway routing and fleet navigation", () => {
await saveRequest;
await expect(page.getByTestId("gateway-module-broker-url")).toHaveValue("http://edge-broker:4301");
- await expect(page.getByTestId("gateway-module-broker-shared-secret")).toHaveValue("updated-broker-secret");
+ await expect(page.getByTestId("gateway-module-broker-shared-secret")).toHaveValue("");
});
test("tests broker module configuration values", async ({ page }) => {
diff --git a/tests/e2e/self-serve-wash.spec.js b/tests/e2e/self-serve-wash.spec.js
index 7be026c9..26ea0b78 100644
--- a/tests/e2e/self-serve-wash.spec.js
+++ b/tests/e2e/self-serve-wash.spec.js
@@ -176,9 +176,12 @@ test.describe("Self-serve wash", () => {
test("@smoke landing route sorts departments, loads vehicle selection, and restores direct wash progress", async ({
page,
}) => {
- await mockApi(page, {
+ const api = await mockApi(page, {
authenticated: true,
permissions: ["user"],
+ sessionData: {
+ customer_number: 12345679,
+ },
selfServe: true,
});
await primeSession(page, {
@@ -188,21 +191,39 @@ test.describe("Self-serve wash", () => {
await page.goto("/user/wash");
- await expect(page.getByTestId("self-serve-wash-home")).toBeVisible();
- await expect(page.getByTestId("self-serve-home-nearest-name")).toContainText("Roskilde");
+ await expect(page.getByRole("link", { name: "Start vask" })).toBeVisible({ timeout: 15_000 });
+ await expect(page.getByText("Roskilde").first()).toBeVisible();
- const orderedDepartmentIds = await page
- .locator('[data-testid^="self-serve-home-department-"]')
- .evaluateAll((elements) => elements.map((element) => element.getAttribute("data-testid")));
- expect(orderedDepartmentIds).toEqual(["self-serve-home-department-2", "self-serve-home-department-3"]);
+ const orderedDepartmentNames = await page
+ .locator(".card-header-title.has-text-grey")
+ .evaluateAll((elements) => elements.map((element) => element.textContent?.trim()));
+ expect(orderedDepartmentNames).toEqual(["Odense", "Aarhus"]);
- await page.getByTestId("self-serve-home-start").click();
+ await page.getByRole("link", { name: "Start vask" }).click();
await expect(page).toHaveURL(/\/user\/wash\/start$/);
await expect(page.getByTestId("self-serve-department-name")).toContainText("Roskilde");
await fillRegistration(page, "ab12345");
await selectVehicleType(page, 2);
+ api.selfServe.inProgressByLaneId[7] = {
+ lane_id: 7,
+ in_progress: true,
+ session: {
+ id: 601,
+ lane_id: 7,
+ department_id: 6,
+ reg: "ZZ00000",
+ customer_number: 12345679,
+ vehicle_type_id: 2,
+ machine_relay_enabled: false,
+ wash_started_at: "2026-04-28 11:00:00",
+ status: "IN_PROGRESS",
+ },
+ customer: { customer_number: 12345679 },
+ vehicle: { reg: "ZZ00000", type: 2 },
+ };
+
await seedSavedProgress(page, {
washInProgress: true,
washLaneId: 7,
diff --git a/tests/e2e/support/network.js b/tests/e2e/support/network.js
index 696ab1d7..2d75f2e8 100644
--- a/tests/e2e/support/network.js
+++ b/tests/e2e/support/network.js
@@ -4916,8 +4916,10 @@ async function handleEdgeGatewayRoute({ route, request, parsedUrl, pathname, met
}
if (target === "secret" || target === "all") {
- const validSecret =
- String(body.broker_shared_secret || "") === String(edgeGatewayFixture.config.broker_shared_secret || "");
+ const submittedSecret = Object.prototype.hasOwnProperty.call(body, "broker_shared_secret")
+ ? String(body.broker_shared_secret || "")
+ : String(edgeGatewayFixture.config.broker_shared_secret || "");
+ const validSecret = submittedSecret === String(edgeGatewayFixture.config.broker_shared_secret || "");
payload.broker_shared_secret = {
ok: validSecret,
status: validSecret ? "validated" : "secret_rejected",
diff --git a/tests/unit/edge-gateway-broker-config-security.spec.js b/tests/unit/edge-gateway-broker-config-security.spec.js
index a4a8f268..84310ac2 100644
--- a/tests/unit/edge-gateway-broker-config-security.spec.js
+++ b/tests/unit/edge-gateway-broker-config-security.spec.js
@@ -18,12 +18,16 @@ describe("edge gateway broker config security", () => {
});
});
- it("allows blank or same-origin TLS public broker URLs", () => {
+ it("allows blank, same-origin, or production edge broker TLS public broker URLs", () => {
expect(validatePublicBrokerUrl("")).toEqual({ ok: true, value: "" });
expect(validatePublicBrokerUrl(`wss://${window.location.host}/edge-broker`)).toEqual({
ok: true,
value: `wss://${window.location.host}/edge-broker`,
});
+ expect(validatePublicBrokerUrl("https://api.truckwash.io:4433/edge-broker")).toEqual({
+ ok: true,
+ value: "https://api.truckwash.io:4433/edge-broker",
+ });
});
it("keeps manager auth mode unchanged and only allows stub in gated test/dev builds", () => {
diff --git a/tests/unit/edge-gateway-service.spec.js b/tests/unit/edge-gateway-service.spec.js
index db0f734c..60a1df74 100644
--- a/tests/unit/edge-gateway-service.spec.js
+++ b/tests/unit/edge-gateway-service.spec.js
@@ -1,8 +1,4 @@
// @vitest-environment jsdom
-<<<<<<< HEAD
-
-=======
->>>>>>> refs/remotes/origin/master
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
@@ -15,31 +11,22 @@ vi.mock("@/components/session/authenticatedRequest.vue", () => ({
import {
EDGE_GATEWAY_WORKSPACE_CACHE_KEY,
-<<<<<<< HEAD
EDGE_GATEWAY_WORKSPACE_CACHE_TTL_MS,
clearEdgeGatewayWorkspaceCache,
-=======
- clearEdgeGatewayWorkspaceCache,
getEdgeGateway,
->>>>>>> refs/remotes/origin/master
getEdgeGatewayInstallTokenStatus,
listEdgeGateways,
peekCachedEdgeGateway,
peekCachedEdgeGatewayList,
getEdgeGatewayModuleConfig,
- peekCachedEdgeGateway,
setEdgeGatewayModuleConfig,
} from "@/services/edgeGateways.js";
describe("edge gateway service", () => {
beforeEach(() => {
authenticatedRequestMock.mockReset();
-<<<<<<< HEAD
localStorage.clear();
sessionStorage.clear();
-=======
- window.localStorage.clear();
->>>>>>> refs/remotes/origin/master
clearEdgeGatewayWorkspaceCache();
});
@@ -99,9 +86,6 @@ describe("edge gateway service", () => {
expect(authenticatedRequestMock).toHaveBeenCalledWith("/edge-gateways/install-token/9001/status", "GET", {});
});
-<<<<<<< HEAD
- it("uses a stable browser cache namespace for session-scoped workspace snapshots", () => {
-=======
it("scopes workspace snapshots to the active session principal", async () => {
window.localStorage.setItem("token", "user-one-token");
authenticatedRequestMock.mockResolvedValueOnce({
@@ -118,8 +102,7 @@ describe("edge gateway service", () => {
expect(window.localStorage.getItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY)).toBeNull();
});
- it("keeps a stable browser cache namespace for workspace snapshots", () => {
->>>>>>> refs/remotes/origin/master
+ it("uses a stable browser cache namespace for session-scoped workspace snapshots", () => {
const source = readFileSync(join(process.cwd(), "src/services/edgeGateways.js"), "utf8");
expect(EDGE_GATEWAY_WORKSPACE_CACHE_KEY).toBe("truckwash.edgeGatewayWorkspace.cache.v1");
diff --git a/tests/unit/invoicing-period-queue-refresh.behavior.spec.js b/tests/unit/invoicing-period-queue-refresh.behavior.spec.js
index dcba99d9..16b50b6f 100644
--- a/tests/unit/invoicing-period-queue-refresh.behavior.spec.js
+++ b/tests/unit/invoicing-period-queue-refresh.behavior.spec.js
@@ -183,6 +183,7 @@ const selfWashCalls = () => requestMock.mock.calls.filter(([url]) => url === "/m
describe("Invoicing period queue-driven refresh", () => {
beforeEach(() => {
+ window.localStorage.setItem("token", "unit-test-period-cache-token");
requestMock.mockReset();
mockPeriodResponses(emptyPeriodResponse());
routeState.query.activeTab = "period";
@@ -206,6 +207,8 @@ describe("Invoicing period queue-driven refresh", () => {
afterEach(() => {
mountedWrappers.forEach((wrapper) => wrapper.unmount());
mountedWrappers = [];
+ window.sessionStorage.clear();
+ window.localStorage.clear();
});
it("refreshes the current paginated page when queue activity reaches a terminal state", async () => {
diff --git a/tests/unit/release-manager-i18n.spec.js b/tests/unit/release-manager-i18n.spec.js
index 8f7bccbf..31b8f0de 100644
--- a/tests/unit/release-manager-i18n.spec.js
+++ b/tests/unit/release-manager-i18n.spec.js
@@ -105,6 +105,8 @@ const flattenStrings = (value, prefix = "") => {
);
};
+const optionalCatalog = (name, catalog) => (catalog ? [[name, catalog]] : []);
+
const loadReleaseManagerCatalogs = () =>
activeLocales.flatMap((locale) => {
const runtimeV1 = readJsonFile(join(root, `src/i18n/locales/${locale}.json`)).configuration.release_manager;
@@ -118,7 +120,7 @@ const loadReleaseManagerCatalogs = () =>
return [
[`${locale} v1`, runtimeV1],
- [`${locale} source`, source],
+ ...optionalCatalog(`${locale} source`, source),
[`${locale} generated v2`, generatedV2],
[`${locale} runtime v2`, runtimeV2],
];