* @file Tests for OCPP20RequestService BootNotification
* @description Unit tests for OCPP 2.0 BootNotification request building (B01)
*/
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-explicit-any */
-
import { expect } from '@std/expect'
import { afterEach, describe, it, mock } from 'node:test'
TEST_CHARGING_STATION_BASE_NAME,
TEST_FIRMWARE_VERSION,
} from '../../ChargingStationTestConstants.js'
+import { createTestableOCPP20RequestService } from './OCPP20TestUtils.js'
await describe('B01 - Cold Boot Charging Station', async () => {
afterEach(() => {
const mockResponseService = new OCPP20ResponseService()
const requestService = new OCPP20RequestService(mockResponseService)
+ const testableRequestService = createTestableOCPP20RequestService(requestService)
const mockChargingStation = createChargingStation({
baseName: TEST_CHARGING_STATION_BASE_NAME,
reason: BootReasonEnumType.PowerUp,
}
- // Access the private buildRequestPayload method via type assertion
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.BOOT_NOTIFICATION,
requestParams
- )
+ ) as OCPP20BootNotificationRequest
expect(payload).toBeDefined()
expect(payload.chargingStation).toBeDefined()
reason: BootReasonEnumType.ApplicationReset,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.BOOT_NOTIFICATION,
requestParams
- )
+ ) as OCPP20BootNotificationRequest
expect(payload).toBeDefined()
expect(payload.chargingStation).toBeDefined()
reason: BootReasonEnumType.FirmwareUpdate,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.BOOT_NOTIFICATION,
requestParams
- )
+ ) as OCPP20BootNotificationRequest
expect(payload).toBeDefined()
expect(payload.chargingStation).toBeDefined()
reason,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.BOOT_NOTIFICATION,
requestParams
- )
+ ) as OCPP20BootNotificationRequest
expect(payload).toBeDefined()
expect(payload.reason).toBe(reason)
reason: BootReasonEnumType.PowerUp,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.BOOT_NOTIFICATION,
requestParams
- )
+ ) as OCPP20BootNotificationRequest
// Validate that the payload has the exact structure of OCPP20BootNotificationRequest
expect(typeof payload).toBe('object')
* @file Tests for OCPP20RequestService HeartBeat
* @description Unit tests for OCPP 2.0 Heartbeat request building (G02)
*/
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-explicit-any */
-
import { expect } from '@std/expect'
import { afterEach, describe, it, mock } from 'node:test'
TEST_CHARGING_STATION_BASE_NAME,
TEST_FIRMWARE_VERSION,
} from '../../ChargingStationTestConstants.js'
+import { createTestableOCPP20RequestService } from './OCPP20TestUtils.js'
await describe('G02 - Heartbeat', async () => {
afterEach(() => {
})
const mockResponseService = new OCPP20ResponseService()
const requestService = new OCPP20RequestService(mockResponseService)
+ const testableRequestService = createTestableOCPP20RequestService(requestService)
const mockChargingStation = createChargingStation({
baseName: TEST_CHARGING_STATION_BASE_NAME,
await it('should build HeartBeat request payload correctly with empty object', () => {
const requestParams: OCPP20HeartbeatRequest = {}
- // Access the private buildRequestPayload method via type assertion
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.HEARTBEAT,
requestParams
// FR: G02.FR.02
await it('should build HeartBeat request payload correctly without parameters', () => {
// Test without passing any request parameters
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.HEARTBEAT
)
await it('should validate payload structure matches OCPP20HeartbeatRequest interface', () => {
const requestParams: OCPP20HeartbeatRequest = {}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.HEARTBEAT,
requestParams
const requestParams: OCPP20HeartbeatRequest = {}
// Call buildRequestPayload multiple times to ensure consistency
- const payload1 = (requestService as any).buildRequestPayload(
+ const payload1 = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.HEARTBEAT,
requestParams
)
- const payload2 = (requestService as any).buildRequestPayload(
+ const payload2 = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.HEARTBEAT,
requestParams
)
- const payload3 = (requestService as any).buildRequestPayload(
+ const payload3 = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.HEARTBEAT
)
const requestParams: OCPP20HeartbeatRequest = {}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
alternativeChargingStation,
OCPP20RequestCommand.HEARTBEAT,
requestParams
await it('should build empty HeartBeat request conforming to OCPP 2.0 specification', () => {
const requestParams: OCPP20HeartbeatRequest = {}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.HEARTBEAT,
requestParams
* @file Tests for OCPP20RequestService StatusNotification
* @description Unit tests for OCPP 2.0 StatusNotification request building (G01)
*/
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-explicit-any */
-
import { expect } from '@std/expect'
import { afterEach, describe, it, mock } from 'node:test'
TEST_STATUS_CHARGE_POINT_VENDOR,
TEST_STATUS_CHARGING_STATION_BASE_NAME,
} from '../../ChargingStationTestConstants.js'
+import { createTestableOCPP20RequestService } from './OCPP20TestUtils.js'
await describe('G01 - Status Notification', async () => {
afterEach(() => {
})
const mockResponseService = new OCPP20ResponseService()
const requestService = new OCPP20RequestService(mockResponseService)
+ const testableRequestService = createTestableOCPP20RequestService(requestService)
const mockChargingStation = createChargingStation({
baseName: TEST_STATUS_CHARGING_STATION_BASE_NAME,
timestamp: testTimestamp,
}
- // Access the private buildRequestPayload method via type assertion
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParams
- )
+ ) as OCPP20StatusNotificationRequest
expect(payload).toBeDefined()
expect(payload.connectorId).toBe(1)
timestamp: testTimestamp,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParams
- )
+ ) as OCPP20StatusNotificationRequest
expect(payload).toBeDefined()
expect(payload.connectorId).toBe(2)
timestamp: testTimestamp,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParams
- )
+ ) as OCPP20StatusNotificationRequest
expect(payload).toBeDefined()
expect(payload.connectorId).toBe(1)
timestamp: testTimestamp,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParams
- )
+ ) as OCPP20StatusNotificationRequest
expect(payload).toBeDefined()
expect(payload.connectorStatus).toBe(status)
timestamp: testTimestamp,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParams
- )
+ ) as OCPP20StatusNotificationRequest
// Validate that the payload has the exact structure of OCPP20StatusNotificationRequest
expect(typeof payload).toBe('object')
timestamp: testTimestamp,
}
- const payloadConnector0 = (requestService as any).buildRequestPayload(
+ const payloadConnector0 = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParamsConnector0
- )
+ ) as OCPP20StatusNotificationRequest
expect(payloadConnector0).toBeDefined()
expect(payloadConnector0.connectorId).toBe(0)
timestamp: testTimestamp,
}
- const payloadEvse0 = (requestService as any).buildRequestPayload(
+ const payloadEvse0 = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParamsEvse0
- )
+ ) as OCPP20StatusNotificationRequest
expect(payloadEvse0).toBeDefined()
expect(payloadEvse0.connectorId).toBe(1)
new Date('2024-06-15T12:30:45.678Z'), // Mid-year with milliseconds
]
- testCases.forEach((timestamp, index) => {
+ testCases.forEach((timestamp, _index) => {
const requestParams: OCPP20StatusNotificationRequest = {
connectorId: 1,
connectorStatus: OCPP20ConnectorStatusEnumType.Available,
timestamp,
}
- const payload = (requestService as any).buildRequestPayload(
+ const payload = testableRequestService.buildRequestPayload(
mockChargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
requestParams
- )
+ ) as OCPP20StatusNotificationRequest
expect(payload).toBeDefined()
expect(payload.timestamp).toBe(timestamp)
import type { ChargingStation } from '../../../../src/charging-station/ChargingStation.js'
+import type { OCPP20RequestService } from '../../../../src/charging-station/ocpp/2.0/OCPP20RequestService.js'
import type { ConfigurationKey } from '../../../../src/types/ChargingStationOcppConfiguration.js'
import type { EmptyObject } from '../../../../src/types/EmptyObject.js'
+import type { JsonType, OCPP20RequestCommand } from '../../../../src/types/index.js'
import {
ConnectorStatusEnum,
import { createChargingStation } from '../../../ChargingStationFactory.js'
import { TEST_CHARGING_STATION_BASE_NAME } from '../../ChargingStationTestConstants.js'
+// ============================================================================
+// Testable Interfaces
+// ============================================================================
+// These interfaces provide type-safe access to private methods for testing
+// purposes, eliminating the need for `as any` casts and eslint-disable comments.
+// ============================================================================
+
+/**
+ * Interface exposing private methods of OCPP20RequestService for testing.
+ * This allows type-safe testing without `as any` casts.
+ */
+export interface TestableOCPP20RequestService {
+ /**
+ * Build a request payload for the given OCPP 2.0 command.
+ * Exposes the private `buildRequestPayload` method for testing.
+ * @param chargingStation - The charging station instance
+ * @param commandName - The OCPP 2.0 request command
+ * @param commandParams - Optional command parameters
+ * @returns The built request payload
+ */
+ buildRequestPayload: (
+ chargingStation: ChargingStation,
+ commandName: OCPP20RequestCommand,
+ commandParams?: JsonType
+ ) => JsonType
+}
+
/**
* Create a mock ChargingStation for OCPP 2.0 transaction event testing.
* Provides standard configuration used across all transaction event test files.
})
}
+/**
+ * Create a testable wrapper for OCPP20RequestService that exposes private methods.
+ *
+ * This function provides type-safe access to private methods that need to be tested,
+ * following the pattern recommended in TEST_STYLE_GUIDE.md to avoid `as any` casts.
+ * @param requestService - The OCPP20RequestService instance to wrap
+ * @returns A testable interface with access to private methods
+ * @example
+ * ```typescript
+ * const testable = createTestableOCPP20RequestService(requestService)
+ * const payload = testable.buildRequestPayload(station, OCPP20RequestCommand.HEARTBEAT)
+ * ```
+ */
+export function createTestableOCPP20RequestService (
+ requestService: OCPP20RequestService
+): TestableOCPP20RequestService {
+ // Use type assertion at the boundary only, providing type-safe interface to tests
+ const service = requestService as unknown as {
+ buildRequestPayload: TestableOCPP20RequestService['buildRequestPayload']
+ }
+ return {
+ buildRequestPayload: service.buildRequestPayload.bind(requestService),
+ }
+}
+
/**
* Reset connector transaction state for all connectors in the charging station.
* This ensures test isolation by clearing any transaction state from previous tests.