From 7cd70f39190b6f1ddab9a27ea2c8b54cbe2ab634 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 27 Feb 2026 17:51:41 +0100 Subject: [PATCH] refactor(tests): reduce eslint-disable comments with proper typing - Add MockOCPPRequestService and MockOCPPIncomingRequestService interfaces - Export TestChargingStation type for typed mock service access - Remove 14 eslint-disable comments from ChargingStationFactory.test.ts - Remove 4 eslint-disable comments from ConfigurationKeyUtils.test.ts - Use Partial for missing config tests Remaining 43 inline eslint-disable comments are all legitimate: - no-empty-function: Testing empty callbacks - require-await: Mock async implementations - no-explicit-any: Testing validators with invalid inputs --- tests/ChargingStationFactory.test.ts | 44 +++++-------------- tests/ChargingStationFactory.ts | 44 ++++++++++++++++--- .../ConfigurationKeyUtils.test.ts | 19 ++++---- 3 files changed, 59 insertions(+), 48 deletions(-) diff --git a/tests/ChargingStationFactory.test.ts b/tests/ChargingStationFactory.test.ts index b3b38090..a842c4e8 100644 --- a/tests/ChargingStationFactory.test.ts +++ b/tests/ChargingStationFactory.test.ts @@ -14,10 +14,7 @@ await describe('ChargingStationFactory', async () => { await it('Should throw error when OCPPRequestService.requestHandler is not mocked', async () => { const station = createChargingStation({ connectorsCount: 1 }) - await expect( - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - (station as any).ocppRequestService.requestHandler() - ).rejects.toThrow( + await expect(station.ocppRequestService.requestHandler()).rejects.toThrow( 'ocppRequestService.requestHandler not mocked. Define in createChargingStation options.' ) }) @@ -26,8 +23,7 @@ await describe('ChargingStationFactory', async () => { const station = createChargingStation({ connectorsCount: 1 }) expect(() => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - ;(station as any).ocppIncomingRequestService.stop() + station.ocppIncomingRequestService.stop() }).toThrow( 'ocppIncomingRequestService.stop not mocked. Define in createChargingStation options.' ) @@ -45,9 +41,7 @@ await describe('ChargingStationFactory', async () => { }, }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - const result = await (station as any).ocppRequestService.requestHandler() - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const result = (await station.ocppRequestService.requestHandler()) as { success: boolean } expect(result.success).toBe(true) }) @@ -62,18 +56,14 @@ await describe('ChargingStationFactory', async () => { }, }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - ;(station as any).ocppIncomingRequestService.stop() + station.ocppIncomingRequestService.stop() expect(stopCalled).toBe(true) }) await it('Should throw error when OCPPRequestService.sendError is not mocked', async () => { const station = createChargingStation({ connectorsCount: 1 }) - await expect( - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - (station as any).ocppRequestService.sendError() - ).rejects.toThrow( + await expect(station.ocppRequestService.sendError()).rejects.toThrow( 'ocppRequestService.sendError not mocked. Define in createChargingStation options.' ) }) @@ -81,10 +71,7 @@ await describe('ChargingStationFactory', async () => { await it('Should throw error when OCPPRequestService.sendResponse is not mocked', async () => { const station = createChargingStation({ connectorsCount: 1 }) - await expect( - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - (station as any).ocppRequestService.sendResponse() - ).rejects.toThrow( + await expect(station.ocppRequestService.sendResponse()).rejects.toThrow( 'ocppRequestService.sendResponse not mocked. Define in createChargingStation options.' ) }) @@ -101,9 +88,7 @@ await describe('ChargingStationFactory', async () => { }, }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - const result = await (station as any).ocppRequestService.sendError() - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const result = (await station.ocppRequestService.sendError()) as { error: string } expect(result.error).toBe('test-error') }) @@ -119,19 +104,14 @@ await describe('ChargingStationFactory', async () => { }, }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - const result = await (station as any).ocppRequestService.sendResponse() - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const result = (await station.ocppRequestService.sendResponse()) as { response: string } expect(result.response).toBe('test-response') }) await it('Should throw error when OCPPIncomingRequestService.incomingRequestHandler is not mocked', async () => { const station = createChargingStation({ connectorsCount: 1 }) - await expect( - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - (station as any).ocppIncomingRequestService.incomingRequestHandler() - ).rejects.toThrow( + await expect(station.ocppIncomingRequestService.incomingRequestHandler()).rejects.toThrow( 'ocppIncomingRequestService.incomingRequestHandler not mocked. Define in createChargingStation options.' ) }) @@ -148,9 +128,9 @@ await describe('ChargingStationFactory', async () => { }, }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - const result = await (station as any).ocppIncomingRequestService.incomingRequestHandler() - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const result = (await station.ocppIncomingRequestService.incomingRequestHandler()) as { + handled: boolean + } expect(result.handled).toBe(true) }) }) diff --git a/tests/ChargingStationFactory.ts b/tests/ChargingStationFactory.ts index 5ade13e4..4b3f3038 100644 --- a/tests/ChargingStationFactory.ts +++ b/tests/ChargingStationFactory.ts @@ -43,23 +43,51 @@ export interface ChargingStationOptions { heartbeatInterval?: number ocppConfiguration?: ChargingStationConfiguration /** Custom OCPP incoming request service for test mocking */ - ocppIncomingRequestService?: unknown + ocppIncomingRequestService?: Partial /** Custom OCPP request service for test mocking */ - ocppRequestService?: unknown + ocppRequestService?: Partial started?: boolean starting?: boolean stationInfo?: Partial websocketPingInterval?: number } +/** + * Mock OCPP incoming request service interface for testing + * Provides typed access to mock handlers without eslint-disable comments + */ +export interface MockOCPPIncomingRequestService { + incomingRequestHandler: () => Promise + stop: () => void +} + +/** + * Mock OCPP request service interface for testing + * Provides typed access to mock handlers without eslint-disable comments + */ +export interface MockOCPPRequestService { + requestHandler: () => Promise + sendError: () => Promise + sendResponse: () => Promise +} + +/** + * Test-specific ChargingStation interface exposing mock services + * Allows typed access to mock OCPP services in tests + */ +export interface TestChargingStation extends ChargingStation { + ocppIncomingRequestService: MockOCPPIncomingRequestService + ocppRequestService: MockOCPPRequestService +} + const CHARGING_STATION_BASE_NAME = 'CS-TEST' /** * Creates a ChargingStation instance for tests * @param options - Configuration options for the charging station - * @returns ChargingStation instance configured for testing + * @returns TestChargingStation instance configured for testing */ -export function createChargingStation (options: ChargingStationOptions = {}): ChargingStation { +export function createChargingStation (options: ChargingStationOptions = {}): TestChargingStation { const baseName = options.baseName ?? CHARGING_STATION_BASE_NAME const templateIndex = 1 const connectionTimeout = options.connectionTimeout ?? Constants.DEFAULT_CONNECTION_TIMEOUT @@ -198,7 +226,7 @@ export function createChargingStation (options: ChargingStationOptions = {}): Ch ], ...options.ocppConfiguration, }, - ocppIncomingRequestService: options.ocppIncomingRequestService ?? { + ocppIncomingRequestService: { incomingRequestHandler: async () => { return await Promise.reject( new Error( @@ -211,8 +239,9 @@ export function createChargingStation (options: ChargingStationOptions = {}): Ch 'ocppIncomingRequestService.stop not mocked. Define in createChargingStation options.' ) }, + ...options.ocppIncomingRequestService, }, - ocppRequestService: options.ocppRequestService ?? { + ocppRequestService: { requestHandler: async () => { return await Promise.reject( new Error( @@ -234,6 +263,7 @@ export function createChargingStation (options: ChargingStationOptions = {}): Ch ) ) }, + ...options.ocppRequestService, }, restartHeartbeat: (): void => { /* no-op for tests */ @@ -270,7 +300,7 @@ export function createChargingStation (options: ChargingStationOptions = {}): Ch stopTxUpdatedInterval: (_connectorId: number): void => { /* no-op for tests */ }, - } as unknown as ChargingStation + } as unknown as TestChargingStation return chargingStation } diff --git a/tests/charging-station/ConfigurationKeyUtils.test.ts b/tests/charging-station/ConfigurationKeyUtils.test.ts index 7c9474d8..031f92a6 100644 --- a/tests/charging-station/ConfigurationKeyUtils.test.ts +++ b/tests/charging-station/ConfigurationKeyUtils.test.ts @@ -5,6 +5,8 @@ import { expect } from '@std/expect' import { describe, it } from 'node:test' +import type { ChargingStationOcppConfiguration } from '../../src/types/index.js' + import { addConfigurationKey, deleteConfigurationKey, @@ -23,9 +25,8 @@ await describe('ConfigurationKeyUtils test suite', async () => { await describe('getConfigurationKey()', async () => { await it('should return undefined when configurationKey array is missing', () => { const cs = createChargingStation() - // remove array - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment - cs.ocppConfiguration = {} as any + // Simulate missing configurationKey array + cs.ocppConfiguration = {} as Partial expect(getConfigurationKey(cs, TEST_KEY_1)).toBeUndefined() }) @@ -54,8 +55,8 @@ await describe('ConfigurationKeyUtils test suite', async () => { await describe('addConfigurationKey()', async () => { await it('should no-op when configurationKey array missing', () => { const cs = createChargingStation() - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment - cs.ocppConfiguration = {} as any + // Simulate missing configurationKey array + cs.ocppConfiguration = {} as Partial addConfigurationKey(cs, TEST_KEY_1, VALUE_A) expect(getConfigurationKey(cs, TEST_KEY_1)).toBeUndefined() }) @@ -214,8 +215,8 @@ await describe('ConfigurationKeyUtils test suite', async () => { await it('should return undefined without logging when configurationKey array missing', t => { const cs = createChargingStation() - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment - cs.ocppConfiguration = {} as any + // Simulate missing configurationKey array + cs.ocppConfiguration = {} as Partial const errorMock = t.mock.method(logger, 'error') const res = setConfigurationKeyValue(cs, TEST_KEY_1, VALUE_A) expect(res).toBeUndefined() @@ -242,8 +243,8 @@ await describe('ConfigurationKeyUtils test suite', async () => { await describe('deleteConfigurationKey()', async () => { await it('should return undefined when configurationKey array missing', () => { const cs = createChargingStation() - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment - cs.ocppConfiguration = {} as any + // Simulate missing configurationKey array + cs.ocppConfiguration = {} as Partial const res = deleteConfigurationKey(cs, TEST_KEY_1) expect(res).toBeUndefined() }) -- 2.53.0