From 0b0352f495d0ba2ad4915d3187c3554b1da8f6eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 5 Jul 2026 19:20:58 +0200 Subject: [PATCH] =?utf8?q?refactor:=20convention=20alignment=20=E2=80=94?= =?utf8?q?=20helpers,=20constants,=20imports,=20tests=20(#1950)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Convention alignment refactor across the monorepo — no behavior change. Helpers adoption: - adopt isEmpty() helper for emptiness checks (9 sites); OCPPServiceUtils.ts:1113 preserved with anchor comment (already-trimmed input; isEmpty would redundantly re-trim) - adopt Constants.UNIT_DIVIDER_KILO for kW→W conversion (4 sites) - use JSONStringify for unknown MCP tool payload (Map/Set-safe replacer) Constants promotion: - promote inline literals to named constants (MAX_ITEMS_PER_REPORT_MESSAGE with OCPP 2.0.1 §2.1.16/§2.1.18 spec-anchor comment; AVG_ENTRY_SIZE_BYTES; DEFAULT_EXPONENTIAL_BACKOFF_BASE_DELAY_MS; DEFAULT_AUTH_CACHE_TTL_SECONDS; DEFAULT_PERSIST_STATE) - coverage gap: isNotEmptyArray adoption at ConfigurationValidation.ts:124 Imports discipline: - add .js extension to relative import in ui-web/vitest.config (ESM/NodeNext) - use component barrels instead of deep imports in tests (10 sites) Test literals: - use DEFAULT_HOST/DEFAULT_PORT constants in ui-common tests (72 sites: 32 in config.test.ts + 40 in WebSocketClient.test.ts) Documentation anchors: - document Number.parseInt/parseFloat convention exceptions (3 comments covering 4 call sites where convertToInt/convertToFloat cannot substitute) Quality gates: typecheck clean, lint clean, 2954/2960 tests pass, 0 fail. Diff: +140/-113 across 28 files. --- src/charging-station/ChargingStation.ts | 12 +-- .../CoherentMeterValuesManager.ts | 4 +- src/charging-station/HelpersConfig.ts | 6 +- .../meter-values/CoherentMeterValueBuilder.ts | 4 +- .../meter-values/CoherentSession.ts | 4 +- .../meter-values/EvProfiles.ts | 4 +- .../ocpp/2.0/OCPP20CertificateManager.ts | 2 +- .../ocpp/2.0/OCPP20IncomingRequestService.ts | 14 ++- src/charging-station/ocpp/OCPPServiceUtils.ts | 5 ++ .../ocpp/auth/cache/InMemoryAuthCache.ts | 6 +- .../ocpp/auth/services/OCPPAuthServiceImpl.ts | 2 +- src/charging-station/ui-server/UIMCPServer.ts | 3 +- src/charging-station/ui-server/UIServerNet.ts | 2 + src/utils/Configuration.ts | 6 +- src/utils/ConfigurationValidation.ts | 4 +- src/utils/Constants.ts | 2 + .../helpers/TemplateFixtures.ts | 2 +- .../2.0/OCPP20CertSigningRetryManager.test.ts | 2 +- ...comingRequestService-GetBaseReport.test.ts | 2 +- ...CPP20ServiceUtils-TransactionEvent.test.ts | 5 +- .../ocpp/2.0/OCPP20VariableManager.test.ts | 2 +- .../ui-server/UIMCPServer.integration.test.ts | 2 +- .../ui-server/UIMCPServer.test.ts | 2 +- .../ui-server/UIWebSocketServer.test.ts | 2 +- .../ui-services/AbstractUIService.test.ts | 2 +- ui/common/tests/WebSocketClient.test.ts | 87 +++++++++++-------- ui/common/tests/config.test.ts | 63 +++++++------- ui/web/vitest.config.ts | 2 +- 28 files changed, 140 insertions(+), 113 deletions(-) diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 774fc870..b974aed4 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -1606,7 +1606,7 @@ export class ChargingStation extends EventEmitter { } return this.stationInfo?.reconnectExponentialDelay === true ? computeExponentialBackOffDelay({ - baseDelayMs: 100, + baseDelayMs: Constants.DEFAULT_EXPONENTIAL_BACKOFF_BASE_DELAY_MS, jitterPercent: 0.2, retryNumber: this.wsConnectionRetryCount, }) @@ -1683,12 +1683,12 @@ export class ChargingStation extends EventEmitter { const powerArrayRandomIndex = Math.floor(secureRandom() * stationTemplate.power.length) stationInfo.maximumPower = stationTemplate.powerUnit === PowerUnits.KILO_WATT - ? stationTemplate.power[powerArrayRandomIndex] * 1000 + ? stationTemplate.power[powerArrayRandomIndex] * Constants.UNIT_DIVIDER_KILO : stationTemplate.power[powerArrayRandomIndex] } else if (typeof stationTemplate.power === 'number') { stationInfo.maximumPower = stationTemplate.powerUnit === PowerUnits.KILO_WATT - ? stationTemplate.power * 1000 + ? stationTemplate.power * Constants.UNIT_DIVIDER_KILO : stationTemplate.power } stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo) @@ -1954,7 +1954,7 @@ export class ChargingStation extends EventEmitter { 'hex' ) const connectorsConfigChanged = - this.connectors.size !== 0 && this.connectorsConfigurationHash !== connectorsConfigHash + !isEmpty(this.connectors) && this.connectorsConfigurationHash !== connectorsConfigHash if (isEmpty(this.connectors) || connectorsConfigChanged) { connectorsConfigChanged && this.connectors.clear() this.connectorsConfigurationHash = connectorsConfigHash @@ -2118,7 +2118,7 @@ export class ChargingStation extends EventEmitter { 'hex' ) const evsesConfigChanged = - this.evses.size !== 0 && this.evsesConfigurationHash !== evsesConfigHash + !isEmpty(this.evses) && this.evsesConfigurationHash !== evsesConfigHash if (isEmpty(this.evses) || evsesConfigChanged) { evsesConfigChanged && this.evses.clear() this.evsesConfigurationHash = evsesConfigHash @@ -2786,7 +2786,7 @@ export class ChargingStation extends EventEmitter { // eslint-disable-next-line promise/no-promise-in-callback sleep( computeExponentialBackOffDelay({ - baseDelayMs: 100, + baseDelayMs: Constants.DEFAULT_EXPONENTIAL_BACKOFF_BASE_DELAY_MS, jitterPercent: 0.2, retryNumber: messageIdx ?? 0, }) diff --git a/src/charging-station/CoherentMeterValuesManager.ts b/src/charging-station/CoherentMeterValuesManager.ts index 5986a023..5cdcd8ec 100644 --- a/src/charging-station/CoherentMeterValuesManager.ts +++ b/src/charging-station/CoherentMeterValuesManager.ts @@ -13,7 +13,7 @@ import type { ChargingStation } from './ChargingStation.js' import { BaseError } from '../exception/index.js' -import { logger } from '../utils/index.js' +import { isEmpty, logger } from '../utils/index.js' import { getEvProfilesFile } from './Helpers.js' import { disposeCoherentSessionRuntime } from './meter-values/CoherentSampleComputer.js' import { @@ -154,7 +154,7 @@ export class CoherentMeterValuesManager { if (this.chargingStation.stationInfo?.coherentMeterValues !== true) { return undefined } - if (this.evProfiles == null || this.evProfiles.profiles.length === 0) { + if (this.evProfiles == null || isEmpty(this.evProfiles.profiles)) { return undefined } const session = createCoherentSession(this.chargingStation, { diff --git a/src/charging-station/HelpersConfig.ts b/src/charging-station/HelpersConfig.ts index 409422a2..12a4d13b 100644 --- a/src/charging-station/HelpersConfig.ts +++ b/src/charging-station/HelpersConfig.ts @@ -36,7 +36,7 @@ import { PowerUnits, Voltage, } from '../types/index.js' -import { clone, isEmpty, isNotEmptyArray, logger, secureRandom } from '../utils/index.js' +import { clone, Constants, isEmpty, isNotEmptyArray, logger, secureRandom } from '../utils/index.js' const moduleName = 'HelpersConfig' @@ -170,12 +170,12 @@ export const getDefaultConnectorMaximumPower = ( const powerArrayRandomIndex = Math.floor(secureRandom() * stationTemplate.power.length) maximumPower = stationTemplate.powerUnit === PowerUnits.KILO_WATT - ? stationTemplate.power[powerArrayRandomIndex] * 1000 + ? stationTemplate.power[powerArrayRandomIndex] * Constants.UNIT_DIVIDER_KILO : stationTemplate.power[powerArrayRandomIndex] } else if (typeof stationTemplate.power === 'number') { maximumPower = stationTemplate.powerUnit === PowerUnits.KILO_WATT - ? stationTemplate.power * 1000 + ? stationTemplate.power * Constants.UNIT_DIVIDER_KILO : stationTemplate.power } if (maximumPower == null) { diff --git a/src/charging-station/meter-values/CoherentMeterValueBuilder.ts b/src/charging-station/meter-values/CoherentMeterValueBuilder.ts index 2a0a7c42..7f705229 100644 --- a/src/charging-station/meter-values/CoherentMeterValueBuilder.ts +++ b/src/charging-station/meter-values/CoherentMeterValueBuilder.ts @@ -35,7 +35,7 @@ import { MeterValuePhase, MeterValueUnit, } from '../../types/index.js' -import { Constants, isNotEmptyArray, logger, roundTo } from '../../utils/index.js' +import { Constants, isEmpty, isNotEmptyArray, logger, roundTo } from '../../utils/index.js' import { advanceEnergyRegister, computeCoherentSample, @@ -171,7 +171,7 @@ const applyRegisterValuesWithoutPhases = ( const surviving: SampledValueTemplate[] = [] for (const family of Map.groupBy(bucket, templateFamilyKey).values()) { const perPhaseLN = family.filter(isLineToNeutralTemplate) - if (perPhaseLN.length === 0) { + if (isEmpty(perPhaseLN)) { surviving.push(...family) continue } diff --git a/src/charging-station/meter-values/CoherentSession.ts b/src/charging-station/meter-values/CoherentSession.ts index 1f3be68b..e8a77dc0 100644 --- a/src/charging-station/meter-values/CoherentSession.ts +++ b/src/charging-station/meter-values/CoherentSession.ts @@ -19,7 +19,7 @@ import type { CoherentSession, EvProfile, ICoherentContext } from './types.js' import { CurrentType, Voltage } from '../../types/index.js' -import { Constants, logger } from '../../utils/index.js' +import { Constants, isEmpty, logger } from '../../utils/index.js' import { selectEvProfile } from './EvProfiles.js' import { createStreamPrng, hashLabel } from './PRNG.js' @@ -83,7 +83,7 @@ export const createCoherentSession = ( context: ICoherentContext, options: CreateSessionOptions ): CoherentSession | undefined => { - if (options.profiles.length === 0) { + if (isEmpty(options.profiles)) { return undefined } const now = options.now ?? Date.now() diff --git a/src/charging-station/meter-values/EvProfiles.ts b/src/charging-station/meter-values/EvProfiles.ts index 33325baa..a7e4135d 100644 --- a/src/charging-station/meter-values/EvProfiles.ts +++ b/src/charging-station/meter-values/EvProfiles.ts @@ -12,7 +12,7 @@ import { readFileSync } from 'node:fs' import { z } from 'zod' import { BaseError } from '../../exception/index.js' -import { getErrorMessage, logger } from '../../utils/index.js' +import { getErrorMessage, isEmpty, logger } from '../../utils/index.js' import { type EvProfile, type EvProfilesFile, EvProfilesFileSchema } from './types.js' const moduleName = 'EvProfiles' @@ -106,7 +106,7 @@ export const interpolateChargingCurve = ( curve: { powerFraction: number; socPercent: number }[], socPercent: number ): number => { - if (curve.length === 0) { + if (isEmpty(curve)) { return 1 } if (process.env.NODE_ENV !== 'production') { diff --git a/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts b/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts index 72702640..ac66e213 100644 --- a/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts +++ b/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts @@ -474,7 +474,7 @@ export class OCPP20CertificateManager { const pemCertificates = pem.match( /-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g ) - if (pemCertificates == null || pemCertificates.length === 0) { + if (pemCertificates == null || isEmpty(pemCertificates)) { return { reason: 'No PEM certificate found', valid: false } } diff --git a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts index 3298f9c4..c49e8602 100644 --- a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts @@ -191,6 +191,13 @@ import { getVariableMetadata, VARIABLE_REGISTRY } from './OCPP20VariableRegistry const moduleName = 'OCPP20IncomingRequestService' +// GetBaseReport response chunking: conservative project default. +// The actual per-device limits are reported at runtime by the Charging Station via +// OCPP 2.0.1 §2.1.16 DeviceDataCtrlr.ItemsPerMessage(instance:GetReport) and +// §2.1.18 DeviceDataCtrlr.BytesPerMessage(instance:GetReport); both are ReadOnly +// device capability declarations with no spec-defined ceiling. +const MAX_ITEMS_PER_REPORT_MESSAGE = 100 as const + interface StationInfoReportField { property: 'chargePointModel' | 'chargePointSerialNumber' | 'chargePointVendor' | 'firmwareVersion' variable: OCPP20DeviceInfoVariableName @@ -1340,7 +1347,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { meterValues.push(meterValue) } } - if (meterValues.length === 0) { + if (isEmpty(meterValues)) { meterValues.push({ sampledValue: [ { @@ -3512,10 +3519,9 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { const cached = stationState.reportDataCache.get(requestId) const reportData = cached ?? this.buildReportData(chargingStation, reportBase) - const maxItemsPerMessage = 100 const chunks = [] - for (let i = 0; i < reportData.length; i += maxItemsPerMessage) { - chunks.push(reportData.slice(i, i + maxItemsPerMessage)) + for (let i = 0; i < reportData.length; i += MAX_ITEMS_PER_REPORT_MESSAGE) { + chunks.push(reportData.slice(i, i + MAX_ITEMS_PER_REPORT_MESSAGE)) } if (!isNotEmptyArray(chunks)) { diff --git a/src/charging-station/ocpp/OCPPServiceUtils.ts b/src/charging-station/ocpp/OCPPServiceUtils.ts index 4e88b242..fc37e9b5 100644 --- a/src/charging-station/ocpp/OCPPServiceUtils.ts +++ b/src/charging-station/ocpp/OCPPServiceUtils.ts @@ -1110,6 +1110,9 @@ const resolveEnabledMeasurands = ( const enabled = new Set() for (const entry of rawValue.split(',')) { const trimmed = entry.trim() + // Kept as `.length === 0`: entry is already trimmed above; `isEmpty()` here would be + // semantically identical (its string branch is `value.trim().length === 0`) — direct + // check avoids a redundant re-trim. if (trimmed.length === 0) { continue } @@ -1486,6 +1489,8 @@ const getLimitFromSampledValueTemplateCustomValue = ( }, ...options, } + // Number.parseFloat preserved: NaN sentinel drives the POSITIVE_INFINITY fallback below; + // convertToFloat throws on NaN and would break the fallback branch. const parsedValue = Number.parseFloat(value ?? '') if (options.limitationEnabled) { return max( diff --git a/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts b/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts index ca4a5c5b..692e2f9a 100644 --- a/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts +++ b/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts @@ -8,6 +8,9 @@ import { AuthorizationStatus } from '../types/AuthTypes.js' const moduleName = 'InMemoryAuthCache' +// Rough heap-footprint estimate per cached entry — not measured; used only for stats display. +const AVG_ENTRY_SIZE_BYTES = 500 as const + /** * Cached authorization entry with expiration */ @@ -236,8 +239,7 @@ export class InMemoryAuthCache implements AuthCache { const hitRate = totalAccess > 0 ? (this.stats.hits / totalAccess) * 100 : 0 // Calculate memory usage estimate - const avgEntrySize = 500 // Rough estimate: 500 bytes per entry - const memoryUsage = this.cache.size * avgEntrySize + const memoryUsage = this.cache.size * AVG_ENTRY_SIZE_BYTES // Clean expired rate limit entries this.cleanupExpiredRateLimits() diff --git a/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts b/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts index 9c2739b7..a9b3d488 100644 --- a/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts +++ b/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts @@ -599,7 +599,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService { allowOfflineTxForUnknownId: false, authKeyManagementEnabled: false, authorizationCacheEnabled: true, - authorizationCacheLifetime: 3600, + authorizationCacheLifetime: Constants.DEFAULT_AUTH_CACHE_TTL_SECONDS, authorizationTimeout: 30, certificateAuthEnabled: this.chargingStation.stationInfo?.ocppVersion !== OCPPVersion.VERSION_16, diff --git a/src/charging-station/ui-server/UIMCPServer.ts b/src/charging-station/ui-server/UIMCPServer.ts index 2ac68868..3c3d667c 100644 --- a/src/charging-station/ui-server/UIMCPServer.ts +++ b/src/charging-station/ui-server/UIMCPServer.ts @@ -28,6 +28,7 @@ import { getErrorMessage, isEmpty, isNotEmptyArray, + JSONStringify, logger, } from '../../utils/index.js' import { AbstractUIServer } from './AbstractUIServer.js' @@ -82,7 +83,7 @@ export class UIMCPServer extends AbstractUIServer { } private static createToolResponse (payload: unknown): CallToolResult { - return { content: [{ text: JSON.stringify(payload), type: 'text' as const }] } + return { content: [{ text: JSONStringify(payload), type: 'text' as const }] } } public override hasResponseHandler (uuid: UUIDv4): boolean { diff --git a/src/charging-station/ui-server/UIServerNet.ts b/src/charging-station/ui-server/UIServerNet.ts index 9d4c403c..d493c014 100644 --- a/src/charging-station/ui-server/UIServerNet.ts +++ b/src/charging-station/ui-server/UIServerNet.ts @@ -152,6 +152,7 @@ const parseIPv4MappedAddress = (address: string): string | undefined => { if (hexMatch == null) { return undefined } + // radix-16 required for IPv4-mapped IPv6 hex octet parsing; convertToInt does not accept a radix const high = Number.parseInt(hexMatch[1], 16) const low = Number.parseInt(hexMatch[2], 16) return [high >> 8, high & 0xff, low >> 8, low & 0xff].join('.') @@ -172,6 +173,7 @@ const expandIPv6 = (address: string): string[] | undefined => { if (groups.length !== 8) { return undefined } + // radix-16 required for IPv6 hex group normalization; convertToInt does not accept a radix return groups.every(isIPv6Group) ? groups.map(group => Number.parseInt(group, 16).toString(16)) : undefined diff --git a/src/utils/Configuration.ts b/src/utils/Configuration.ts index 1daa6ac7..c242c9ec 100644 --- a/src/utils/Configuration.ts +++ b/src/utils/Configuration.ts @@ -90,9 +90,7 @@ const defaultWorkerConfiguration: WorkerConfiguration = { startDelay: DEFAULT_WORKER_START_DELAY_MS, } -const defaultPersistState = true - -export const DEFAULT_PERSIST_STATE = defaultPersistState +export const DEFAULT_PERSIST_STATE = true as const // eslint-disable-next-line @typescript-eslint/no-extraneous-class export class Configuration { @@ -195,7 +193,7 @@ export class Configuration { } public static getPersistState (): boolean { - return Configuration.getConfigurationData()?.persistState ?? defaultPersistState + return Configuration.getConfigurationData()?.persistState ?? DEFAULT_PERSIST_STATE } public static getStationTemplateUrls (): StationTemplateUrl[] | undefined { diff --git a/src/utils/ConfigurationValidation.ts b/src/utils/ConfigurationValidation.ts index a58ab40c..9cd36e78 100644 --- a/src/utils/ConfigurationValidation.ts +++ b/src/utils/ConfigurationValidation.ts @@ -14,7 +14,7 @@ import { } from './ConfigurationMigrations.js' import { ConfigurationSchema } from './ConfigurationSchema.js' import { configurationLogPrefix } from './ConfigurationUtils.js' -import { assertIsJsonObject, clone, isEmpty } from './Utils.js' +import { assertIsJsonObject, clone, isEmpty, isNotEmptyArray } from './Utils.js' const moduleName = 'ConfigurationValidation' @@ -121,7 +121,7 @@ export const validateConfiguration = (parsed: unknown, filePath: string): Config )}` ) } - if (remapErrors.length > 0) { + if (isNotEmptyArray(remapErrors)) { throw new ConfigurationValidationError(remapErrors, { filePath, migratedFrom, diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index b6a62242..5cd04899 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -44,6 +44,8 @@ export class Constants { static readonly DEFAULT_EV_CONNECTION_TIMEOUT_SECONDS = 180 + static readonly DEFAULT_EXPONENTIAL_BACKOFF_BASE_DELAY_MS = 100 + static readonly DEFAULT_FLUCTUATION_PERCENT = 5 static readonly DEFAULT_HASH_ALGORITHM = 'sha384' diff --git a/tests/charging-station/helpers/TemplateFixtures.ts b/tests/charging-station/helpers/TemplateFixtures.ts index 575d331e..45dc3f59 100644 --- a/tests/charging-station/helpers/TemplateFixtures.ts +++ b/tests/charging-station/helpers/TemplateFixtures.ts @@ -2,7 +2,7 @@ * @file Shared template fixtures for schema/migration/validation tests. */ -import { CURRENT_SCHEMA_VERSION } from '../../../src/charging-station/TemplateMigrations.js' +import { CURRENT_SCHEMA_VERSION } from '../../../src/charging-station/index.js' import { TEST_CHARGE_POINT_MODEL, TEST_CHARGE_POINT_VENDOR, diff --git a/tests/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.test.ts b/tests/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.test.ts index 9884d90a..6861983b 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.test.ts @@ -8,7 +8,7 @@ import { afterEach, beforeEach, describe, it, mock } from 'node:test' import type { ChargingStation } from '../../../../src/charging-station/index.js' -import { buildConfigKey } from '../../../../src/charging-station/ConfigurationKeyUtils.js' +import { buildConfigKey } from '../../../../src/charging-station/index.js' import { OCPP20CertSigningRetryManager } from '../../../../src/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.js' import { OCPP20VariableManager } from '../../../../src/charging-station/ocpp/2.0/OCPP20VariableManager.js' import { diff --git a/tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-GetBaseReport.test.ts b/tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-GetBaseReport.test.ts index f8f1054c..d713c48a 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-GetBaseReport.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-GetBaseReport.test.ts @@ -12,7 +12,7 @@ import { addConfigurationKey, buildConfigKey, setConfigurationKeyValue, -} from '../../../../src/charging-station/ConfigurationKeyUtils.js' +} from '../../../../src/charging-station/index.js' import { createTestableIncomingRequestService } from '../../../../src/charging-station/ocpp/2.0/__testable__/index.js' import { OCPP20IncomingRequestService } from '../../../../src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.js' import { OCPP20VariableManager } from '../../../../src/charging-station/ocpp/2.0/OCPP20VariableManager.js' diff --git a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts index 297a27fe..9eed14c4 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts @@ -14,10 +14,9 @@ import assert from 'node:assert/strict' import { afterEach, beforeEach, describe, it, mock } from 'node:test' import type { ChargingStation } from '../../../../src/charging-station/index.js' -import type { ConnectorStatus } from '../../../../src/types/ConnectorStatus.js' -import type { EmptyObject } from '../../../../src/types/index.js' +import type { ConnectorStatus, EmptyObject } from '../../../../src/types/index.js' -import { addConfigurationKey } from '../../../../src/charging-station/ConfigurationKeyUtils.js' +import { addConfigurationKey } from '../../../../src/charging-station/index.js' import { buildTransactionEvent, OCPP20ServiceUtils, diff --git a/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts b/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts index 58785921..59ee7b52 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts @@ -13,7 +13,7 @@ import { buildConfigKey, deleteConfigurationKey, getConfigurationKey, -} from '../../../../src/charging-station/ConfigurationKeyUtils.js' +} from '../../../../src/charging-station/index.js' import { createTestableVariableManager } from '../../../../src/charging-station/ocpp/2.0/__testable__/index.js' import { OCPP20VariableManager } from '../../../../src/charging-station/ocpp/2.0/OCPP20VariableManager.js' import { VARIABLE_REGISTRY } from '../../../../src/charging-station/ocpp/2.0/OCPP20VariableRegistry.js' diff --git a/tests/charging-station/ui-server/UIMCPServer.integration.test.ts b/tests/charging-station/ui-server/UIMCPServer.integration.test.ts index 881dec9c..7741526d 100644 --- a/tests/charging-station/ui-server/UIMCPServer.integration.test.ts +++ b/tests/charging-station/ui-server/UIMCPServer.integration.test.ts @@ -15,7 +15,7 @@ import { afterEach, beforeEach, describe, it } from 'node:test' import { UIMCPServer } from '../../../src/charging-station/ui-server/UIMCPServer.js' import { HttpMethod } from '../../../src/charging-station/ui-server/UIServerUtils.js' import { ApplicationProtocol, ConfigurationSection } from '../../../src/types/index.js' -import { Configuration } from '../../../src/utils/Configuration.js' +import { Configuration } from '../../../src/utils/index.js' import { standardCleanup } from '../../helpers/TestLifecycleHelpers.js' import { createMockBootstrap, createMockUIServerConfiguration } from './UIServerTestUtils.js' diff --git a/tests/charging-station/ui-server/UIMCPServer.test.ts b/tests/charging-station/ui-server/UIMCPServer.test.ts index bc3adb8c..bc5493fa 100644 --- a/tests/charging-station/ui-server/UIMCPServer.test.ts +++ b/tests/charging-station/ui-server/UIMCPServer.test.ts @@ -38,7 +38,7 @@ import { ProcedureName, ResponseStatus, } from '../../../src/types/index.js' -import { logger } from '../../../src/utils/Logger.js' +import { logger } from '../../../src/utils/index.js' import { createLoggerMocks, standardCleanup, diff --git a/tests/charging-station/ui-server/UIWebSocketServer.test.ts b/tests/charging-station/ui-server/UIWebSocketServer.test.ts index bdb27fca..ae9b7c36 100644 --- a/tests/charging-station/ui-server/UIWebSocketServer.test.ts +++ b/tests/charging-station/ui-server/UIWebSocketServer.test.ts @@ -25,7 +25,7 @@ import { ProcedureName, ResponseStatus, } from '../../../src/types/index.js' -import { logger } from '../../../src/utils/Logger.js' +import { logger } from '../../../src/utils/index.js' import { createLoggerMocks, standardCleanup } from '../../helpers/TestLifecycleHelpers.js' import { TEST_UUID } from './UIServerTestConstants.js' import { diff --git a/tests/charging-station/ui-server/ui-services/AbstractUIService.test.ts b/tests/charging-station/ui-server/ui-services/AbstractUIService.test.ts index 0fd3a017..a1f99660 100644 --- a/tests/charging-station/ui-server/ui-services/AbstractUIService.test.ts +++ b/tests/charging-station/ui-server/ui-services/AbstractUIService.test.ts @@ -16,7 +16,7 @@ import { ResponseStatus, UIRequestOrigin, } from '../../../../src/types/index.js' -import { logger } from '../../../../src/utils/Logger.js' +import { logger } from '../../../../src/utils/index.js' import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js' import { TEST_HASH_ID, TEST_UUID } from '../UIServerTestConstants.js' import { diff --git a/ui/common/tests/WebSocketClient.test.ts b/ui/common/tests/WebSocketClient.test.ts index e9d9bc04..12c63bbf 100644 --- a/ui/common/tests/WebSocketClient.test.ts +++ b/ui/common/tests/WebSocketClient.test.ts @@ -7,6 +7,7 @@ import type { WebSocketFactory } from '../src/client/types.js' import type { ResponsePayload } from '../src/types/UIProtocol.js' import { ServerFailureError, WebSocketClient } from '../src/client/WebSocketClient.js' +import { DEFAULT_HOST, DEFAULT_PORT } from '../src/constants.js' import { AuthenticationType, ProcedureName, @@ -21,8 +22,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -45,8 +46,8 @@ await describe('WebSocketClient', async () => { type: AuthenticationType.PROTOCOL_BASIC_AUTH, username: 'admin', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -62,8 +63,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -90,8 +91,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -120,8 +121,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -164,8 +165,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -183,8 +184,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -203,8 +204,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -245,8 +246,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -264,8 +265,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -286,8 +287,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -306,8 +307,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -340,8 +341,8 @@ await describe('WebSocketClient', async () => { const client = new WebSocketClient( () => mockWs, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }, @@ -369,8 +370,8 @@ await describe('WebSocketClient', async () => { const client = new WebSocketClient( () => mockWs, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }, @@ -397,8 +398,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -421,8 +422,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -445,8 +446,8 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient(factory, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) @@ -469,7 +470,12 @@ await describe('WebSocketClient', async () => { const mockWs = createMockWebSocketLike() const client = new WebSocketClient( () => mockWs, - { host: 'localhost', port: 8080, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'] }, + { + host: DEFAULT_HOST, + port: DEFAULT_PORT, + protocol: Protocol.UI, + version: ProtocolVersion['0.0.1'], + }, undefined, notification => { notifications.push(notification) @@ -492,7 +498,12 @@ await describe('WebSocketClient', async () => { const factory: WebSocketFactory = () => mockWs const client = new WebSocketClient( factory, - { host: 'localhost', port: 8080, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'] }, + { + host: DEFAULT_HOST, + port: DEFAULT_PORT, + protocol: Protocol.UI, + version: ProtocolVersion['0.0.1'], + }, undefined, notification => { notifications.push(notification) @@ -514,8 +525,8 @@ await describe('WebSocketClient', async () => { await it('should NOT fire onNotification when callback is undefined', async () => { const mockWs = createMockWebSocketLike() const client = new WebSocketClient(() => mockWs, { - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: Protocol.UI, version: ProtocolVersion['0.0.1'], }) diff --git a/ui/common/tests/config.test.ts b/ui/common/tests/config.test.ts index 32d0b681..3cc51287 100644 --- a/ui/common/tests/config.test.ts +++ b/ui/common/tests/config.test.ts @@ -2,12 +2,13 @@ import assert from 'node:assert' import { describe, it } from 'node:test' import { configurationSchema, uiServerConfigSchema } from '../src/config/schema.js' +import { DEFAULT_HOST, DEFAULT_PORT } from '../src/constants.js' await describe('config schema validation', async () => { await it('should validate a minimal valid config', () => { const result = uiServerConfigSchema.safeParse({ - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -16,8 +17,8 @@ await describe('config schema validation', async () => { await it('should reject config with empty protocol', () => { const result = uiServerConfigSchema.safeParse({ - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: '', version: '0.0.1', }) @@ -26,8 +27,8 @@ await describe('config schema validation', async () => { await it('should reject config with protocol not in Protocol enum', () => { const result = uiServerConfigSchema.safeParse({ - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ws', version: '0.0.1', }) @@ -36,8 +37,8 @@ await describe('config schema validation', async () => { await it('should reject config with version not in ProtocolVersion enum', () => { const result = uiServerConfigSchema.safeParse({ - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '2.0', }) @@ -46,7 +47,7 @@ await describe('config schema validation', async () => { await it('should reject missing required host field', () => { const result = uiServerConfigSchema.safeParse({ - port: 8080, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -55,7 +56,7 @@ await describe('config schema validation', async () => { await it('should reject invalid port number', () => { const result = uiServerConfigSchema.safeParse({ - host: 'localhost', + host: DEFAULT_HOST, port: 99999, }) assert.strictEqual(result.success, false) @@ -64,7 +65,7 @@ await describe('config schema validation', async () => { await it('should reject empty host string', () => { const result = uiServerConfigSchema.safeParse({ host: '', - port: 8080, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -81,7 +82,7 @@ await describe('config schema validation', async () => { }, host: 'simulator.example.com', name: 'My Simulator', - port: 8080, + port: DEFAULT_PORT, protocol: 'ui', secure: true, version: '0.0.1', @@ -92,8 +93,8 @@ await describe('config schema validation', async () => { await it('should validate configuration with array of servers', () => { const result = configurationSchema.safeParse({ uiServer: [ - { host: 'server1.example.com', port: 8080, protocol: 'ui', version: '0.0.1' }, - { host: 'server2.example.com', port: 8080, protocol: 'ui', version: '0.0.1' }, + { host: 'server1.example.com', port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1' }, + { host: 'server2.example.com', port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1' }, ], }) assert.strictEqual(result.success, true) @@ -101,7 +102,7 @@ await describe('config schema validation', async () => { await it('should validate configuration with single server', () => { const result = configurationSchema.safeParse({ - uiServer: { host: 'localhost', port: 8080, protocol: 'ui', version: '0.0.1' }, + uiServer: { host: DEFAULT_HOST, port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1' }, }) assert.strictEqual(result.success, true) }) @@ -112,8 +113,8 @@ await describe('config schema validation', async () => { enabled: true, type: 'protocol-basic-auth', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -137,8 +138,8 @@ await describe('config schema validation', async () => { type: 'protocol-basic-auth', username: '', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -158,8 +159,8 @@ await describe('config schema validation', async () => { type: 'protocol-basic-auth', username: 'admin', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -179,8 +180,8 @@ await describe('config schema validation', async () => { type: 'protocol-basic-auth', username: 'a:b', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -202,8 +203,8 @@ await describe('config schema validation', async () => { password: 'admin', type: 'protocol-basic-auth', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -222,8 +223,8 @@ await describe('config schema validation', async () => { type: 'protocol-basic-auth', username: 'admin', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -243,8 +244,8 @@ await describe('config schema validation', async () => { type: 'protocol-basic-auth', username: 'admin', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) @@ -257,8 +258,8 @@ await describe('config schema validation', async () => { enabled: false, type: 'protocol-basic-auth', }, - host: 'localhost', - port: 8080, + host: DEFAULT_HOST, + port: DEFAULT_PORT, protocol: 'ui', version: '0.0.1', }) diff --git a/ui/web/vitest.config.ts b/ui/web/vitest.config.ts index e4e241fe..f5390505 100644 --- a/ui/web/vitest.config.ts +++ b/ui/web/vitest.config.ts @@ -2,7 +2,7 @@ import { fileURLToPath } from 'node:url' import { mergeConfig } from 'vite' import { configDefaults, defineConfig } from 'vitest/config' -import viteConfig from './vite.config' +import viteConfig from './vite.config.js' const nodeMajor = Number.parseInt(process.versions.node.split('.')[0], 10) -- 2.53.0