From f571938efcce16442638cf23376fbee8d1dee45b Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Wed, 21 Jul 2021 22:14:33 +0200 Subject: [PATCH] Migrate settings.js to TypeScript. --- lib/types/types.ts | 108 ++++++++++++ lib/util/{settings.js => settings.ts} | 238 ++++++++++++-------------- lib/util/yaml.ts | 13 +- npm-shrinkwrap.json | 6 + package.json | 1 + test/settings.test.js | 16 +- 6 files changed, 240 insertions(+), 142 deletions(-) create mode 100644 lib/types/types.ts rename lib/util/{settings.js => settings.ts} (77%) diff --git a/lib/types/types.ts b/lib/types/types.ts new file mode 100644 index 000000000..df8ec8d2b --- /dev/null +++ b/lib/types/types.ts @@ -0,0 +1,108 @@ +/* eslint-disable */ + +interface KeyValue { + [s: string]: any, +} + +interface Settings { + devices?: {[s: string]: {friendly_name: string, retention?: number}}, + groups?: {[s: string]: {friendly_name: string, devices?: string[]}}, + passlist: string[], + blocklist: string[], + whitelist: string[], + ban: string[], + permit_join: boolean, + frontend?: { + auth_token?: string, + }, + mqtt: { + include_device_information: boolean, + force_disable_retain: boolean + version?: number, + user?: string, + password?: string, + }, + serial: { + disable_led: boolean, + }, + device_options: {[s: string]: unknown}, + map_options: { + graphviz: { + colors: { + fill: { + enddevice: string, + coordinator: string, + router: string, + }, + font: { + coordinator: string, + router: string, + enddevice: string, + }, + line: { + active: string, + inactive: string, + }, + }, + }, + }, + experimental: { + output: 'json' | 'attribute' | 'attribute_and_json', + }, + advanced: { + legacy_api: boolean, + log_rotation: boolean, + log_symlink_current: boolean, + log_output: ('console' | 'file')[], + log_directory: string, + log_file: string, + log_level: 'debug' | 'info' | 'error' | 'warn', + log_syslog: {}, + soft_reset_timeout: number, + pan_id: number, + ext_pan_id: number[], + channel: number, + adapter_concurrent: number | null, + adapter_delay: number | null, + availability_timeout: number, + availability_blocklist: string[], + availability_passlist: string[], + availability_blacklist: string[], + availability_whitelist: string[], + cache_state: boolean, + cache_state_persistent: boolean, + cache_state_send_on_startup: boolean, + last_seen: 'disable' | 'ISO_8601' | 'ISO_8601_local' | 'epoch', + elapsed: boolean, + network_key: number[], + report: boolean, + homeassistant_discovery_topic: string, + homeassistant_status_topic: string, + homeassistant_legacy_entity_attributes: boolean, + homeassistant_legacy_triggers: boolean, + timestamp_format: string, + }, + ota: { + update_check_interval: number, + disable_automatic_update_check: boolean + }, + external_converters: string[], +} + +interface DeviceSettings { + friendlyName: string, + ID: string, + retention?: number, +} + +interface GroupSettings { + friendlyName: string, + devices: string[], + ID: number, +} + +type EntitySettings = { + type: 'device' | 'group' + ID: number | string, + friendlyName: string, +} diff --git a/lib/util/settings.js b/lib/util/settings.ts similarity index 77% rename from lib/util/settings.js rename to lib/util/settings.ts index a21532d46..58823ad01 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.ts @@ -1,17 +1,19 @@ -const data = require('./data'); -const utils = require('./utils'); +import data from './data'; +import utils from './utils'; +import objectAssignDeep from 'object-assign-deep'; +import path from 'path'; +import * as yaml from './yaml'; +import Ajv from 'ajv'; +import schemaJson from './settings.schema.json'; +export const schema = schemaJson; + // DEPRECATED ZIGBEE2MQTT_CONFIG: https://github.com/Koenkk/zigbee2mqtt/issues/4697 -const file = process.env.ZIGBEE2MQTT_CONFIG || data.joinPath('configuration.yaml'); -const objectAssignDeep = require(`object-assign-deep`); -const path = require('path'); -const yaml = require('./yaml'); -const Ajv = require('ajv'); -const schema = require('./settings.schema.json'); +const file = process.env.ZIGBEE2MQTT_CONFIG ?? data.joinPath('configuration.yaml'); const ajvSetting = new Ajv({allErrors: true}).addKeyword('requiresRestart').compile(schema); const ajvRestartRequired = new Ajv({allErrors: true}) - .addKeyword({keyword: 'requiresRestart', validate: (schema, data) => !schema}).compile(schema); + .addKeyword({keyword: 'requiresRestart', validate: (schema: unknown) => !schema}).compile(schema); -const defaults = { +const defaults: Settings = { passlist: [], blocklist: [], // Deprecated: use block/passlist @@ -161,11 +163,12 @@ const defaults = { external_converters: [], }; -let _settings; -let _settingsWithDefaults; +let _settings: Partial; +let _settingsWithDefaults: Settings; -function write() { - const settings = get(); +function write(): void { + const settings = getInternalSettings(); + /* eslint-disable-line */ // @ts-ignore const toWrite = objectAssignDeep.noMutate(settings); // Read settings to check if we have to split devices/groups into separate file. @@ -188,17 +191,18 @@ function write() { } // Write devices/groups to separate file if required. - const writeDevicesOrGroups = (type) => { + const writeDevicesOrGroups = (type: 'devices' | 'groups'): void => { if (typeof actual[type] === 'string' || Array.isArray(actual[type])) { const fileToWrite = Array.isArray(actual[type]) ? actual[type][0] : actual[type]; + /* eslint-disable-line */ // @ts-ignore const content = objectAssignDeep.noMutate(settings[type]); // If an array, only write to first file and only devices which are not in the other files. if (Array.isArray(actual[type])) { - actual[type].filter((f, i) => i !== 0) - .map((f) => yaml.readIfExists(data.joinPath(f), {})) - .map((c) => Object.keys(c)) - .forEach((k) => delete content[k]); + actual[type].filter((f: string, i: number) => i !== 0) + .map((f: string) => yaml.readIfExists(data.joinPath(f), {})) + .map((c: KeyValue) => Object.keys(c)) + .forEach((k: string) => delete content[k]); } yaml.writeIfChanged(data.joinPath(fileToWrite), content); @@ -212,12 +216,13 @@ function write() { yaml.writeIfChanged(file, toWrite); _settings = read(); - _settingsWithDefaults = objectAssignDeep.noMutate(defaults, get()); + /* eslint-disable-line */ // @ts-ignore + _settingsWithDefaults = objectAssignDeep.noMutate(defaults, getInternalSettings()); } -function validate() { +export function validate(): string[] { try { - get(); + getInternalSettings(); } catch (error) { if (error.name === 'YAMLException') { return [ @@ -245,14 +250,14 @@ function validate() { } // Verify that all friendly names are unique - const names = []; - const check = (name) => { + const names: string[] = []; + const check = (name: string): void => { if (names.includes(name)) errors.push(`Duplicate friendly_name '${name}' found`); errors.push(...utils.validateFriendlyName(name)); names.push(name); }; - const settingsWithDefaults = getWithDefaults(); + const settingsWithDefaults = get(); Object.values(settingsWithDefaults.devices).forEach((d) => check(d.friendly_name)); Object.values(settingsWithDefaults.groups).forEach((g) => check(g.friendly_name)); @@ -264,7 +269,7 @@ function validate() { } } - const checkAvailabilityList = (list, type) => { + const checkAvailabilityList = (list: string[], type: string): void => { list.forEach((e) => { if (!getEntity(e)) { errors.push(`Non-existing entity '${e}' specified in '${type}'`); @@ -280,11 +285,12 @@ function validate() { return errors; } -function read() { - const s = yaml.read(file); +function read(): Settings { + const s = yaml.read(file) as Settings; // Read !secret MQTT username and password if set - const interpetValue = (value) => { + // eslint-disable-next-line + const interpetValue = (value: any): any => { const re = /!(.*) (.*)/g; const match = re.exec(value); if (match) { @@ -296,26 +302,28 @@ function read() { } }; - if (s.mqtt && s.mqtt.user && s.mqtt.password) { + if (s.mqtt?.user && s.mqtt?.password) { s.mqtt.user = interpetValue(s.mqtt.user); s.mqtt.password = interpetValue(s.mqtt.password); } - if (s.advanced && s.advanced.network_key) { + if (s.advanced?.network_key) { s.advanced.network_key = interpetValue(s.advanced.network_key); } - if (s.frontend && s.frontend.auth_token) { + if (s.frontend?.auth_token) { s.frontend.auth_token = interpetValue(s.frontend.auth_token); } // Read devices/groups configuration from separate file if specified. - const readDevicesOrGroups = (type) => { + const readDevicesOrGroups = (type: 'devices' | 'groups'): void => { if (typeof s[type] === 'string' || Array.isArray(s[type])) { - const files = Array.isArray(s[type]) ? s[type] : [s[type]]; + /* eslint-disable-line */ // @ts-ignore + const files: string[] = Array.isArray(s[type]) ? s[type] : [s[type]]; s[type] = {}; for (const file of files) { const content = yaml.readIfExists(data.joinPath(file), {}); + /* eslint-disable-line */ // @ts-ignore s[type] = objectAssignDeep.noMutate(s[type], content); } } @@ -327,8 +335,8 @@ function read() { return s; } -function applyEnvironmentVariables(settings) { - const iterate = (obj, path) => { +function applyEnvironmentVariables(settings: Partial): void { + const iterate = (obj: KeyValue, path: string[]): void => { Object.keys(obj).forEach((key) => { if (key !== 'type') { if (key !== 'properties' && obj[key]) { @@ -336,14 +344,17 @@ function applyEnvironmentVariables(settings) { const envPart = path.reduce((acc, val) => `${acc}${val}_`, ''); const envVariableName = (`ZIGBEE2MQTT_CONFIG_${envPart}${key}`).toUpperCase(); if (process.env[envVariableName]) { - const setting = path.reduce((acc, val, index) => { + const setting = path.reduce((acc, val) => { + /* eslint-disable-line */ // @ts-ignore acc[val] = acc[val] || {}; + /* eslint-disable-line */ // @ts-ignore return acc[val]; }, settings); if (type.indexOf('object') >= 0 || type.indexOf('array') >= 0) { setting[key] = JSON.parse(process.env[envVariableName]); } else if (type.indexOf('number') >= 0) { + /* eslint-disable-line */ // @ts-ignore setting[key] = process.env[envVariableName] * 1; } else if (type.indexOf('boolean') >= 0) { setting[key] = process.env[envVariableName].toLowerCase() === 'true'; @@ -369,7 +380,7 @@ function applyEnvironmentVariables(settings) { iterate(schema.properties, []); } -function get() { +function getInternalSettings(): Partial { if (!_settings) { _settings = read(); applyEnvironmentVariables(_settings); @@ -378,9 +389,10 @@ function get() { return _settings; } -function getWithDefaults() { +export function get(): Settings { if (!_settingsWithDefaults) { - _settingsWithDefaults = objectAssignDeep.noMutate(defaults, get()); + /* eslint-disable-line */ // @ts-ignore + _settingsWithDefaults = objectAssignDeep.noMutate(defaults, getInternalSettings()); } if (!_settingsWithDefaults.devices) { @@ -394,8 +406,9 @@ function getWithDefaults() { return _settingsWithDefaults; } -function set(path, value) { - let settings = get(); +export function set(path: string[], value: string | number): void { + /* eslint-disable-next-line */ + let settings: any = getInternalSettings(); for (let i = 0; i < path.length; i++) { const key = path[i]; @@ -413,7 +426,7 @@ function set(path, value) { write(); } -function apply(newSettings) { +export function apply(newSettings: Record): boolean { ajvSetting(newSettings); const errors = ajvSetting.errors && ajvSetting.errors.filter((e) => e.keyword !== 'required'); if (errors.length) { @@ -421,7 +434,8 @@ function apply(newSettings) { throw new Error(`${error.instancePath.substring(1)} ${error.message}`); } - get(); // Ensure _settings is intialized. + getInternalSettings(); // Ensure _settings is intialized. + /* eslint-disable-line */ // @ts-ignore _settings = objectAssignDeep.noMutate(_settings, newSettings); write(); @@ -431,8 +445,8 @@ function apply(newSettings) { return restartRequired; } -function getGroup(IDorName) { - const settings = getWithDefaults(); +export function getGroup(IDorName: string): GroupSettings { + const settings = get(); const byID = settings.groups[IDorName]; if (byID) { return {devices: [], ...byID, ID: Number(IDorName), friendlyName: byID.friendly_name}; @@ -447,14 +461,14 @@ function getGroup(IDorName) { return null; } -function getGroups() { - const settings = getWithDefaults(); +export function getGroups(): GroupSettings[] { + const settings = get(); return Object.entries(settings.groups).map(([ID, group]) => { return {devices: [], ...group, ID: Number(ID), friendlyName: group.friendly_name}; }); } -function getGroupThrowIfNotExists(IDorName) { +function getGroupThrowIfNotExists(IDorName: string): GroupSettings { const group = getGroup(IDorName); if (!group) { throw new Error(`Group '${IDorName}' does not exist`); @@ -463,8 +477,8 @@ function getGroupThrowIfNotExists(IDorName) { return group; } -function getDevice(IDorName) { - const settings = getWithDefaults(); +export function getDevice(IDorName: string): DeviceSettings { + const settings = get(); const byID = settings.devices[IDorName]; if (byID) { return {...byID, ID: IDorName, friendlyName: byID.friendly_name}; @@ -479,7 +493,7 @@ function getDevice(IDorName) { return null; } -function getDeviceThrowIfNotExists(IDorName) { +function getDeviceThrowIfNotExists(IDorName: string): DeviceSettings { const device = getDevice(IDorName); if (!device) { throw new Error(`Device '${IDorName}' does not exist`); @@ -488,7 +502,7 @@ function getDeviceThrowIfNotExists(IDorName) { return device; } -function getEntity(IDorName) { +export function getEntity(IDorName: string): EntitySettings { const device = getDevice(IDorName); if (device) { return {...device, type: 'device'}; @@ -502,12 +516,12 @@ function getEntity(IDorName) { return null; } -function addDevice(ID) { +export function addDevice(ID: string): DeviceSettings { if (getDevice(ID)) { throw new Error(`Device '${ID}' already exists`); } - const settings = get(); + const settings = getInternalSettings(); if (!settings.devices) { settings.devices = {}; @@ -518,9 +532,8 @@ function addDevice(ID) { return getDevice(ID); } -// Legacy: can be removed after bridgeLegacy has been removed -function whitelistDevice(ID) { - const settings = get(); +export function whitelistDevice(ID: string): void { + const settings = getInternalSettings(); if (!settings.whitelist) { settings.whitelist = []; } @@ -533,8 +546,8 @@ function whitelistDevice(ID) { write(); } -function blockDevice(ID) { - const settings = get(); +export function blockDevice(ID: string): void { + const settings = getInternalSettings(); if (!settings.blocklist) { settings.blocklist = []; } @@ -543,8 +556,8 @@ function blockDevice(ID) { write(); } -function banDevice(ID) { - const settings = get(); +export function banDevice(ID: string): void { + const settings = getInternalSettings(); if (!settings.ban) { settings.ban = []; } @@ -553,15 +566,15 @@ function banDevice(ID) { write(); } -function removeDevice(IDorName) { +export function removeDevice(IDorName: string): void { const device = getDeviceThrowIfNotExists(IDorName); - const settings = get(); + const settings = getInternalSettings(); delete settings.devices[device.ID]; // Remove device from groups if (settings.groups) { const regex = - new RegExp(`^(${device.friendly_name}|${device.ID})(/(\\d|${utils.getEndpointNames().join('|')}))?$`); + new RegExp(`^(${device.friendlyName}|${device.ID})(/(\\d|${utils.getEndpointNames().join('|')}))?$`); for (const group of Object.values(settings.groups).filter((g) => g.devices)) { group.devices = group.devices.filter((device) => !device.match(regex)); } @@ -570,13 +583,13 @@ function removeDevice(IDorName) { write(); } -function addGroup(name, ID=null) { +export function addGroup(name: string, ID?: string): GroupSettings { utils.validateFriendlyName(name, true); if (getGroup(name) || getDevice(name)) { throw new Error(`friendly_name '${name}' is already in use`); } - const settings = get(); + const settings = getInternalSettings(); if (!settings.groups) { settings.groups = {}; } @@ -591,7 +604,7 @@ function addGroup(name, ID=null) { // ensure provided ID is not in use ID = ID.toString(); if (settings.groups.hasOwnProperty(ID)) { - throw new Error(`group id '${ID}' is already in use`); + throw new Error(`Group ID '${ID}' is already in use`); } } @@ -601,56 +614,50 @@ function addGroup(name, ID=null) { return getGroup(ID); } -function groupHasDevice(group, keys) { - for (const device of group.devices) { - const index = keys.indexOf(device); - if (index != -1) { - return keys[index]; - } +function groupGetDevice(group: {devices?: string[]}, keys: string[]): string { + for (const device of group.devices ?? []) { + if (keys.includes(device)) return device; } - return false; + return null; } -function addDeviceToGroup(groupIDorName, keys) { - const groupID = getGroupThrowIfNotExists(groupIDorName).ID; - const settings = get(); +export function addDeviceToGroup(IDorName: string, keys: string[]): void { + const groupID = getGroupThrowIfNotExists(IDorName).ID; + const settings = getInternalSettings(); const group = settings.groups[groupID]; - if (!group.devices) { - group.devices = []; - } - - if (!groupHasDevice(group, keys)) { + if (!groupGetDevice(group, keys)) { + if (!group.devices) group.devices = []; group.devices.push(keys[0]); write(); } } -function removeDeviceFromGroup(groupIDorName, keys) { - const groupID = getGroupThrowIfNotExists(groupIDorName).ID; - const settings = get(); +export function removeDeviceFromGroup(IDorName: string, keys: string[]): void { + const groupID = getGroupThrowIfNotExists(IDorName).ID; + const settings = getInternalSettings(); const group = settings.groups[groupID]; if (!group.devices) { - group.devices = []; + return; } - const key = groupHasDevice(group, keys); + const key = groupGetDevice(group, keys); if (key) { group.devices = group.devices.filter((d) => d != key); write(); } } -function removeGroup(groupIDorName) { - const groupID = getGroupThrowIfNotExists(groupIDorName).ID; - const settings = get(); +export function removeGroup(IDorName: string): void { + const groupID = getGroupThrowIfNotExists(IDorName).ID; + const settings = getInternalSettings(); delete settings.groups[groupID]; write(); } -function changeEntityOptions(IDorName, newOptions) { - const settings = get(); +export function changeEntityOptions(IDorName: string, newOptions: KeyValue): void { + const settings = getInternalSettings(); delete newOptions.friendly_name; delete newOptions.devices; if (getDevice(IDorName)) { @@ -666,13 +673,13 @@ function changeEntityOptions(IDorName, newOptions) { write(); } -function changeFriendlyName(IDorName, newName) { +export function changeFriendlyName(IDorName: string, newName: string): void { utils.validateFriendlyName(newName, true); if (getGroup(newName) || getDevice(newName)) { throw new Error(`friendly_name '${newName}' is already in use`); } - const settings = get(); + const settings = getInternalSettings(); if (getDevice(IDorName)) { settings.devices[getDevice(IDorName).ID].friendly_name = newName; } else if (getGroup(IDorName)) { @@ -684,39 +691,18 @@ function changeFriendlyName(IDorName, newName) { write(); } -module.exports = { - validate, - get: getWithDefaults, - set, - apply, - getDevice, - getGroup, - getGroups, - getEntity, - whitelistDevice, - banDevice, - blockDevice, - addDevice, - removeDevice, - addGroup, - removeGroup, - addDeviceToGroup, - removeDeviceFromGroup, - changeEntityOptions, - changeFriendlyName, - schema, - reRead: () => { - _settings = null; - get(); - _settingsWithDefaults = null; - getWithDefaults(); - }, +export function reRead(): void { + _settings = null; + getInternalSettings(); + _settingsWithDefaults = null; + get(); +} - // For tests only - _write: write, - _clear: () => { +export const testing = { + write, + clear: (): void => { _settings = null; _settingsWithDefaults = null; }, - _getDefaults: () => defaults, + defaults, }; diff --git a/lib/util/yaml.ts b/lib/util/yaml.ts index 2e84b4d1b..eb3319df8 100644 --- a/lib/util/yaml.ts +++ b/lib/util/yaml.ts @@ -3,10 +3,9 @@ import fs from 'fs'; import equals from 'fast-deep-equal/es6'; import 'source-map-support/register'; -function read(file: string): Record { +export function read(file: string): KeyValue { try { - // eslint-disable-next-line - // @ts-ignore + /* eslint-disable-line */ // @ts-ignore return yaml.load(fs.readFileSync(file, 'utf8')); } catch (error) { if (error.name === 'YAMLException') { @@ -17,23 +16,21 @@ function read(file: string): Record { } } -function readIfExists(file: string, default_?: Record): Record { +export function readIfExists(file: string, default_?: KeyValue): KeyValue { return fs.existsSync(file) ? read(file) : default_; } -function writeIfChanged(file: string, content: Record): void { +export function writeIfChanged(file: string, content: KeyValue): void { const before = readIfExists(file); if (!equals(before, content)) { fs.writeFileSync(file, yaml.dump(content)); } } -function updateIfChanged(file: string, key: string, value: unknown): void { +export function updateIfChanged(file: string, key: string, value: KeyValue): void { const content = read(file); if (content[key] !== value) { content[key] = value; writeIfChanged(file, content); } } - -module.exports = {read, readIfExists, writeIfChanged, updateIfChanged}; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 91feeada0..ffe168ca9 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -2357,6 +2357,12 @@ "integrity": "sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==", "dev": true }, + "@types/object-assign-deep": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@types/object-assign-deep/-/object-assign-deep-0.4.0.tgz", + "integrity": "sha512-3D0F3rHRNDc8cQSXNzwF1jBrJi28Mdrhc10ZLlqbJWDPYRWTTWB9Tc8JoKrgBvLKioXoPoHT6Uzf3s2F7akCUg==", + "dev": true + }, "@types/prettier": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", diff --git a/package.json b/package.json index 171825b2c..54050dbf6 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@babel/preset-typescript": "^7.14.5", "@types/jest": "^26.0.24", "@types/js-yaml": "^4.0.2", + "@types/object-assign-deep": "^0.4.0", "@types/ws": "^7.4.6", "@typescript-eslint/eslint-plugin": "^4.28.3", "@typescript-eslint/parser": "^4.28.3", diff --git a/test/settings.test.js b/test/settings.test.js index 6b150a09b..0ad4d335c 100644 --- a/test/settings.test.js +++ b/test/settings.test.js @@ -2,7 +2,7 @@ require('./stub/logger'); require('./stub/data'); const data = require('../lib/util/data.js'); const utils = require('../lib/util/utils.js'); -const settings = require('../lib/util/settings.js'); +const settings = require('../lib/util/settings.ts'); const fs = require('fs'); const configurationFile = data.joinPath('configuration.yaml'); const devicesFile = data.joinPath('devices.yaml'); @@ -47,7 +47,7 @@ describe('Settings', () => { it('Should return default settings', () => { write(configurationFile, {}); const s = settings.get(); - const expected = settings._getDefaults(); + const expected = objectAssignDeep.noMutate({}, settings.testing.defaults); expected.devices = {}; expected.groups = {}; expect(s).toStrictEqual(expected); @@ -56,7 +56,7 @@ describe('Settings', () => { it('Should return settings', () => { write(configurationFile, {permit_join: true}); const s = settings.get(); - const expected = settings._getDefaults(); + const expected = objectAssignDeep.noMutate({}, settings.testing.defaults); expected.devices = {}; expected.groups = {}; expected.permit_join = true; @@ -73,7 +73,7 @@ describe('Settings', () => { write(configurationFile, {}); const s = settings.get(); - const expected = objectAssignDeep.noMutate({}, settings._getDefaults()); + const expected = objectAssignDeep.noMutate({}, settings.testing.defaults); expected.devices = {}; expected.groups = {}; expected.serial.disable_led = true; @@ -163,7 +163,7 @@ describe('Settings', () => { expect(settings.get().mqtt).toStrictEqual(expected); expect(settings.get().advanced.network_key).toStrictEqual([1,2,3]); - settings._write(); + settings.testing.write(); expect(read(configurationFile)).toStrictEqual(contentConfiguration); expect(read(secretFile)).toStrictEqual(contentSecret); @@ -493,7 +493,7 @@ describe('Settings', () => { settings.addGroup('test123', 123); expect(() => { settings.addGroup('test_id_123', 123); - }).toThrow(new Error("group id '123' is already in use")); + }).toThrow(new Error("Group ID '123' is already in use")); const expected = { '123': { friendly_name: 'test123', @@ -702,13 +702,13 @@ describe('Settings', () => { \t wrong `) - settings._clear(); + settings.testing.clear(); const error = `Your YAML file: '${configurationFile}' is invalid (use https://jsonformatter.org/yaml-validator to find and fix the issue)`; expect(settings.validate()).toEqual(expect.arrayContaining([error])); }); it('Should throw error when yaml file does not exist', () => { - settings._clear(); + settings.testing.clear(); const error = `ENOENT: no such file or directory, open '${configurationFile}'`; expect(settings.validate()).toEqual(expect.arrayContaining([error])); });