From 4d6442e0e5f487b8cda73345f6ecc1189914144a Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sat, 28 Feb 2026 22:39:32 +0100 Subject: [PATCH] refactor(tests): cleanup unused exports and consolidate testable classes - Remove unused exports from UIServerTestUtils - Remove unused ping()/pong() from MockWebSocket - Remove waitForCondition from StationHelpers - Consolidate TestableUIWebSocketServer into UIServerTestUtils - Remove createMockOCPP20TransactionTestStation wrapper - Add _brand to MockSharedLRUCache to fix static-only class lint --- .../ChargingStationTestUtils.ts | 1 - .../helpers/StationHelpers.ts | 20 ----- tests/charging-station/mocks/MockCaches.ts | 68 ++--------------- tests/charging-station/mocks/MockWebSocket.ts | 14 ---- ...CPP20ServiceUtils-TransactionEvent.test.ts | 21 +++-- .../ocpp/2.0/OCPP20TestUtils.ts | 23 ------ .../ui-server/UIServerTestUtils.ts | 76 ++++++++++++------- .../ui-server/UIWebSocketServer.test.ts | 21 +---- .../ui-services/AbstractUIService.test.ts | 12 +-- 9 files changed, 72 insertions(+), 184 deletions(-) diff --git a/tests/charging-station/ChargingStationTestUtils.ts b/tests/charging-station/ChargingStationTestUtils.ts index 4d27ced1..bfff81ae 100644 --- a/tests/charging-station/ChargingStationTestUtils.ts +++ b/tests/charging-station/ChargingStationTestUtils.ts @@ -35,7 +35,6 @@ export { createMockChargingStation, createMockChargingStationTemplate, resetChargingStationState, - waitForCondition, } from './helpers/StationHelpers.js' export { MockIdTagsCache, MockSharedLRUCache } from './mocks/MockCaches.js' diff --git a/tests/charging-station/helpers/StationHelpers.ts b/tests/charging-station/helpers/StationHelpers.ts index e0f047b8..065439c3 100644 --- a/tests/charging-station/helpers/StationHelpers.ts +++ b/tests/charging-station/helpers/StationHelpers.ts @@ -918,26 +918,6 @@ export function resetChargingStationState (station: ChargingStation): void { } } -/** - * Wait for a condition to be true with timeout - * @param condition - Function that returns true when condition is met - * @param timeout - Maximum time to wait in milliseconds - * @param interval - Check interval in milliseconds - */ -export async function waitForCondition ( - condition: () => boolean, - timeout = 1000, - interval = 10 -): Promise { - const startTime = Date.now() - while (!condition()) { - if (Date.now() - startTime > timeout) { - throw new Error('Timeout waiting for condition') - } - await new Promise(resolve => setTimeout(resolve, interval)) - } -} - /** * Determines whether EVSEs should be used based on configuration * @param options - Configuration options to check diff --git a/tests/charging-station/mocks/MockCaches.ts b/tests/charging-station/mocks/MockCaches.ts index b21ed2ac..19bf0f6f 100644 --- a/tests/charging-station/mocks/MockCaches.ts +++ b/tests/charging-station/mocks/MockCaches.ts @@ -1,18 +1,14 @@ /** * Mock cache implementations for testing * - * Provides in-memory caching without requiring Bootstrap initialization. + * Provides minimal singleton mock caches for test isolation. + * These mocks implement only getInstance/resetInstance for singleton management. */ -import type { - ChargingStationConfiguration, - ChargingStationTemplate, -} from '../../../src/types/index.js' - /** * Mock IdTagsCache for testing * - * Provides mock RFID tag management without file system access. + * Minimal singleton mock for RFID tag cache. */ export class MockIdTagsCache { private static instance: MockIdTagsCache | null = null @@ -27,18 +23,6 @@ export class MockIdTagsCache { MockIdTagsCache.instance = null } - public clear (): void { - this.idTagsMap.clear() - } - - public deleteIdTags (file: string): boolean { - return this.idTagsMap.delete(file) - } - - public getIdTag (): string { - return 'TEST-TAG-001' - } - public getIdTags (file: string): string[] | undefined { return this.idTagsMap.get(file) } @@ -51,12 +35,11 @@ export class MockIdTagsCache { /** * Mock SharedLRUCache for testing * - * Provides in-memory caching without requiring Bootstrap initialization. + * Minimal singleton mock for shared LRU cache. */ export class MockSharedLRUCache { private static instance: MockSharedLRUCache | null = null - private readonly configurations = new Map() - private readonly templates = new Map() + private readonly _brand = 'MockSharedLRUCache' as const public static getInstance (): MockSharedLRUCache { MockSharedLRUCache.instance ??= new MockSharedLRUCache() @@ -66,45 +49,4 @@ export class MockSharedLRUCache { public static resetInstance (): void { MockSharedLRUCache.instance = null } - - public clear (): void { - this.templates.clear() - this.configurations.clear() - } - - public deleteChargingStationConfiguration (hash: string): void { - this.configurations.delete(hash) - } - - public deleteChargingStationTemplate (hash: string): void { - this.templates.delete(hash) - } - - public getChargingStationConfiguration (hash: string): ChargingStationConfiguration | undefined { - return this.configurations.get(hash) - } - - public getChargingStationTemplate (hash: string): ChargingStationTemplate | undefined { - return this.templates.get(hash) - } - - public hasChargingStationConfiguration (hash: string): boolean { - return this.configurations.has(hash) - } - - public hasChargingStationTemplate (hash: string): boolean { - return this.templates.has(hash) - } - - public setChargingStationConfiguration (config: ChargingStationConfiguration): void { - if (config.configurationHash != null) { - this.configurations.set(config.configurationHash, config) - } - } - - public setChargingStationTemplate (template: ChargingStationTemplate): void { - if (template.templateHash != null) { - this.templates.set(template.templateHash, template) - } - } } diff --git a/tests/charging-station/mocks/MockWebSocket.ts b/tests/charging-station/mocks/MockWebSocket.ts index 04e75bc7..2420023b 100644 --- a/tests/charging-station/mocks/MockWebSocket.ts +++ b/tests/charging-station/mocks/MockWebSocket.ts @@ -98,20 +98,6 @@ export class MockWebSocket extends EventEmitter { return this.sentMessages.map(msg => JSON.parse(msg) as unknown) } - /** - * Ping the server (no-op in mock) - */ - public ping (): void { - // No-op for tests - } - - /** - * Pong response (no-op in mock) - */ - public pong (): void { - // No-op for tests - } - /** * Send a message through the WebSocket * @param data - Message to send 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 fa3fa3f6..58c7acda 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts @@ -36,14 +36,12 @@ import { TEST_CHARGING_STATION_BASE_NAME } from '../../ChargingStationTestConsta import { createMockChargingStation } from '../../ChargingStationTestUtils.js' import { type CapturedOCPPRequest, - createMockOCPP20TransactionTestStation, createMockStationWithRequestTracking, type MockStationWithTracking, resetConnectorTransactionState, resetLimits, TransactionContextFixtures, } from './OCPP20TestUtils.js' - // ============================================================================ // Transaction Flow Patterns for Parameterized Testing // ============================================================================ @@ -80,10 +78,24 @@ const TRANSACTION_FLOWS = [ ] as const await describe('E01-E04 - OCPP 2.0.1 TransactionEvent Implementation', async () => { - let mockChargingStation: ReturnType + let mockChargingStation: ChargingStation beforeEach(() => { - mockChargingStation = createMockOCPP20TransactionTestStation() + const { station } = createMockChargingStation({ + baseName: TEST_CHARGING_STATION_BASE_NAME, + connectorsCount: 3, + evseConfiguration: { evsesCount: 3 }, + heartbeatInterval: Constants.DEFAULT_HEARTBEAT_INTERVAL, + ocppRequestService: { + requestHandler: async () => Promise.resolve({} as EmptyObject), + }, + stationInfo: { + ocppStrictCompliance: true, + ocppVersion: OCPPVersion.VERSION_201, + }, + websocketPingInterval: Constants.DEFAULT_WEBSOCKET_PING_INTERVAL, + }) + mockChargingStation = station resetLimits(mockChargingStation) }) @@ -91,7 +103,6 @@ await describe('E01-E04 - OCPP 2.0.1 TransactionEvent Implementation', async () afterEach(() => { standardCleanup() }) - // FR: E01.FR.01 - TransactionEventRequest structure validation await describe('buildTransactionEvent', async () => { await it('should build valid TransactionEvent Started with sequence number 0', () => { diff --git a/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts b/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts index a2654cf6..9ce6b990 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts @@ -72,29 +72,6 @@ export interface TestableOCPP20RequestService { ) => JsonType } -/** - * Create a mock ChargingStation for OCPP 2.0 transaction event testing. - * Provides standard configuration used across all transaction event test files. - * @returns ChargingStation configured for OCPP 2.0 transaction testing - */ -export function createMockOCPP20TransactionTestStation (): ChargingStation { - const { station } = createMockChargingStation({ - baseName: TEST_CHARGING_STATION_BASE_NAME, - connectorsCount: 3, - evseConfiguration: { evsesCount: 3 }, - heartbeatInterval: Constants.DEFAULT_HEARTBEAT_INTERVAL, - ocppRequestService: { - requestHandler: async () => Promise.resolve({} as EmptyObject), - }, - stationInfo: { - ocppStrictCompliance: true, - ocppVersion: OCPPVersion.VERSION_201, - }, - websocketPingInterval: Constants.DEFAULT_WEBSOCKET_PING_INTERVAL, - }) - return station -} - /** * Create a mock ChargingStation with request tracking for testing OCPP request flows. * This is useful for tests that need to verify what requests were sent. diff --git a/tests/charging-station/ui-server/UIServerTestUtils.ts b/tests/charging-station/ui-server/UIServerTestUtils.ts index f22dddf6..bbe82d0f 100644 --- a/tests/charging-station/ui-server/UIServerTestUtils.ts +++ b/tests/charging-station/ui-server/UIServerTestUtils.ts @@ -13,15 +13,62 @@ import type { UUIDv4, } from '../../../src/types/index.js' +import { UIWebSocketServer } from '../../../src/charging-station/ui-server/UIWebSocketServer.js' import { ApplicationProtocol, ApplicationProtocolVersion, AuthenticationType, ProcedureName, + ProtocolVersion, ResponseStatus, } from '../../../src/types/index.js' import { MockWebSocket } from '../mocks/MockWebSocket.js' +/** + * Testable UIWebSocketServer that exposes protected members for testing. + * Consolidates TestableUIWebSocketServer from UIWebSocketServer.test.ts and AbstractUIService.test.ts. + */ +export class TestableUIWebSocketServer extends UIWebSocketServer { + /** + * Add a response handler for testing + * @param uuid + * @param ws + */ + public addResponseHandler (uuid: UUIDv4, ws: MockWebSocket): void { + this.responseHandlers.set(uuid, ws as never) + } + + /** Get the size of response handlers map */ + public getResponseHandlersSize (): number { + return this.responseHandlers.size + } + + /** + * Get UI service by version + * @param version + */ + public getUIService (version: ProtocolVersion) { + return this.uiServices.get(version) + } + + /** + * Register a mock UI service for testing + * @param version + * @param service + */ + public registerMockUIService (version: string, service: unknown): void { + this.uiServices.set(version as never, service as never) + } + + /** + * Test helper to register protocol version UI service + * @param version + */ + public testRegisterProtocolVersionUIService (version: ProtocolVersion): void { + this.registerProtocolVersionUIService(version) + } +} + /** * Create a MockWebSocket configured for UI protocol testing. * @param protocol - UI protocol version (default: 'ui0.0.1') @@ -142,35 +189,6 @@ export const createProtocolRequest = ( return [uuid, procedureName, payload] } -export const createValidAuthorizeRequest = (uuid: UUIDv4, hashId: string): string => { - return JSON.stringify( - createProtocolRequest(uuid, ProcedureName.AUTHORIZE, { - hashIds: [hashId], - idTag: 'test-id-tag', - }) - ) -} - -export const createValidListRequest = (uuid: UUIDv4): string => { - return JSON.stringify(createProtocolRequest(uuid, ProcedureName.LIST_CHARGING_STATIONS, {})) -} - -export const createInvalidRequest = (): string => { - return '{"invalid": "json"' -} - -export const createMalformedRequest = (): string => { - return JSON.stringify({ not: 'an array' }) -} - -export const createMockBroadcastResponse = ( - uuid: string, - hashId: string, - status: ResponseStatus = ResponseStatus.SUCCESS -): [string, { hashId: string; status: ResponseStatus }] => { - return [uuid, { hashId, status }] -} - /** * Mock UI service behavior mode for testing different request handler scenarios. */ diff --git a/tests/charging-station/ui-server/UIWebSocketServer.test.ts b/tests/charging-station/ui-server/UIWebSocketServer.test.ts index 05d71e6b..a0afa68d 100644 --- a/tests/charging-station/ui-server/UIWebSocketServer.test.ts +++ b/tests/charging-station/ui-server/UIWebSocketServer.test.ts @@ -9,31 +9,16 @@ import { afterEach, describe, it, mock } from 'node:test' import type { UUIDv4 } from '../../../src/types/index.js' -import { UIWebSocketServer } from '../../../src/charging-station/ui-server/UIWebSocketServer.js' import { ProcedureName, ResponseStatus } from '../../../src/types/index.js' -import { MockWebSocket } from '../mocks/MockWebSocket.js' import { TEST_UUID } from './UIServerTestConstants.js' import { createMockUIServerConfiguration, createMockUIService, createMockUIWebSocket, MockUIServiceMode, + TestableUIWebSocketServer, } from './UIServerTestUtils.js' -class TestableUIWebSocketServer extends UIWebSocketServer { - public addResponseHandler (uuid: UUIDv4, ws: MockWebSocket): void { - this.responseHandlers.set(uuid, ws as never) - } - - public getResponseHandlersSize (): number { - return this.responseHandlers.size - } - - public registerMockUIService (version: string, service: unknown): void { - this.uiServices.set(version as never, service as never) - } -} - await describe('UIWebSocketServer test suite', async () => { afterEach(() => { mock.restoreAll() @@ -181,7 +166,7 @@ await describe('UIWebSocketServer test suite', async () => { await it('should create server with valid WebSocket configuration', () => { const config = createMockUIServerConfiguration() - const server = new UIWebSocketServer(config) + const server = new TestableUIWebSocketServer(config) expect(server).toBeDefined() }) @@ -194,7 +179,7 @@ await describe('UIWebSocketServer test suite', async () => { }, }) - const server = new UIWebSocketServer(config) + const server = new TestableUIWebSocketServer(config) expect(server).toBeDefined() }) }) 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 a1eadcd0..5531054b 100644 --- a/tests/charging-station/ui-server/ui-services/AbstractUIService.test.ts +++ b/tests/charging-station/ui-server/ui-services/AbstractUIService.test.ts @@ -7,25 +7,15 @@ import { expect } from '@std/expect' import { afterEach, describe, it, mock } from 'node:test' -import { UIWebSocketServer } from '../../../../src/charging-station/ui-server/UIWebSocketServer.js' import { ProcedureName, ProtocolVersion, ResponseStatus } from '../../../../src/types/index.js' import { TEST_HASH_ID, TEST_UUID } from '../UIServerTestConstants.js' import { createMockChargingStationData, createMockUIServerConfiguration, createProtocolRequest, + TestableUIWebSocketServer, } from '../UIServerTestUtils.js' -class TestableUIWebSocketServer extends UIWebSocketServer { - public getUIService (version: ProtocolVersion) { - return this.uiServices.get(version) - } - - public testRegisterProtocolVersionUIService (version: ProtocolVersion): void { - this.registerProtocolVersionUIService(version) - } -} - await describe('AbstractUIService test suite', async () => { afterEach(() => { mock.restoreAll() -- 2.53.0