From: Jérôme Benoit Date: Fri, 27 Feb 2026 02:24:13 +0000 (+0100) Subject: refactor(tests): rename createRealChargingStation to createMockChargingStation X-Git-Tag: ocpp-server@v3.0.0~133 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=11b065b13edc4ebfd6a3a8096330bf56a2644d92;p=e-mobility-charging-stations-simulator.git refactor(tests): rename createRealChargingStation to createMockChargingStation - Rename function to reflect its nature as a lightweight stub, not a real instance - Update all usages in ChargingStation.test.ts - Add EVSE 0 with connector 0 for station-level availability checks in EVSE mode - Add StopTransactionReason parameter to stop() method signature - Add comment explaining deleteConfiguration parameter usage in delete() - Update interface and type names to match (MockChargingStationOptions/Result) - Update JSDoc and file header to reflect mock terminology --- diff --git a/tests/charging-station/ChargingStation.test.ts b/tests/charging-station/ChargingStation.test.ts index 14895965..43ec2967 100644 --- a/tests/charging-station/ChargingStation.test.ts +++ b/tests/charging-station/ChargingStation.test.ts @@ -4,7 +4,7 @@ import { afterEach, describe, it } from 'node:test' import type { ChargingStation } from '../../src/charging-station/ChargingStation.js' import { RegistrationStatusEnumType } from '../../src/types/index.js' -import { cleanupChargingStation, createRealChargingStation } from './ChargingStationTestUtils.js' +import { cleanupChargingStation, createMockChargingStation } from './ChargingStationTestUtils.js' await describe('ChargingStation', async () => { await describe('Lifecycle', async () => { @@ -18,7 +18,7 @@ await describe('ChargingStation', async () => { await it('should transition from stopped to started on start()', () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station // Act @@ -33,7 +33,7 @@ await describe('ChargingStation', async () => { await it('should not restart when already started', () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station // Act @@ -49,7 +49,7 @@ await describe('ChargingStation', async () => { await it('should set starting flag during start()', () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station // Act & Assert @@ -63,7 +63,7 @@ await describe('ChargingStation', async () => { await it('should transition from started to stopped on stop()', async () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station station.start() expect(station.started).toBe(true) @@ -77,7 +77,7 @@ await describe('ChargingStation', async () => { await it('should be idempotent when calling stop() on already stopped station', async () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station // Station starts in stopped state expect(station.started).toBe(false) @@ -91,7 +91,7 @@ await describe('ChargingStation', async () => { await it('should set stopping flag during stop()', async () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station station.start() @@ -108,7 +108,7 @@ await describe('ChargingStation', async () => { await it('should clear bootNotificationResponse on stop()', async () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station station.start() expect(station.bootNotificationResponse).toBeDefined() @@ -122,7 +122,7 @@ await describe('ChargingStation', async () => { await it('should be restartable after stop()', async () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station station.start() expect(station.started).toBe(true) @@ -138,7 +138,7 @@ await describe('ChargingStation', async () => { await it('should handle delete() on stopped station', async () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station expect(station.started).toBe(false) @@ -153,7 +153,7 @@ await describe('ChargingStation', async () => { await it('should stop station before delete() if running', async () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station station.start() expect(station.started).toBe(true) @@ -168,7 +168,7 @@ await describe('ChargingStation', async () => { await it('should guard against concurrent start operations', () => { // Arrange - const result = createRealChargingStation({ connectorsCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 1 }) station = result.station // Simulate starting state manually to test guard @@ -197,7 +197,7 @@ await describe('ChargingStation', async () => { // === Connector Query Tests === await it('should return true for hasConnector() with existing connector IDs', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station expect(station.hasConnector(0)).toBe(true) @@ -206,7 +206,7 @@ await describe('ChargingStation', async () => { }) await it('should return false for hasConnector() with non-existing connector IDs', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station expect(station.hasConnector(3)).toBe(false) @@ -215,7 +215,7 @@ await describe('ChargingStation', async () => { }) await it('should return connector status for valid connector IDs', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station const status1 = station.getConnectorStatus(1) @@ -226,7 +226,7 @@ await describe('ChargingStation', async () => { }) await it('should return undefined for getConnectorStatus() with invalid connector IDs', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station expect(station.getConnectorStatus(999)).toBeUndefined() @@ -234,7 +234,7 @@ await describe('ChargingStation', async () => { }) await it('should correctly count connectors via getNumberOfConnectors()', () => { - const result = createRealChargingStation({ connectorsCount: 3 }) + const result = createMockChargingStation({ connectorsCount: 3 }) station = result.station // Should return 3, not 4 (connector 0 is excluded from count) @@ -242,7 +242,7 @@ await describe('ChargingStation', async () => { }) await it('should return true for isConnectorAvailable() on operative connectors', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station expect(station.isConnectorAvailable(1)).toBe(true) @@ -251,14 +251,14 @@ await describe('ChargingStation', async () => { await it('should return false for isConnectorAvailable() on connector 0', () => { // Connector 0 is never "available" per isConnectorAvailable() logic (connectorId > 0) - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station expect(station.isConnectorAvailable(0)).toBe(false) }) await it('should return false for isConnectorAvailable() on non-existing connector', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station expect(station.isConnectorAvailable(999)).toBe(false) @@ -267,7 +267,7 @@ await describe('ChargingStation', async () => { // === Connector 0 (shared power) Tests === await it('should include connector 0 for shared power configuration', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station // Connector 0 always exists and represents the charging station itself @@ -276,7 +276,7 @@ await describe('ChargingStation', async () => { }) await it('should determine station availability via connector 0 status', () => { - const result = createRealChargingStation({ connectorsCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 2 }) station = result.station // Initially connector 0 is operative @@ -286,7 +286,7 @@ await describe('ChargingStation', async () => { // === EVSE Query Tests (non-EVSE mode) === await it('should return 0 for getNumberOfEvses() in non-EVSE mode', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 0 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 0 }) station = result.station expect(station.hasEvses).toBe(false) @@ -294,7 +294,7 @@ await describe('ChargingStation', async () => { }) await it('should return undefined for getEvseIdByConnectorId() in non-EVSE mode', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 0 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 0 }) station = result.station expect(station.getEvseIdByConnectorId(1)).toBeUndefined() @@ -304,21 +304,21 @@ await describe('ChargingStation', async () => { // === EVSE Mode Tests === await it('should enable hasEvses flag in EVSE mode', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station expect(station.hasEvses).toBe(true) }) await it('should return correct EVSE count via getNumberOfEvses() in EVSE mode', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station expect(station.getNumberOfEvses()).toBe(1) }) await it('should return connector status via getConnectorStatus() in EVSE mode', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station // Connectors are nested under EVSEs in EVSE mode @@ -330,7 +330,7 @@ await describe('ChargingStation', async () => { }) await it('should map connector IDs to EVSE IDs via getEvseIdByConnectorId()', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station // In single-EVSE mode, both connectors should map to EVSE 1 @@ -339,14 +339,14 @@ await describe('ChargingStation', async () => { }) await it('should return undefined for getEvseIdByConnectorId() with invalid connector', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station expect(station.getEvseIdByConnectorId(999)).toBeUndefined() }) await it('should return EVSE status via getEvseStatus() for valid EVSE IDs', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station const evseStatus = station.getEvseStatus(1) @@ -357,14 +357,14 @@ await describe('ChargingStation', async () => { }) await it('should return undefined for getEvseStatus() with invalid EVSE IDs', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station expect(station.getEvseStatus(999)).toBeUndefined() }) await it('should return true for hasConnector() with connectors in EVSE mode', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station expect(station.hasConnector(1)).toBe(true) @@ -372,14 +372,14 @@ await describe('ChargingStation', async () => { }) await it('should return false for hasConnector() with non-existing connector in EVSE mode', () => { - const result = createRealChargingStation({ connectorsCount: 2, evsesCount: 1 }) + const result = createMockChargingStation({ connectorsCount: 2, evsesCount: 1 }) station = result.station expect(station.hasConnector(999)).toBe(false) }) await it('should correctly count connectors in EVSE mode via getNumberOfConnectors()', () => { - const result = createRealChargingStation({ connectorsCount: 4, evsesCount: 2 }) + const result = createMockChargingStation({ connectorsCount: 4, evsesCount: 2 }) station = result.station // Should return total connectors across all EVSEs diff --git a/tests/charging-station/ChargingStationTestUtils.ts b/tests/charging-station/ChargingStationTestUtils.ts index ca39f17e..3cc5e5c1 100644 --- a/tests/charging-station/ChargingStationTestUtils.ts +++ b/tests/charging-station/ChargingStationTestUtils.ts @@ -1,12 +1,12 @@ /** - * Utilities for creating REAL ChargingStation instances in tests + * Utilities for creating MOCK ChargingStation instances in tests * - * This file provides factory functions to instantiate actual ChargingStation - * objects (not mocks) with properly isolated dependencies for testing. + * This file provides factory functions to instantiate mock ChargingStation + * objects (lightweight stubs) with properly isolated dependencies for testing. * * Key patterns: * - MockWebSocket: Captures sent messages for assertion - * - Singleton mocking: Overrides getInstance() before ChargingStation import + * - Singleton mocking: Overrides getInstance() for shared caches * - Cleanup utilities: Prevents test pollution via timer/listener cleanup * @see tests/ChargingStationFactory.ts for mock factory (creates mock objects) * @see tests/charging-station/ChargingStationTestConstants.ts for test constants @@ -22,6 +22,7 @@ import type { ChargingStationTemplate, ConnectorStatus, EvseStatus, + StopTransactionReason, } from '../../src/types/index.js' import { @@ -70,9 +71,9 @@ export interface ChargingStationMocks { } /** - * Options for creating a real ChargingStation instance + * Options for creating a mock ChargingStation instance */ -export interface RealChargingStationOptions { +export interface MockChargingStationOptions { /** Auto-start the station on creation */ autoStart?: boolean @@ -105,9 +106,9 @@ export interface RealChargingStationOptions { } /** - * Result of creating a real ChargingStation instance + * Result of creating a mock ChargingStation instance */ -export interface RealChargingStationResult { +export interface MockChargingStationResult { /** All mocks used by the station for assertion */ mocks: ChargingStationMocks @@ -446,46 +447,28 @@ export function cleanupChargingStation (station: ChargingStation): void { } /** - * Create a mock template for testing - * @param overrides - Template properties to override - * @returns ChargingStationTemplate for testing - */ -export function createMockTemplate ( - overrides: Partial = {} -): ChargingStationTemplate { - return { - baseName: TEST_CHARGING_STATION_BASE_NAME, - chargePointModel: 'Test Model', - chargePointVendor: 'Test Vendor', - numberOfConnectors: 2, - ocppVersion: OCPPVersion.VERSION_16, - ...overrides, - } as ChargingStationTemplate -} - -/** - * Creates a minimal ChargingStation-like object for testing + * Creates a minimal mock ChargingStation-like object for testing * * Due to the complexity of the ChargingStation class and its deep dependencies * (Bootstrap singleton, file system, WebSocket, worker threads), this factory - * creates an object that implements the essential ChargingStation interface + * creates a lightweight stub that implements the essential ChargingStation interface * without requiring the full initialization chain. * * This is useful for testing code that depends on ChargingStation methods * without needing the full OCPP protocol stack. - * @param options - Configuration options for the charging station - * @returns Object with station instance and mocks for assertion + * @param options - Configuration options for the mock charging station + * @returns Object with mock station instance and mocks for assertion * @example * ```typescript - * const { station, mocks } = createRealChargingStation({ connectorsCount: 2 }) + * const { station, mocks } = createMockChargingStation({ connectorsCount: 2 }) * expect(station.connectors.size).toBe(3) // 0 + 2 connectors * station.wsConnection = mocks.webSocket * mocks.webSocket.simulateMessage('["3","uuid",{}]') * ``` */ -export function createRealChargingStation ( - options: RealChargingStationOptions = {} -): RealChargingStationResult { +export function createMockChargingStation ( + options: MockChargingStationOptions = {} +): MockChargingStationResult { const { autoStart = false, baseName = TEST_CHARGING_STATION_BASE_NAME, @@ -522,6 +505,18 @@ export function createRealChargingStation ( // Create EVSEs map if applicable const evses = new Map() if (useEvses) { + // EVSE 0 contains connector 0 (station-level status for availability checks) + const evse0Connectors = new Map() + const connector0Status = connectors.get(0) + if (connector0Status != null) { + evse0Connectors.set(0, connector0Status) + } + evses.set(0, { + availability: AvailabilityType.Operative, + connectors: evse0Connectors, + }) + + // Create EVSEs 1..N with their respective connectors const connectorsPerEvse = Math.ceil(connectorsCount / evsesCount) for (let evseId = 1; evseId <= evsesCount; evseId++) { const evseConnectors = new Map() @@ -561,6 +556,7 @@ export function createRealChargingStation ( } }, connectors, + async delete (deleteConfiguration = true): Promise { if (this.started) { await this.stop() @@ -568,6 +564,8 @@ export function createRealChargingStation ( this.requests.clear() this.connectors.clear() this.evses.clear() + // Note: deleteConfiguration controls file deletion in real implementation + // Mock doesn't have file system access, so parameter is unused }, // Event emitter methods (minimal implementation) emit: () => true, @@ -731,7 +729,8 @@ export function createRealChargingStation ( templateIndex: index, templateName: templateFile, }, - async stop (): Promise { + + async stop (reason?: StopTransactionReason, stopTransactions?: boolean): Promise { if (this.started && !this.stopping) { this.stopping = true // Simulate async stop behavior (immediate resolution for tests) @@ -771,6 +770,24 @@ export function createRealChargingStation ( } } +/** + * Create a mock template for testing + * @param overrides - Template properties to override + * @returns ChargingStationTemplate for testing + */ +export function createMockTemplate ( + overrides: Partial = {} +): ChargingStationTemplate { + return { + baseName: TEST_CHARGING_STATION_BASE_NAME, + chargePointModel: 'Test Model', + chargePointVendor: 'Test Vendor', + numberOfConnectors: 2, + ocppVersion: OCPPVersion.VERSION_16, + ...overrides, + } as ChargingStationTemplate +} + /** * Reset a ChargingStation to its initial state *