]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor(tests): rename createRealChargingStation to createMockChargingStation
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 27 Feb 2026 02:24:13 +0000 (03:24 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 27 Feb 2026 14:00:18 +0000 (15:00 +0100)
- 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

tests/charging-station/ChargingStation.test.ts
tests/charging-station/ChargingStationTestUtils.ts

index 14895965ba9dc1700ce52e70627209e20fdc0a8d..43ec2967ab2c0177f015047053db1f6edb5a7373 100644 (file)
@@ -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
index ca39f17ef9bff1c3e89accdfdb0a7baf1f2c9970..3cc5e5c13661bfd9835e24c3e525befa3918312e 100644 (file)
@@ -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> = {}
-): 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<number, EvseStatus>()
   if (useEvses) {
+    // EVSE 0 contains connector 0 (station-level status for availability checks)
+    const evse0Connectors = new Map<number, ConnectorStatus>()
+    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<number, ConnectorStatus>()
@@ -561,6 +556,7 @@ export function createRealChargingStation (
       }
     },
     connectors,
+
     async delete (deleteConfiguration = true): Promise<void> {
       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<void> {
+
+    async stop (reason?: StopTransactionReason, stopTransactions?: boolean): Promise<void> {
       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> = {}
+): 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
  *