'use strict'; /** * Unit tests for config.js */ const { describe, it, beforeEach, afterEach } = require('node:test'); const assert = require('node:assert/strict'); const { buildConfig, resetConfig } = require('../../src/config'); describe('config.js', () => { const originalEnv = {}; beforeEach(() => { // Save and clear relevant env vars const keys = [ 'MM_BOT_TOKEN', 'MM_BASE_URL', 'MM_MAX_SOCKETS', 'TRANSCRIPT_DIR', 'THROTTLE_MS', 'IDLE_TIMEOUT_S', 'SESSION_POLL_MS', 'MAX_ACTIVE_SESSIONS', 'MAX_MESSAGE_CHARS', 'MAX_STATUS_LINES', 'MAX_RETRIES', 'CIRCUIT_BREAKER_THRESHOLD', 'CIRCUIT_BREAKER_COOLDOWN_S', 'HEALTH_PORT', 'LOG_LEVEL', 'PID_FILE', 'OFFSET_FILE', 'TOOL_LABELS_FILE', 'DEFAULT_CHANNEL', 'ENABLE_FS_WATCH', 'MM_PORT', ]; for (const k of keys) { originalEnv[k] = process.env[k]; delete process.env[k]; } resetConfig(); }); afterEach(() => { // Restore env for (const [k, v] of Object.entries(originalEnv)) { if (v === undefined) delete process.env[k]; else process.env[k] = v; } resetConfig(); }); it('throws if MM_BOT_TOKEN is missing', () => { assert.throws(() => buildConfig(), /MM_BOT_TOKEN/); }); it('builds config with only required vars', () => { process.env.MM_BOT_TOKEN = 'test-token'; const cfg = buildConfig(); assert.equal(cfg.mm.token, 'test-token'); assert.equal(cfg.mm.baseUrl, 'https://slack.solio.tech'); assert.equal(cfg.throttleMs, 500); assert.equal(cfg.idleTimeoutS, 60); assert.equal(cfg.maxActiveSessions, 20); assert.equal(cfg.healthPort, 9090); assert.equal(cfg.logLevel, 'info'); }); it('reads all env vars correctly', () => { process.env.MM_BOT_TOKEN = 'mytoken'; process.env.MM_BASE_URL = 'https://mm.example.com'; process.env.MM_MAX_SOCKETS = '8'; process.env.THROTTLE_MS = '250'; process.env.IDLE_TIMEOUT_S = '120'; process.env.MAX_ACTIVE_SESSIONS = '10'; process.env.MAX_MESSAGE_CHARS = '5000'; process.env.LOG_LEVEL = 'debug'; process.env.HEALTH_PORT = '8080'; process.env.ENABLE_FS_WATCH = 'false'; const cfg = buildConfig(); assert.equal(cfg.mm.token, 'mytoken'); assert.equal(cfg.mm.baseUrl, 'https://mm.example.com'); assert.equal(cfg.mm.maxSockets, 8); assert.equal(cfg.throttleMs, 250); assert.equal(cfg.idleTimeoutS, 120); assert.equal(cfg.maxActiveSessions, 10); assert.equal(cfg.maxMessageChars, 5000); assert.equal(cfg.logLevel, 'debug'); assert.equal(cfg.healthPort, 8080); assert.equal(cfg.enableFsWatch, false); }); it('throws on invalid MM_BASE_URL', () => { process.env.MM_BOT_TOKEN = 'token'; process.env.MM_BASE_URL = 'not-a-url'; assert.throws(() => buildConfig(), /MM_BASE_URL/); }); it('throws on non-integer THROTTLE_MS', () => { process.env.MM_BOT_TOKEN = 'token'; process.env.THROTTLE_MS = 'abc'; assert.throws(() => buildConfig(), /THROTTLE_MS/); }); it('ENABLE_FS_WATCH accepts "1", "true", "yes"', () => { process.env.MM_BOT_TOKEN = 'token'; process.env.ENABLE_FS_WATCH = '1'; assert.equal(buildConfig().enableFsWatch, true); resetConfig(); process.env.ENABLE_FS_WATCH = 'true'; assert.equal(buildConfig().enableFsWatch, true); resetConfig(); process.env.ENABLE_FS_WATCH = 'yes'; assert.equal(buildConfig().enableFsWatch, true); resetConfig(); process.env.ENABLE_FS_WATCH = '0'; assert.equal(buildConfig().enableFsWatch, false); resetConfig(); }); it('nullish defaults for optional string fields', () => { process.env.MM_BOT_TOKEN = 'token'; const cfg = buildConfig(); assert.equal(cfg.toolLabelsFile, null); assert.equal(cfg.defaultChannel, null); }); });