Files
settler/test/basic/specificClass.basic.test.js
znetsixe b8247fc755 P6: convert settler to platform infrastructure
Refactor of settler to use BaseNodeAdapter + commandRegistry + statusBadge.
settler follows the platform refactor plan in .claude/refactor/MODULE_SPLIT.md.
Tests stay green; CONTRACT.md generated; legacy aliases preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:23:44 +02:00

124 lines
3.9 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const EventEmitter = require('events');
const Settler = require('../../src/specificClass');
const NUM_SPECIES = 13;
function makeSettler() {
return new Settler({
general: { name: 'TestSettler', id: 'settler-test-1', logging: { enabled: false, logLevel: 'error' } },
functionality: { softwareType: 'settler', positionVsParent: 'downstream' },
});
}
test('constructor sets default state', () => {
const s = makeSettler();
assert.equal(s.F_in, 0);
assert.deepEqual(s.Cs_in, new Array(NUM_SPECIES).fill(0));
assert.equal(s.C_TS, 2500);
assert.equal(s.upstreamReactor, null);
assert.equal(s.returnPump, null);
});
test('getEffluent conserves total flow (mass balance)', () => {
const s = makeSettler();
s.F_in = 200;
s.C_TS = 3000;
const C = new Array(NUM_SPECIES).fill(5);
C[12] = 2000;
s.Cs_in = C;
const [eff, sur, ret] = s.getEffluent;
assert.equal(eff.topic, 'Fluent');
assert.ok(Math.abs(eff.payload.F + sur.payload.F + ret.payload.F - 200) < 1e-6);
for (let i = 7; i <= 12; i++) assert.equal(eff.payload.C[i], 0);
});
test('getEffluent clamps F_s to F_in when X_TS exceeds C_TS', () => {
const s = makeSettler();
s.F_in = 100;
s.C_TS = 1000;
s.Cs_in = new Array(NUM_SPECIES).fill(10);
s.Cs_in[12] = 5000;
const [eff] = s.getEffluent;
assert.equal(eff.payload.F, 0);
});
test('reactor stateChange pulls effluent (preserves _connectReactor integration)', () => {
const s = makeSettler();
let outputChanges = 0;
s.emitter.on('output-changed', () => outputChanges++);
const reactor = {
config: { general: { name: 'r', id: 'r-1' }, functionality: { positionVsParent: 'upstream' } },
emitter: new EventEmitter(),
measurements: { emitter: new EventEmitter() },
// Mirror the array shape the reactor produces in production.
get getEffluent() {
const C = new Array(NUM_SPECIES).fill(2);
C[12] = 3500;
return [{ topic: 'Fluent', payload: { inlet: 0, F: 150, C } }];
},
};
s.router.dispatchRegister(reactor, 'reactor');
reactor.emitter.emit('stateChange');
assert.equal(s.upstreamReactor, reactor);
assert.equal(s.F_in, 150);
assert.equal(s.Cs_in[12], 3500);
assert.ok(outputChanges >= 1, 'reactor stateChange should trigger output-changed');
});
test('reactor stateChange handles single-envelope getEffluent (not array)', () => {
const s = makeSettler();
const reactor = {
config: { general: { name: 'r', id: 'r-1' }, functionality: { positionVsParent: 'upstream' } },
emitter: new EventEmitter(),
measurements: { emitter: new EventEmitter() },
get getEffluent() {
const C = new Array(NUM_SPECIES).fill(1);
C[12] = 800;
return { topic: 'Fluent', payload: { inlet: 0, F: 42, C } };
},
};
s.router.dispatchRegister(reactor, 'reactor');
reactor.emitter.emit('stateChange');
assert.equal(s.F_in, 42);
assert.equal(s.Cs_in[12], 800);
});
test('TSS measurement updates C_TS via _updateMeasurement', () => {
const s = makeSettler();
s._updateMeasurement('quantity (tss)', 7000);
assert.equal(s.C_TS, 7000);
});
test('downstream machine becomes returnPump', () => {
const s = makeSettler();
const pump = {
config: { general: { name: 'pump', id: 'p-1' }, functionality: { positionVsParent: 'downstream' } },
measurements: { emitter: new EventEmitter() },
};
s.router.dispatchRegister(pump, 'machine');
assert.equal(s.returnPump, pump);
assert.equal(pump.upstreamSource, s);
});
test('getStatusBadge returns idle when F_in=0, green when flowing', () => {
const s = makeSettler();
const idle = s.getStatusBadge();
assert.equal(idle.fill, 'blue');
s.F_in = 100;
s.C_TS = 5000;
const C = new Array(NUM_SPECIES).fill(10);
C[12] = 3000;
s.Cs_in = C;
const active = s.getStatusBadge();
assert.equal(active.fill, 'green');
assert.ok(active.text.includes('F_in'));
});