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], ];