Files
generalFunctions/test/configManager.test.js
2026-03-12 16:39:25 +01:00

218 lines
8.9 KiB
JavaScript

const path = require('path');
const ConfigManager = require('../src/configs/index');
describe('ConfigManager', () => {
const configDir = path.resolve(__dirname, '../src/configs');
let cm;
beforeEach(() => {
cm = new ConfigManager(configDir);
});
// ── getConfig() ──────────────────────────────────────────────────────
describe('getConfig()', () => {
it('should load and parse a known JSON config file', () => {
const config = cm.getConfig('baseConfig');
expect(config).toBeDefined();
expect(typeof config).toBe('object');
});
it('should return the same content on successive calls', () => {
const a = cm.getConfig('baseConfig');
const b = cm.getConfig('baseConfig');
expect(a).toEqual(b);
});
it('should throw when the config file does not exist', () => {
expect(() => cm.getConfig('nonExistentConfig_xyz'))
.toThrow(/Failed to load config/);
});
it('should throw a descriptive message including the config name', () => {
expect(() => cm.getConfig('missing'))
.toThrow("Failed to load config 'missing'");
});
});
// ── hasConfig() ──────────────────────────────────────────────────────
describe('hasConfig()', () => {
it('should return true for a config that exists', () => {
expect(cm.hasConfig('baseConfig')).toBe(true);
});
it('should return false for a config that does not exist', () => {
expect(cm.hasConfig('doesNotExist_abc')).toBe(false);
});
});
// ── getAvailableConfigs() ────────────────────────────────────────────
describe('getAvailableConfigs()', () => {
it('should return an array of strings', () => {
const configs = cm.getAvailableConfigs();
expect(Array.isArray(configs)).toBe(true);
configs.forEach(name => expect(typeof name).toBe('string'));
});
it('should include known config names without .json extension', () => {
const configs = cm.getAvailableConfigs();
expect(configs).toContain('baseConfig');
expect(configs).toContain('diffuser');
expect(configs).toContain('measurement');
});
it('should not include .json extension in returned names', () => {
const configs = cm.getAvailableConfigs();
configs.forEach(name => {
expect(name).not.toMatch(/\.json$/);
});
});
it('should throw when pointed at a non-existent directory', () => {
const bad = new ConfigManager('/tmp/nonexistent_dir_xyz_123');
expect(() => bad.getAvailableConfigs()).toThrow(/Failed to read config directory/);
});
});
// ── buildConfig() ────────────────────────────────────────────────────
describe('buildConfig()', () => {
it('should return an object with general and functionality sections', () => {
const uiConfig = { name: 'TestNode', unit: 'bar', enableLog: true, logLevel: 'debug' };
const result = cm.buildConfig('measurement', uiConfig, 'node-id-1');
expect(result).toHaveProperty('general');
expect(result).toHaveProperty('functionality');
expect(result).toHaveProperty('output');
});
it('should populate general.name from uiConfig.name', () => {
const uiConfig = { name: 'MySensor' };
const result = cm.buildConfig('measurement', uiConfig, 'id-1');
expect(result.general.name).toBe('MySensor');
});
it('should default general.name to nodeName when uiConfig.name is empty', () => {
const result = cm.buildConfig('measurement', {}, 'id-1');
expect(result.general.name).toBe('measurement');
});
it('should set general.id from the nodeId argument', () => {
const result = cm.buildConfig('valve', {}, 'node-42');
expect(result.general.id).toBe('node-42');
});
it('should default unit to unitless', () => {
const result = cm.buildConfig('valve', {}, 'id-1');
expect(result.general.unit).toBe('unitless');
});
it('should default logging.enabled to true when enableLog is undefined', () => {
const result = cm.buildConfig('valve', {}, 'id-1');
expect(result.general.logging.enabled).toBe(true);
});
it('should respect enableLog = false', () => {
const result = cm.buildConfig('valve', { enableLog: false }, 'id-1');
expect(result.general.logging.enabled).toBe(false);
});
it('should default logLevel to info', () => {
const result = cm.buildConfig('valve', {}, 'id-1');
expect(result.general.logging.logLevel).toBe('info');
});
it('should set functionality.softwareType to lowercase nodeName', () => {
const result = cm.buildConfig('Valve', {}, 'id-1');
expect(result.functionality.softwareType).toBe('valve');
});
it('should default positionVsParent to atEquipment', () => {
const result = cm.buildConfig('valve', {}, 'id-1');
expect(result.functionality.positionVsParent).toBe('atEquipment');
});
it('should set distance when hasDistance is true', () => {
const result = cm.buildConfig('valve', { hasDistance: true, distance: 5.5 }, 'id-1');
expect(result.functionality.distance).toBe(5.5);
});
it('should set distance to undefined when hasDistance is false', () => {
const result = cm.buildConfig('valve', { hasDistance: false, distance: 5.5 }, 'id-1');
expect(result.functionality.distance).toBeUndefined();
});
// ── asset section ──────────────────────────────────────────────────
it('should not include asset section when no asset fields provided', () => {
const result = cm.buildConfig('valve', {}, 'id-1');
expect(result.asset).toBeUndefined();
});
it('should include asset section when supplier is provided', () => {
const result = cm.buildConfig('valve', { supplier: 'Siemens' }, 'id-1');
expect(result.asset).toBeDefined();
expect(result.asset.supplier).toBe('Siemens');
});
it('should populate asset defaults for missing optional fields', () => {
const result = cm.buildConfig('valve', { supplier: 'ABB' }, 'id-1');
expect(result.asset.category).toBe('sensor');
expect(result.asset.type).toBe('Unknown');
expect(result.asset.model).toBe('Unknown');
});
// ── domainConfig merge ─────────────────────────────────────────────
it('should merge domainConfig sections into the result', () => {
const domain = { scaling: { enabled: true, factor: 2 } };
const result = cm.buildConfig('measurement', {}, 'id-1', domain);
expect(result.scaling).toEqual({ enabled: true, factor: 2 });
});
it('should handle empty domainConfig gracefully', () => {
const result = cm.buildConfig('measurement', {}, 'id-1', {});
expect(result).toHaveProperty('general');
expect(result).toHaveProperty('functionality');
});
it('should default output formats to process and influxdb', () => {
const result = cm.buildConfig('measurement', {}, 'id-1');
expect(result.output).toEqual({
process: 'process',
dbase: 'influxdb',
});
});
it('should allow output format overrides from ui config', () => {
const result = cm.buildConfig('measurement', {
processOutputFormat: 'json',
dbaseOutputFormat: 'csv',
}, 'id-1');
expect(result.output).toEqual({
process: 'json',
dbase: 'csv',
});
});
});
// ── createEndpoint() ─────────────────────────────────────────────────
describe('createEndpoint()', () => {
it('should return a JavaScript string containing the node name', () => {
const script = cm.createEndpoint('baseConfig');
expect(typeof script).toBe('string');
expect(script).toContain('baseConfig');
expect(script).toContain('window.EVOLV');
});
it('should throw for a non-existent config', () => {
expect(() => cm.createEndpoint('doesNotExist_xyz'))
.toThrow(/Failed to create endpoint/);
});
});
// ── getBaseConfig() ──────────────────────────────────────────────────
describe('getBaseConfig()', () => {
it('should load the baseConfig.json file', () => {
const base = cm.getBaseConfig();
expect(base).toBeDefined();
expect(typeof base).toBe('object');
});
});
});