From 36e2baf081242c609907d616b2945a9ead9d6fdd Mon Sep 17 00:00:00 2001 From: Nerivec <62446222+Nerivec@users.noreply.github.com> Date: Mon, 14 Apr 2025 21:51:01 +0200 Subject: [PATCH] fix: Use Map for State (#27105) --- lib/eventBus.ts | 2 +- lib/extension/availability.ts | 10 ++--- lib/extension/bind.ts | 2 +- lib/extension/groups.ts | 2 +- lib/extension/homeassistant.ts | 2 +- lib/extension/networkMap.ts | 6 +-- lib/mqtt.ts | 2 +- lib/state.ts | 54 +++++++++++++--------- lib/util/settingsMigration.ts | 2 +- lib/zigbee.ts | 4 +- test/controller.test.ts | 74 ++++++++++++++----------------- test/extensions/bridge.test.ts | 4 +- test/extensions/groups.test.ts | 4 +- test/extensions/otaUpdate.test.ts | 2 +- test/extensions/publish.test.ts | 2 +- test/extensions/receive.test.ts | 2 +- 16 files changed, 89 insertions(+), 85 deletions(-) diff --git a/lib/eventBus.ts b/lib/eventBus.ts index b781913f2..a2fa90435 100644 --- a/lib/eventBus.ts +++ b/lib/eventBus.ts @@ -35,7 +35,7 @@ type EventBusListener = K extends keyof EventBusMap : never; export default class EventBus { - private callbacksByExtension: Map}[]> = new Map(); + private callbacksByExtension = new Map}[]>(); private emitter = new events.EventEmitter(); constructor() { diff --git a/lib/extension/availability.ts b/lib/extension/availability.ts index 380d420ee..feb735390 100644 --- a/lib/extension/availability.ts +++ b/lib/extension/availability.ts @@ -20,15 +20,15 @@ const RETRIEVE_ON_RECONNECT: readonly {keys: string[]; condition?: (state: KeyVa export default class Availability extends Extension { /** Mapped by IEEE address */ - private readonly timers: Map = new Map(); + private readonly timers = new Map(); /** Mapped by IEEE address or Group ID */ - private readonly lastPublishedAvailabilities: Map = new Map(); + private readonly lastPublishedAvailabilities = new Map(); /** Mapped by IEEE address */ - private readonly pingBackoffs: Map = new Map(); + private readonly pingBackoffs = new Map(); /** IEEE addresses, waiting for last seen changes to take them out of "availability sleep" */ - private readonly backoffPausedDevices: Set = new Set(); + private readonly backoffPausedDevices = new Set(); /** Mapped by IEEE address */ - private readonly retrieveStateDebouncers: Map void> = new Map(); + private readonly retrieveStateDebouncers = new Map void>(); private pingQueue: Device[] = []; private pingQueueExecuting = false; private stopped = false; diff --git a/lib/extension/bind.ts b/lib/extension/bind.ts index 44f4b0c11..860b6b59e 100755 --- a/lib/extension/bind.ts +++ b/lib/extension/bind.ts @@ -567,7 +567,7 @@ export default class Bind extends Extension { ); if (polls.length) { - const toPoll: Set = new Set(); + const toPoll = new Set(); // Add bound devices for (const endpoint of data.device.zh.endpoints) { diff --git a/lib/extension/groups.ts b/lib/extension/groups.ts index e9f465445..767a96b54 100644 --- a/lib/extension/groups.ts +++ b/lib/extension/groups.ts @@ -106,7 +106,7 @@ export default class Groups extends Extension { // Invalidate the last optimistic group state when group state is changed directly. delete this.lastOptimisticState[entity.ID]; - const groupsToPublish: Set = new Set(); + const groupsToPublish = new Set(); for (const member of entity.zh.members) { const device = this.zigbee.resolveEntity(member.getDevice()) as Device; diff --git a/lib/extension/homeassistant.ts b/lib/extension/homeassistant.ts index fec4533ff..d060093fa 100644 --- a/lib/extension/homeassistant.ts +++ b/lib/extension/homeassistant.ts @@ -1472,7 +1472,7 @@ export class HomeAssistant extends Extension { const discovered = this.getDiscovered(entity); discovered.discovered = true; const lastDiscoveredTopics = Object.keys(discovered.messages); - const newDiscoveredTopics: Set = new Set(); + const newDiscoveredTopics = new Set(); for (const config of this.getConfigs(entity)) { const payload = {...config.discovery_payload}; diff --git a/lib/extension/networkMap.ts b/lib/extension/networkMap.ts index 3092a8564..59fd7bf88 100644 --- a/lib/extension/networkMap.ts +++ b/lib/extension/networkMap.ts @@ -185,9 +185,9 @@ export default class NetworkMap extends Extension { async networkScan(includeRoutes: boolean): Promise { logger.info(`Starting network scan (includeRoutes '${includeRoutes}')`); - const lqis: Map = new Map(); - const routingTables: Map = new Map(); - const failed: Map = new Map(); + const lqis = new Map(); + const routingTables = new Map(); + const failed = new Map(); const requestWithRetry = async (request: () => Promise): Promise => { try { const result = await request(); diff --git a/lib/mqtt.ts b/lib/mqtt.ts index 099cd9244..9063ce84a 100644 --- a/lib/mqtt.ts +++ b/lib/mqtt.ts @@ -14,7 +14,7 @@ import utils from './util/utils'; const NS = 'z2m:mqtt'; export default class MQTT { - private publishedTopics: Set = new Set(); + private publishedTopics = new Set(); private connectionTimer?: NodeJS.Timeout; private client!: MqttClient; private eventBus: EventBus; diff --git a/lib/state.ts b/lib/state.ts index b840ae7d6..c5d5518d2 100644 --- a/lib/state.ts +++ b/lib/state.ts @@ -1,4 +1,4 @@ -import fs from 'node:fs'; +import {existsSync, readFileSync, writeFileSync} from 'node:fs'; import objectAssignDeep from 'object-assign-deep'; @@ -7,9 +7,8 @@ import logger from './util/logger'; import * as settings from './util/settings'; import utils from './util/utils'; -const saveInterval = 1000 * 60 * 5; // 5 minutes - -const dontCacheProperties = [ +const SAVE_INTERVAL = 1000 * 60 * 5; // 5 minutes +const CACHE_IGNORE_PROPERTIES = [ 'action', 'action_.*', 'button', @@ -32,8 +31,8 @@ const dontCacheProperties = [ ]; class State { - private state: {[s: string | number]: KeyValue} = {}; - private file = data.joinPath('state.json'); + private readonly state = new Map(); + private readonly file = data.joinPath('state.json'); private timer?: NodeJS.Timeout; constructor( @@ -48,15 +47,15 @@ class State { this.load(); // Save the state on every interval - this.timer = setInterval(() => this.save(), saveInterval); + this.timer = setInterval(() => this.save(), SAVE_INTERVAL); } stop(): void { // Remove any invalid states (ie when the device has left the network) when the system is stopped - for (const key in this.state) { - if (typeof key === 'string' && !this.zigbee.resolveEntity(key)) { + for (const [key] of this.state) { + if (typeof key === 'string' && key.startsWith('0x') && !this.zigbee.resolveEntity(key)) { // string key = ieeeAddr - delete this.state[key]; + this.state.delete(key); } } @@ -64,10 +63,21 @@ class State { this.save(); } + clear(): void { + this.state.clear(); + } + private load(): void { - if (fs.existsSync(this.file)) { + this.state.clear(); + + if (existsSync(this.file)) { try { - this.state = JSON.parse(fs.readFileSync(this.file, 'utf8')); + const stateObj = JSON.parse(readFileSync(this.file, 'utf8')) as KeyValue; + + for (const key in stateObj) { + this.state.set(key.startsWith('0x') ? key : Number.parseInt(key, 10), stateObj[key]); + } + logger.debug(`Loaded state from file ${this.file}`); } catch (error) { logger.debug(`Failed to load state from file ${this.file} (corrupt file?) (${(error as Error).message})`); @@ -80,9 +90,11 @@ class State { private save(): void { if (settings.get().advanced.cache_state_persistent) { logger.debug(`Saving state to file ${this.file}`); - const json = JSON.stringify(this.state, null, 4); + + const json = JSON.stringify(Object.fromEntries(this.state), null, 4); + try { - fs.writeFileSync(this.file, json, 'utf8'); + writeFileSync(this.file, json, 'utf8'); } catch (error) { logger.error(`Failed to write state to '${this.file}' (${error})`); } @@ -92,28 +104,28 @@ class State { } exists(entity: Device | Group): boolean { - return this.state[entity.ID] !== undefined; + return this.state.has(entity.ID); } get(entity: Group | Device): KeyValue { - return this.state[entity.ID] || {}; + return this.state.get(entity.ID) || {}; } set(entity: Group | Device, update: KeyValue, reason?: string): KeyValue { - const fromState = this.state[entity.ID] || {}; + const fromState = this.state.get(entity.ID) || {}; const toState = objectAssignDeep({}, fromState, update); const newCache = {...toState}; const entityDontCacheProperties = entity.options.filtered_cache || []; - utils.filterProperties(dontCacheProperties.concat(entityDontCacheProperties), newCache); + utils.filterProperties(CACHE_IGNORE_PROPERTIES.concat(entityDontCacheProperties), newCache); - this.state[entity.ID] = newCache; + this.state.set(entity.ID, newCache); this.eventBus.emitStateChange({entity, from: fromState, to: toState, reason, update}); return toState; } - remove(ID: string | number): void { - delete this.state[ID]; + remove(ID: string | number): boolean { + return this.state.delete(ID); } } diff --git a/lib/util/settingsMigration.ts b/lib/util/settingsMigration.ts index 3234eb112..3455db55c 100644 --- a/lib/util/settingsMigration.ts +++ b/lib/util/settingsMigration.ts @@ -510,7 +510,7 @@ export function migrateIfNecessary(): void { while (currentSettings.version !== finalVersion) { let migrationNotesFileName: string | undefined; // don't duplicate outputs - const migrationNotes: Set = new Set(); + const migrationNotes = new Set(); const transfers: SettingsTransfer[] = []; const changes: SettingsChange[] = []; const additions: SettingsAdd[] = []; diff --git a/lib/zigbee.ts b/lib/zigbee.ts index 2d7a672bf..2bb998e4e 100644 --- a/lib/zigbee.ts +++ b/lib/zigbee.ts @@ -21,8 +21,8 @@ export default class Zigbee { // @ts-expect-error initialized in start private herdsman: Controller; private eventBus: EventBus; - private groupLookup: Map = new Map(); - private deviceLookup: Map = new Map(); + private groupLookup = new Map(); + private deviceLookup = new Map(); constructor(eventBus: EventBus) { this.eventBus = eventBus; diff --git a/test/controller.test.ts b/test/controller.test.ts index 947c95300..1cdd1d529 100644 --- a/test/controller.test.ts +++ b/test/controller.test.ts @@ -13,6 +13,9 @@ import {devices, mockController as mockZHController, events as mockZHEvents, ret import type {Mock, MockInstance} from 'vitest'; +import type Device from '../lib/model/device'; +import type {Device as ZhDevice} from './mocks/zigbeeHerdsman'; + import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; @@ -54,6 +57,11 @@ describe('Controller', () => { let controller: Controller; let mockExit: Mock; + const getZ2MDevice = (zhDevice: string | number | ZhDevice): Device => { + // @ts-expect-error private + return controller.zigbee.resolveEntity(zhDevice)! as Device; + }; + beforeAll(async () => { vi.useFakeTimers(); }); @@ -64,7 +72,7 @@ describe('Controller', () => { data.writeDefaultConfiguration(); settings.reRead(); controller = new Controller(vi.fn(), mockExit); - mocksClear.forEach((m) => m.mockClear()); + for (const mock of mocksClear) mock.mockClear(); settings.reRead(); data.writeDefaultState(); }); @@ -264,8 +272,7 @@ describe('Controller', () => { mockLogger.error.mockClear(); // @ts-expect-error private controller.mqtt.client.reconnecting = true; - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb'); + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, { state: 'ON', brightness: 50, @@ -302,7 +309,7 @@ describe('Controller', () => { await controller.start(); await flushPromises(); // @ts-expect-error private - expect(controller.state.state).toStrictEqual({}); + expect(controller.state.state).toStrictEqual(new Map()); }); it('Should remove device not on passlist on startup', async () => { @@ -737,8 +744,7 @@ describe('Controller', () => { await controller.start(); settings.set(['advanced', 'output'], 'attribute'); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, { dummy: {1: 'yes', 2: 'no'}, color: {r: 100, g: 50, b: 10}, @@ -763,8 +769,7 @@ describe('Controller', () => { await controller.start(); settings.set(['advanced', 'output'], 'attribute_and_json'); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 99}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(5); @@ -784,8 +789,7 @@ describe('Controller', () => { settings.set(['advanced', 'output'], 'attribute_and_json'); settings.set(['devices', devices.bulb.ieeeAddr, 'filtered_attributes'], ['color_temp', 'linkquality']); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 99}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(3); @@ -799,8 +803,7 @@ describe('Controller', () => { settings.set(['advanced', 'output'], 'attribute_and_json'); settings.set(['device_options', 'filtered_attributes'], ['color_temp', 'linkquality']); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 99}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(3); @@ -815,16 +818,15 @@ describe('Controller', () => { settings.set(['devices', devices.bulb.ieeeAddr, 'filtered_cache'], ['linkquality']); mockMQTTPublishAsync.mockClear(); + const device = getZ2MDevice('bulb'); // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; - // @ts-expect-error private - expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'}); + expect(controller.state.get(device)).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'}); await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 87}); await flushPromises(); // @ts-expect-error private - expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'}); + expect(controller.state.get(device)).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'}); expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(5); expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/state', 'ON', {qos: 0, retain: true}); expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/brightness', '200', {qos: 0, retain: true}); @@ -842,16 +844,15 @@ describe('Controller', () => { settings.set(['device_options', 'filtered_cache'], ['linkquality']); mockMQTTPublishAsync.mockClear(); + const device = getZ2MDevice('bulb'); // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; - // @ts-expect-error private - expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'}); + expect(controller.state.get(device)).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'}); await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 87}); await flushPromises(); // @ts-expect-error private - expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'}); + expect(controller.state.get(device)).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'}); expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(5); expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/state', 'ON', {qos: 0, retain: true}); expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/brightness', '200', {qos: 0, retain: true}); @@ -867,8 +868,7 @@ describe('Controller', () => { await controller.start(); settings.set(['mqtt', 'include_device_information'], true); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - let device = controller.zigbee.resolveEntity('bulb')!; + let device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON'}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledWith( @@ -892,8 +892,7 @@ describe('Controller', () => { ); // Unsupported device should have model "unknown" - // @ts-expect-error private - device = controller.zigbee.resolveEntity('unsupported2')!; + device = getZ2MDevice('unsupported2'); await controller.publishEntityState(device, {state: 'ON'}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledWith( @@ -918,8 +917,7 @@ describe('Controller', () => { await controller.start(); settings.set(['devices', devices.bulb.ieeeAddr, 'retain'], false); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON'}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledWith( @@ -933,8 +931,7 @@ describe('Controller', () => { await controller.start(); settings.set(['devices', devices.bulb.ieeeAddr, 'retain'], true); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON'}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledWith( @@ -950,8 +947,7 @@ describe('Controller', () => { settings.set(['devices', devices.bulb.ieeeAddr, 'retain'], true); settings.set(['devices', devices.bulb.ieeeAddr, 'retention'], 37); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON'}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledWith( @@ -965,8 +961,7 @@ describe('Controller', () => { data.writeEmptyState(); await controller.start(); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {}); await flushPromises(); expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(0); @@ -977,8 +972,7 @@ describe('Controller', () => { data.removeState(); await controller.start(); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON'}); await controller.publishEntityState(device, {brightness: 200}); await flushPromises(); @@ -1005,8 +999,7 @@ describe('Controller', () => { data.writeEmptyState(); await controller.start(); mockMQTTPublishAsync.mockClear(); - // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; + const device = getZ2MDevice('bulb'); await controller.publishEntityState(device, {state: 'ON'}); await controller.publishEntityState(device, {brightness: 200}); await flushPromises(); @@ -1020,7 +1013,7 @@ describe('Controller', () => { await controller.start(); await flushPromises(); // @ts-expect-error private - expect(controller.state.state).toStrictEqual({}); + expect(controller.state.state).toStrictEqual(new Map()); }); it('Start controller with force_disable_retain', async () => { @@ -1120,14 +1113,13 @@ describe('Controller', () => { it('Should remove state of removed device when stopped', async () => { await controller.start(); + const device = getZ2MDevice('bulb'); // @ts-expect-error private - const device = controller.zigbee.resolveEntity('bulb')!; - // @ts-expect-error private - expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'}); + expect(controller.state.get(device)).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'}); device.zh.isDeleted = true; await controller.stop(); // @ts-expect-error private - expect(controller.state.state[device.ieeeAddr]).toStrictEqual(undefined); + expect(controller.state.state.get(device.ieeeAddr)).toStrictEqual(undefined); }); it('EventBus should handle errors', async () => { diff --git a/test/extensions/bridge.test.ts b/test/extensions/bridge.test.ts index 48f2e4b52..b62260202 100644 --- a/test/extensions/bridge.test.ts +++ b/test/extensions/bridge.test.ts @@ -78,7 +78,7 @@ describe('Extension: Bridge', () => { // @ts-expect-error private extension.restartRequired = false; // @ts-expect-error private - controller.state.state = {[devices.bulb.ieeeAddr]: {brightness: 50}}; + controller.state.state = new Map([[devices.bulb.ieeeAddr, {brightness: 50}]]); fs.rmSync(deviceIconsDir, {force: true, recursive: true}); }); @@ -2809,7 +2809,7 @@ describe('Extension: Bridge', () => { mockMQTTEvents.message('zigbee2mqtt/bridge/request/device/remove', 'bulb'); await flushPromises(); // @ts-expect-error private - expect(controller.state[device.ieeeAddr]).toBeUndefined(); + expect(controller.state.state.get(device.ieeeAddr)).toBeUndefined(); expect(device.removeFromNetwork).toHaveBeenCalledTimes(1); expect(device.removeFromDatabase).not.toHaveBeenCalled(); expect(settings.getDevice('bulb')).toBeUndefined(); diff --git a/test/extensions/groups.test.ts b/test/extensions/groups.test.ts index fe7458fae..514f7ba69 100644 --- a/test/extensions/groups.test.ts +++ b/test/extensions/groups.test.ts @@ -46,7 +46,7 @@ describe('Extension: Groups', () => { groups.gledopto_group.command.mockClear(); zhcGlobalStore.clear(); // @ts-expect-error private - controller.state.state = {}; + controller.state.clear(); }); it('Should publish group state change when a device in it changes state', async () => { @@ -461,7 +461,7 @@ describe('Extension: Groups', () => { await flushPromises(); mockMQTTPublishAsync.mockClear(); // @ts-expect-error private - controller.state.state = {}; + controller.state.clear(); await mockMQTTEvents.message('zigbee2mqtt/bulb_color/set', stringify({state: 'OFF'})); await flushPromises(); diff --git a/test/extensions/otaUpdate.test.ts b/test/extensions/otaUpdate.test.ts index 55eca0537..3188a1ad4 100644 --- a/test/extensions/otaUpdate.test.ts +++ b/test/extensions/otaUpdate.test.ts @@ -70,7 +70,7 @@ describe('Extension: OTAUpdate', () => { updateSpy.mockClear(); isUpdateAvailableSpy.mockClear(); // @ts-expect-error private - controller.state.state = {}; + controller.state.clear(); }); afterEach(() => { diff --git a/test/extensions/publish.test.ts b/test/extensions/publish.test.ts index b509db877..8f30c39d1 100644 --- a/test/extensions/publish.test.ts +++ b/test/extensions/publish.test.ts @@ -43,7 +43,7 @@ describe('Extension: Publish', () => { beforeEach(async () => { data.writeDefaultConfiguration(); // @ts-expect-error private - controller.state.state = {}; + controller.state.clear(); settings.reRead(); loadTopicGetSetRegex(); mocksClear.forEach((m) => m.mockClear()); diff --git a/test/extensions/receive.test.ts b/test/extensions/receive.test.ts index 9a8cd8439..a7720bf9e 100644 --- a/test/extensions/receive.test.ts +++ b/test/extensions/receive.test.ts @@ -25,7 +25,7 @@ describe('Extension: Receive', () => { beforeEach(async () => { // @ts-expect-error private - controller.state.state = {}; + controller.state.clear(); data.writeDefaultConfiguration(); settings.reRead(); mocksClear.forEach((m) => m.mockClear());