createMockChargingStation,
createMockChargingStationTemplate,
resetChargingStationState,
- waitForCondition,
} from './helpers/StationHelpers.js'
export { MockIdTagsCache, MockSharedLRUCache } from './mocks/MockCaches.js'
}
}
-/**
- * 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<void> {
- 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
/**
* 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
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)
}
/**
* 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<string, ChargingStationConfiguration>()
- private readonly templates = new Map<string, ChargingStationTemplate>()
+ private readonly _brand = 'MockSharedLRUCache' as const
public static getInstance (): MockSharedLRUCache {
MockSharedLRUCache.instance ??= new 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)
- }
- }
}
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
import { createMockChargingStation } from '../../ChargingStationTestUtils.js'
import {
type CapturedOCPPRequest,
- createMockOCPP20TransactionTestStation,
createMockStationWithRequestTracking,
type MockStationWithTracking,
resetConnectorTransactionState,
resetLimits,
TransactionContextFixtures,
} from './OCPP20TestUtils.js'
-
// ============================================================================
// Transaction Flow Patterns for Parameterized Testing
// ============================================================================
] as const
await describe('E01-E04 - OCPP 2.0.1 TransactionEvent Implementation', async () => {
- let mockChargingStation: ReturnType<typeof createMockOCPP20TransactionTestStation>
+ 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)
})
afterEach(() => {
standardCleanup()
})
-
// FR: E01.FR.01 - TransactionEventRequest structure validation
await describe('buildTransactionEvent', async () => {
await it('should build valid TransactionEvent Started with sequence number 0', () => {
) => 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.
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')
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.
*/
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()
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()
})
},
})
- const server = new UIWebSocketServer(config)
+ const server = new TestableUIWebSocketServer(config)
expect(server).toBeDefined()
})
})
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()