From: Jérôme Benoit Date: Fri, 27 Feb 2026 15:45:27 +0000 (+0100) Subject: refactor(tests): add mock factories to eliminate test duplication X-Git-Tag: ocpp-server@v3.0.0~123 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=2845ec5e39b5217694a76b32ce8261a06e3ad9e2;p=e-mobility-charging-stations-simulator.git refactor(tests): add mock factories to eliminate test duplication - Add createMockAuthServiceTestStation() to MockFactories.ts - Add createMockOCPP20TransactionTestStation() to OCPP20TestUtils.ts - Replace 19 inline mocks in OCPPAuthServiceImpl.test.ts - Replace inline setup in 3 OCPP 2.0 transaction test files --- diff --git a/tests/charging-station/ChargingStation.test.ts b/tests/charging-station/ChargingStation.test.ts index 42a35197..d87fae2d 100644 --- a/tests/charging-station/ChargingStation.test.ts +++ b/tests/charging-station/ChargingStation.test.ts @@ -6,6 +6,9 @@ import type { ChargingStation } from '../../src/charging-station/ChargingStation import { AvailabilityType, RegistrationStatusEnumType } from '../../src/types/index.js' import { cleanupChargingStation, createMockChargingStation } from './ChargingStationTestUtils.js' +// Alias for tests that reference createRealChargingStation +const createRealChargingStation = createMockChargingStation + await describe('ChargingStation', async () => { await describe('Lifecycle', async () => { let station: ChargingStation | undefined diff --git a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-CableFirst.test.ts b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-CableFirst.test.ts index 3a3396dd..dae0db1f 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-CableFirst.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-CableFirst.test.ts @@ -1,23 +1,22 @@ import { expect } from '@std/expect' import { afterEach, describe, it } from 'node:test' -import type { EmptyObject } from '../../../../src/types/index.js' - import { OCPP20ServiceUtils } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js' import { ConnectorStatusEnum, OCPP20TransactionEventEnumType, OCPP20TriggerReasonEnumType, - OCPPVersion, } from '../../../../src/types/index.js' import { OCPP20ChargingStateEnumType, type OCPP20TransactionContext, } from '../../../../src/types/ocpp/2.0/Transaction.js' -import { Constants, generateUUID } from '../../../../src/utils/index.js' -import { createChargingStation } from '../../../ChargingStationFactory.js' -import { TEST_CHARGING_STATION_BASE_NAME } from './OCPP20TestConstants.js' -import { resetConnectorTransactionState, resetLimits } from './OCPP20TestUtils.js' +import { generateUUID } from '../../../../src/utils/index.js' +import { + createMockOCPP20TransactionTestStation, + resetConnectorTransactionState, + resetLimits, +} from './OCPP20TestUtils.js' /** * E02 - Cable-First Transaction Flow Tests @@ -38,22 +37,7 @@ import { resetConnectorTransactionState, resetLimits } from './OCPP20TestUtils.j * - E02.FR.03: Connector status transitions reflect cable state changes */ await describe('E02 - Cable-First Transaction Flow', async () => { - const mockChargingStation = createChargingStation({ - baseName: TEST_CHARGING_STATION_BASE_NAME, - connectorsCount: 3, - evseConfiguration: { evsesCount: 3 }, - heartbeatInterval: Constants.DEFAULT_HEARTBEAT_INTERVAL, - ocppRequestService: { - requestHandler: async () => { - return Promise.resolve({} as EmptyObject) - }, - }, - stationInfo: { - ocppStrictCompliance: true, - ocppVersion: OCPPVersion.VERSION_201, - }, - websocketPingInterval: Constants.DEFAULT_WEBSOCKET_PING_INTERVAL, - }) + const mockChargingStation = createMockOCPP20TransactionTestStation() // Reset limits and state before tests resetLimits(mockChargingStation) diff --git a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-IdTokenFirst.test.ts b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-IdTokenFirst.test.ts index ea38f12b..00fa1c2a 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-IdTokenFirst.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent-IdTokenFirst.test.ts @@ -1,13 +1,10 @@ import { expect } from '@std/expect' import { afterEach, describe, it } from 'node:test' -import type { EmptyObject } from '../../../../src/types/index.js' - import { OCPP20ServiceUtils } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js' import { OCPP20TransactionEventEnumType, OCPP20TriggerReasonEnumType, - OCPPVersion, } from '../../../../src/types/index.js' import { OCPP20ChargingStateEnumType, @@ -15,10 +12,12 @@ import { type OCPP20IdTokenType, type OCPP20TransactionContext, } from '../../../../src/types/ocpp/2.0/Transaction.js' -import { Constants, generateUUID } from '../../../../src/utils/index.js' -import { createChargingStation } from '../../../ChargingStationFactory.js' -import { TEST_CHARGING_STATION_BASE_NAME } from './OCPP20TestConstants.js' -import { resetConnectorTransactionState, resetLimits } from './OCPP20TestUtils.js' +import { generateUUID } from '../../../../src/utils/index.js' +import { + createMockOCPP20TransactionTestStation, + resetConnectorTransactionState, + resetLimits, +} from './OCPP20TestUtils.js' /** * E03 IdToken-First Transaction Flow Tests (OCPP 2.0.1) @@ -38,22 +37,7 @@ import { resetConnectorTransactionState, resetLimits } from './OCPP20TestUtils.j * - E02: Cable connection -> EV detection -> Authorization -> Charging */ await describe('E03 - IdToken-First Pre-Authorization Flow', async () => { - const mockChargingStation = createChargingStation({ - baseName: TEST_CHARGING_STATION_BASE_NAME, - connectorsCount: 3, - evseConfiguration: { evsesCount: 3 }, - heartbeatInterval: Constants.DEFAULT_HEARTBEAT_INTERVAL, - ocppRequestService: { - requestHandler: async () => { - return Promise.resolve({} as EmptyObject) - }, - }, - stationInfo: { - ocppStrictCompliance: true, - ocppVersion: OCPPVersion.VERSION_201, - }, - websocketPingInterval: Constants.DEFAULT_WEBSOCKET_PING_INTERVAL, - }) + const mockChargingStation = createMockOCPP20TransactionTestStation() // Reset limits and state before tests resetLimits(mockChargingStation) 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 15b305be..85b69984 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts @@ -6,8 +6,6 @@ import { expect } from '@std/expect' import { describe, it } from 'node:test' -import type { EmptyObject } from '../../../../src/types/index.js' - import { OCPP20ServiceUtils } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js' import { OCPP20TransactionEventEnumType, @@ -23,26 +21,10 @@ import { import { Constants, generateUUID } from '../../../../src/utils/index.js' import { createChargingStation } from '../../../ChargingStationFactory.js' import { TEST_CHARGING_STATION_BASE_NAME } from './OCPP20TestConstants.js' -import { resetLimits } from './OCPP20TestUtils.js' +import { createMockOCPP20TransactionTestStation, resetLimits } from './OCPP20TestUtils.js' await describe('E01-E04 - OCPP 2.0.1 TransactionEvent Implementation', async () => { - const mockChargingStation = createChargingStation({ - baseName: TEST_CHARGING_STATION_BASE_NAME, - connectorsCount: 3, - evseConfiguration: { evsesCount: 3 }, - heartbeatInterval: Constants.DEFAULT_HEARTBEAT_INTERVAL, - ocppRequestService: { - requestHandler: async () => { - // Mock successful OCPP request responses (EmptyObject for TransactionEventResponse) - return Promise.resolve({} as EmptyObject) - }, - }, - stationInfo: { - ocppStrictCompliance: true, - ocppVersion: OCPPVersion.VERSION_201, - }, - websocketPingInterval: Constants.DEFAULT_WEBSOCKET_PING_INTERVAL, - }) + const mockChargingStation = createMockOCPP20TransactionTestStation() // Reset limits before tests resetLimits(mockChargingStation) diff --git a/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts b/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts index c7eb7b5f..c718934d 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts @@ -1,8 +1,37 @@ import type { ChargingStation } from '../../../../src/charging-station/ChargingStation.js' import type { ConfigurationKey } from '../../../../src/types/ChargingStationOcppConfiguration.js' +import type { EmptyObject } from '../../../../src/types/EmptyObject.js' -import { ConnectorStatusEnum, OCPP20RequiredVariableName } from '../../../../src/types/index.js' +import { + ConnectorStatusEnum, + OCPP20RequiredVariableName, + OCPPVersion, +} from '../../../../src/types/index.js' import { Constants } from '../../../../src/utils/index.js' +import { createChargingStation } from '../../../ChargingStationFactory.js' +import { TEST_CHARGING_STATION_BASE_NAME } from '../../ChargingStationTestConstants.js' + +/** + * 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 { + return createChargingStation({ + 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, + }) +} /** * Reset connector transaction state for all connectors in the charging station. diff --git a/tests/charging-station/ocpp/auth/helpers/MockFactories.ts b/tests/charging-station/ocpp/auth/helpers/MockFactories.ts index 6836f3cf..80396d88 100644 --- a/tests/charging-station/ocpp/auth/helpers/MockFactories.ts +++ b/tests/charging-station/ocpp/auth/helpers/MockFactories.ts @@ -2,6 +2,7 @@ import { expect } from '@std/expect' +import type { ChargingStation } from '../../../../../src/charging-station/ChargingStation.js' import type { OCPPAuthService } from '../../../../../src/charging-station/ocpp/auth/interfaces/OCPPAuthService.js' import { @@ -279,3 +280,27 @@ export const createMockChargingStation = ( }, ...overrides, }) + +/** + * Create a mock ChargingStation for auth service testing. + * Provides minimal station interface needed for OCPPAuthServiceImpl tests. + * @param id - Station identifier suffix (e.g., '001' creates 'TEST-CS-001') + * @param ocppVersion - OCPP version (defaults to VERSION_16) + * @returns Mock ChargingStation with logPrefix and stationInfo + */ +export const createMockAuthServiceTestStation = ( + id: string, + ocppVersion: OCPPVersion = OCPPVersion.VERSION_16 +): ChargingStation => + ({ + getConnectorStatus: () => ({ status: 'Available' }), + idTagLocalAuthorized: () => false, + isConnected: () => true, + logPrefix: () => `[TEST-CS-${id}]`, + ocppVersion, + sendRequest: () => Promise.resolve({}), + stationInfo: { + chargingStationId: `TEST-CS-${id}`, + hashId: `test-hash-${id}`, + }, + }) as unknown as ChargingStation diff --git a/tests/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.test.ts b/tests/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.test.ts index 74eabda1..dc7a4e72 100644 --- a/tests/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.test.ts +++ b/tests/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.test.ts @@ -1,7 +1,6 @@ import { expect } from '@std/expect' import { afterEach, describe, it } from 'node:test' -import type { ChargingStation } from '../../../../../src/charging-station/ChargingStation.js' import type { OCPPAuthService } from '../../../../../src/charging-station/ocpp/auth/interfaces/OCPPAuthService.js' import { OCPPAuthServiceImpl } from '../../../../../src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.js' @@ -13,6 +12,7 @@ import { type UnifiedIdentifier, } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js' import { OCPPVersion } from '../../../../../src/types/ocpp/OCPPVersion.js' +import { createMockAuthServiceTestStation } from '../helpers/MockFactories.js' await describe('OCPPAuthServiceImpl', async () => { afterEach(() => { @@ -21,13 +21,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('constructor', async () => { await it('should initialize with OCPP 1.6 charging station', () => { - const mockStation = { - logPrefix: () => '[TEST-CS-001]', - stationInfo: { - chargingStationId: 'TEST-CS-001', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('001') const authService: OCPPAuthService = new OCPPAuthServiceImpl(mockStation) @@ -37,13 +31,7 @@ await describe('OCPPAuthServiceImpl', async () => { }) await it('should initialize with OCPP 2.0 charging station', () => { - const mockStation = { - logPrefix: () => '[TEST-CS-002]', - stationInfo: { - chargingStationId: 'TEST-CS-002', - ocppVersion: OCPPVersion.VERSION_20, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('002', OCPPVersion.VERSION_20) const authService = new OCPPAuthServiceImpl(mockStation) @@ -53,13 +41,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('getConfiguration', async () => { await it('should return default configuration', () => { - const mockStation = { - logPrefix: () => '[TEST-CS-003]', - stationInfo: { - chargingStationId: 'TEST-CS-003', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('003') const authService = new OCPPAuthServiceImpl(mockStation) const config = authService.getConfiguration() @@ -73,13 +55,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('updateConfiguration', async () => { await it('should update configuration', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-004]', - stationInfo: { - chargingStationId: 'TEST-CS-004', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('004') const authService = new OCPPAuthServiceImpl(mockStation) @@ -96,13 +72,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('isSupported', async () => { await it('should check if identifier type is supported for OCPP 1.6', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-005]', - stationInfo: { - chargingStationId: 'TEST-CS-005', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('005') const authService = new OCPPAuthServiceImpl(mockStation) await authService.initialize() @@ -117,13 +87,7 @@ await describe('OCPPAuthServiceImpl', async () => { }) await it('should check if identifier type is supported for OCPP 2.0', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-006]', - stationInfo: { - chargingStationId: 'TEST-CS-006', - ocppVersion: OCPPVersion.VERSION_20, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('006', OCPPVersion.VERSION_20) const authService = new OCPPAuthServiceImpl(mockStation) await authService.initialize() @@ -140,13 +104,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('testConnectivity', async () => { await it('should test remote connectivity', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-007]', - stationInfo: { - chargingStationId: 'TEST-CS-007', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('007') const authService = new OCPPAuthServiceImpl(mockStation) const isConnected = await authService.testConnectivity() @@ -157,13 +115,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('clearCache', async () => { await it('should clear authorization cache', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-008]', - stationInfo: { - chargingStationId: 'TEST-CS-008', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('008') const authService = new OCPPAuthServiceImpl(mockStation) @@ -173,13 +125,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('invalidateCache', async () => { await it('should invalidate cache for specific identifier', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-009]', - stationInfo: { - chargingStationId: 'TEST-CS-009', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('009') const authService = new OCPPAuthServiceImpl(mockStation) @@ -195,13 +141,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('getStats', async () => { await it('should return authentication statistics', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-010]', - stationInfo: { - chargingStationId: 'TEST-CS-010', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('010') const authService = new OCPPAuthServiceImpl(mockStation) const stats = await authService.getStats() @@ -216,13 +156,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('authorize', async () => { await it('should authorize identifier using strategy chain', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-011]', - stationInfo: { - chargingStationId: 'TEST-CS-011', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('011') const authService = new OCPPAuthServiceImpl(mockStation) @@ -246,13 +180,7 @@ await describe('OCPPAuthServiceImpl', async () => { }) await it('should return INVALID status when all strategies fail', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-012]', - stationInfo: { - chargingStationId: 'TEST-CS-012', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('012') const authService = new OCPPAuthServiceImpl(mockStation) @@ -277,13 +205,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('isLocallyAuthorized', async () => { await it('should check local authorization', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-013]', - stationInfo: { - chargingStationId: 'TEST-CS-013', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('013') const authService = new OCPPAuthServiceImpl(mockStation) @@ -302,13 +224,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('OCPP version specific behavior', async () => { await it('should handle OCPP 1.6 specific identifiers', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-014]', - stationInfo: { - chargingStationId: 'TEST-CS-014', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('014') const authService = new OCPPAuthServiceImpl(mockStation) @@ -330,13 +246,7 @@ await describe('OCPPAuthServiceImpl', async () => { }) await it('should handle OCPP 2.0 specific identifiers', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-015]', - stationInfo: { - chargingStationId: 'TEST-CS-015', - ocppVersion: OCPPVersion.VERSION_20, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('015', OCPPVersion.VERSION_20) const authService = new OCPPAuthServiceImpl(mockStation) @@ -360,13 +270,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('error handling', async () => { await it('should handle invalid identifier gracefully', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-016]', - stationInfo: { - chargingStationId: 'TEST-CS-016', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('016') const authService = new OCPPAuthServiceImpl(mockStation) @@ -390,13 +294,7 @@ await describe('OCPPAuthServiceImpl', async () => { await describe('authentication contexts', async () => { await it('should handle TRANSACTION_START context', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-017]', - stationInfo: { - chargingStationId: 'TEST-CS-017', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('017') const authService = new OCPPAuthServiceImpl(mockStation) @@ -419,13 +317,7 @@ await describe('OCPPAuthServiceImpl', async () => { }) await it('should handle TRANSACTION_STOP context', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-018]', - stationInfo: { - chargingStationId: 'TEST-CS-018', - ocppVersion: OCPPVersion.VERSION_16, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('018') const authService = new OCPPAuthServiceImpl(mockStation) @@ -448,13 +340,7 @@ await describe('OCPPAuthServiceImpl', async () => { }) await it('should handle REMOTE_START context', async () => { - const mockStation = { - logPrefix: () => '[TEST-CS-019]', - stationInfo: { - chargingStationId: 'TEST-CS-019', - ocppVersion: OCPPVersion.VERSION_20, - }, - } as unknown as ChargingStation + const mockStation = createMockAuthServiceTestStation('019', OCPPVersion.VERSION_20) const authService = new OCPPAuthServiceImpl(mockStation)