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>
This commit is contained in:
123
test/basic/specificClass.basic.test.js
Normal file
123
test/basic/specificClass.basic.test.js
Normal file
@@ -0,0 +1,123 @@
|
||||
'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'));
|
||||
});
|
||||
Reference in New Issue
Block a user