]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor(tests): consolidate duplicate test helpers
authorJérôme Benoit <jerome.benoit@sap.com>
Thu, 2 Apr 2026 19:48:40 +0000 (21:48 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Thu, 2 Apr 2026 19:48:40 +0000 (21:48 +0200)
Extract createStationWithRequestHandler to shared
TestLifecycleHelpers, eliminating duplication between
OCPPConnectorStatusOperations and OCPPServiceOperations tests.
Extend setupConnectorWithTransaction to support string
transactionId and pending mode, replacing local
setupTransaction/setupPendingTransaction helpers.

tests/charging-station/ocpp/OCPPConnectorStatusOperations.test.ts
tests/charging-station/ocpp/OCPPServiceOperations.test.ts
tests/helpers/TestLifecycleHelpers.ts

index 3aad34228af5b2ee5584744ed57c17b2b9bc3414..530fa077fe555ec66b056a1d019d57486d6e5237 100644 (file)
@@ -10,9 +10,7 @@
 import assert from 'node:assert/strict'
 import { afterEach, describe, it, mock } from 'node:test'
 
-import type { ChargingStation } from '../../../src/charging-station/index.js'
 import type { Reservation } from '../../../src/types/index.js'
-import type { MockChargingStationOptions } from '../helpers/StationHelpers.js'
 
 import {
   restoreConnectorStatus,
@@ -24,25 +22,10 @@ import {
   type OCPP20StatusNotificationRequest,
   OCPPVersion,
 } from '../../../src/types/index.js'
-import { standardCleanup } from '../../helpers/TestLifecycleHelpers.js'
-import { createMockChargingStation } from '../ChargingStationTestUtils.js'
-
-/**
- * Creates a mock station with a spied requestHandler for verifying OCPP requests.
- * @param opts - Additional mock station options to merge
- * @returns The station and its requestHandler spy
- */
-function createStationWithRequestHandler (opts?: Partial<MockChargingStationOptions>): {
-  requestHandler: ReturnType<typeof mock.fn>
-  station: ChargingStation
-} {
-  const requestHandler = mock.fn(() => Promise.resolve({}))
-  const { station } = createMockChargingStation({
-    ocppRequestService: { requestHandler },
-    ...opts,
-  })
-  return { requestHandler, station }
-}
+import {
+  createStationWithRequestHandler,
+  standardCleanup,
+} from '../../helpers/TestLifecycleHelpers.js'
 
 await describe('OCPPConnectorStatusOperations', async () => {
   afterEach(() => {
index 474e078a7189f9d5d81bc0b4d0d38343b19760ae..8154038c4fe4d4baf3461f0900cc157827b39bc5 100644 (file)
@@ -6,10 +6,7 @@
  */
 
 import assert from 'node:assert/strict'
-import { afterEach, describe, it, mock } from 'node:test'
-
-import type { ChargingStation } from '../../../src/charging-station/index.js'
-import type { MockChargingStationOptions } from '../helpers/StationHelpers.js'
+import { afterEach, describe, it } from 'node:test'
 
 import {
   AuthContext,
@@ -25,30 +22,17 @@ import {
   stopTransactionOnConnector,
 } from '../../../src/charging-station/ocpp/OCPPServiceOperations.js'
 import { type OCPP20TransactionEventRequest, OCPPVersion } from '../../../src/types/index.js'
-import { standardCleanup } from '../../helpers/TestLifecycleHelpers.js'
+import {
+  createStationWithRequestHandler,
+  setupConnectorWithTransaction,
+  standardCleanup,
+} from '../../helpers/TestLifecycleHelpers.js'
 import { createMockChargingStation } from '../ChargingStationTestUtils.js'
 import {
   createMockAuthorizationResult,
   createMockAuthService,
 } from './auth/helpers/MockFactories.js'
 
-/**
- * Creates a mock charging station with a tracked request handler for testing
- * @param opts - optional charging station configuration options
- * @returns object with the mock station and the mock request handler function
- */
-function createStationWithRequestHandler (opts?: Partial<MockChargingStationOptions>): {
-  requestHandler: ReturnType<typeof mock.fn>
-  station: ChargingStation
-} {
-  const requestHandler = mock.fn(async (..._args: unknown[]) => Promise.resolve({}))
-  const { station } = createMockChargingStation({
-    ocppRequestService: { requestHandler },
-    ...opts,
-  })
-  return { requestHandler, station }
-}
-
 /**
  * Registers a mock auth service for the given station in OCPPAuthServiceFactory.
  * @param station - Mock charging station instance
@@ -65,49 +49,6 @@ function injectMockAuthService (
   return mockService
 }
 
-/**
- * Configures a connector with a pending (not started) transaction for testing
- * @param station - the charging station mock
- * @param connectorId - the connector ID to configure
- * @param txId - the transaction ID to assign
- */
-function setupPendingTransaction (
-  station: ChargingStation,
-  connectorId: number,
-  txId: string
-): void {
-  const connectorStatus = station.getConnectorStatus(connectorId)
-  if (connectorStatus == null) {
-    throw new Error(`Connector ${String(connectorId)} not found`)
-  }
-  connectorStatus.transactionPending = true
-  connectorStatus.transactionStarted = false
-  connectorStatus.transactionId = txId
-  connectorStatus.transactionStart = new Date()
-}
-
-/**
- * Configures a connector with a started transaction for testing
- * @param station - the charging station mock
- * @param connectorId - the connector ID to configure
- * @param txId - the transaction ID to assign
- */
-function setupTransaction (
-  station: ChargingStation,
-  connectorId: number,
-  txId: number | string
-): void {
-  const connectorStatus = station.getConnectorStatus(connectorId)
-  if (connectorStatus == null) {
-    throw new Error(`Connector ${String(connectorId)} not found`)
-  }
-  connectorStatus.transactionStarted = true
-  connectorStatus.transactionId = txId
-  connectorStatus.transactionIdTag = `TAG-${String(txId)}`
-  connectorStatus.transactionStart = new Date()
-  connectorStatus.idTagAuthorized = true
-}
-
 await describe('OCPPServiceOperations', async () => {
   afterEach(() => {
     OCPPAuthServiceFactory.clearAllInstances()
@@ -120,7 +61,7 @@ await describe('OCPPServiceOperations', async () => {
       requestHandler.mock.mockImplementation(async (..._args: unknown[]) =>
         Promise.resolve({ idTagInfo: { status: 'Accepted' } })
       )
-      setupTransaction(station, 1, 100)
+      setupConnectorWithTransaction(station, 1, { transactionId: 100 })
 
       const result = await stopTransactionOnConnector(station, 1)
 
@@ -140,7 +81,7 @@ await describe('OCPPServiceOperations', async () => {
       requestHandler.mock.mockImplementation(async (..._args: unknown[]) =>
         Promise.resolve({ idTokenInfo: { status: 'Accepted' } })
       )
-      setupTransaction(station, 1, 'tx-uuid-001')
+      setupConnectorWithTransaction(station, 1, { transactionId: 'tx-uuid-001' })
 
       const result = await stopTransactionOnConnector(station, 1)
 
@@ -179,8 +120,8 @@ await describe('OCPPServiceOperations', async () => {
         sentCommands.push(args[1] as string)
         return Promise.resolve({ idTagInfo: { status: 'Accepted' } })
       })
-      setupTransaction(station, 1, 101)
-      setupTransaction(station, 2, 102)
+      setupConnectorWithTransaction(station, 1, { transactionId: 101 })
+      setupConnectorWithTransaction(station, 2, { transactionId: 102 })
 
       await stopRunningTransactions(station)
 
@@ -203,8 +144,8 @@ await describe('OCPPServiceOperations', async () => {
         })
         return Promise.resolve({ idTokenInfo: { status: 'Accepted' } })
       })
-      setupTransaction(station, 1, 'tx-001')
-      setupTransaction(station, 2, 'tx-002')
+      setupConnectorWithTransaction(station, 1, { transactionId: 'tx-001' })
+      setupConnectorWithTransaction(station, 2, { transactionId: 'tx-002' })
 
       await stopRunningTransactions(station)
 
@@ -230,8 +171,8 @@ await describe('OCPPServiceOperations', async () => {
         })
         return Promise.resolve({ idTokenInfo: { status: 'Accepted' } })
       })
-      setupTransaction(station, 1, 'tx-started')
-      setupPendingTransaction(station, 2, 'tx-pending')
+      setupConnectorWithTransaction(station, 1, { transactionId: 'tx-started' })
+      setupConnectorWithTransaction(station, 2, { pending: true, transactionId: 'tx-pending' })
 
       await stopRunningTransactions(station)
 
@@ -248,7 +189,7 @@ await describe('OCPPServiceOperations', async () => {
       requestHandler.mock.mockImplementation(async () =>
         Promise.reject(new Error('Simulated network error'))
       )
-      setupTransaction(station, 1, 'tx-fail')
+      setupConnectorWithTransaction(station, 1, { transactionId: 'tx-fail' })
 
       await assert.doesNotReject(() => stopRunningTransactions(station))
     })
index 370c91d4c57b7fc2f43f231c3da67b79460457b8..0d11ab6878b393c06d269497795fd17f4019440c 100644 (file)
@@ -28,7 +28,9 @@
 import { mock } from 'node:test'
 
 import type { ChargingStation } from '../../src/charging-station/index.js'
+import type { MockChargingStationOptions } from '../charging-station/helpers/StationHelpers.js'
 
+import { createMockChargingStation } from '../charging-station/ChargingStationTestUtils.js'
 import { MockIdTagsCache, MockSharedLRUCache } from '../charging-station/mocks/MockCaches.js'
 
 /**
@@ -194,6 +196,23 @@ export function createLoggerMocks (
   }
 }
 
+/**
+ * Creates a mock charging station with a spied requestHandler for verifying OCPP requests.
+ * @param opts - Additional mock station options to merge
+ * @returns Object with the station and its requestHandler spy
+ */
+export function createStationWithRequestHandler (opts?: Partial<MockChargingStationOptions>): {
+  requestHandler: ReturnType<typeof mock.fn>
+  station: ChargingStation
+} {
+  const requestHandler = mock.fn(async (..._args: unknown[]) => Promise.resolve({}))
+  const { station } = createMockChargingStation({
+    ocppRequestService: { requestHandler },
+    ...opts,
+  })
+  return { requestHandler, station }
+}
+
 /**
  * Create a timer scope for manual control over timer mocking.
  *
@@ -244,6 +263,7 @@ export function createTimerScope (
  * @param station - ChargingStation instance
  * @param connectorId - Connector to setup
  * @param options - Transaction options
+ * @param options.pending - Whether transaction is pending (not started) (default: false)
  * @param options.transactionId - Transaction ID to set
  * @param options.idTag - ID tag for the transaction (default: TAG-{transactionId})
  * @param options.energyImport - Energy import value in Wh (default: 0)
@@ -263,8 +283,9 @@ export function setupConnectorWithTransaction (
   options: {
     energyImport?: number
     idTag?: string
+    pending?: boolean
     remoteStarted?: boolean
-    transactionId: number
+    transactionId: number | string
   }
 ): void {
   const connectorStatus = station.getConnectorStatus(connectorId)
@@ -272,13 +293,18 @@ export function setupConnectorWithTransaction (
     throw new Error(`Connector ${String(connectorId)} not found`)
   }
 
-  connectorStatus.transactionStarted = true
+  if (options.pending === true) {
+    connectorStatus.transactionPending = true
+    connectorStatus.transactionStarted = false
+  } else {
+    connectorStatus.transactionStarted = true
+  }
   connectorStatus.transactionId = options.transactionId
   connectorStatus.transactionIdTag = options.idTag ?? `TAG-${String(options.transactionId)}`
   connectorStatus.transactionEnergyActiveImportRegisterValue = options.energyImport ?? 0
   connectorStatus.transactionRemoteStarted = options.remoteStarted ?? false
   connectorStatus.transactionStart = new Date()
-  connectorStatus.idTagAuthorized = true
+  connectorStatus.idTagAuthorized = options.pending !== true
 }
 
 /**