Merge pull request #107 from copenhagentruckwash/investigate-and-fix-failing-tests
Resolve failing frontend CI: fix merge conflicts, restore edge cache & tests
This commit is contained in:
@@ -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(
|
||||
<ButtonsBox class="pos-actions pos-actions--stacked">
|
||||
<Cancel tabindex="2" class="is-fullwidth" />
|
||||
</ButtonsBox>
|
||||
<div
|
||||
v-if="shouldShowActionRailControls"
|
||||
class="pos-shell-actions__rail"
|
||||
data-testid="pos-step-1-action-rail"
|
||||
>
|
||||
<div v-if="shouldShowActionRailControls" class="pos-shell-actions__rail" data-testid="pos-step-1-action-rail">
|
||||
<PosDesktopDuplicateWarning
|
||||
v-if="shouldShowDuplicateWarningInActionRail"
|
||||
:title="t('admin.pos.warning')"
|
||||
|
||||
@@ -117,6 +117,14 @@ const emit = defineEmits<{
|
||||
</b-radio-button>
|
||||
</div>
|
||||
</div>
|
||||
<b-message
|
||||
v-if="!isMachineAvailable(selectedLaneId)"
|
||||
type="is-warning"
|
||||
aria-close-label="Luk besked"
|
||||
data-testid="self-serve-machine-unavailable-guidance"
|
||||
>
|
||||
{{ $t("self_wash.machine_unavailable_for_lane") }}
|
||||
</b-message>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -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),
|
||||
]);
|
||||
|
||||
+73
-120
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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],
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user