Files
pumpingStation/test/basic/control-manual.basic.test.js
znetsixe f5c6282478 refactor(units): use UnitPolicy.convert instead of hardcoded m3/h<->m3/s scalars
Replace the M3H_TO_M3S constant in control/manual.js and the `* 3600`
inline conversion in the status badge with this.unitPolicy.convert
calls. Expose unitPolicy on the frozen control context so manual
strategies pick it up without reaching into host. Matches the
contract direction in .claude/refactor/CONTRACTS.md §6.

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

72 lines
2.3 KiB
JavaScript

// Unit tests for the manual control strategy.
// Run with: node --test test/basic/control-manual.basic.test.js
const test = require('node:test');
const assert = require('node:assert/strict');
const { UnitPolicy } = require('generalFunctions');
const manual = require('../../src/control/manual');
const unitPolicy = UnitPolicy.declare({
canonical: { flow: 'm3/s' },
output: { flow: 'm3/s' },
requireUnitForTypes: [],
});
function makeGroup(name) {
const calls = { handleInput: [] };
return {
config: { general: { name } },
handleInput: async (...args) => { calls.handleInput.push(args); },
_calls: calls,
};
}
function makeMachine(name) {
const calls = { handleInput: [] };
return {
config: { general: { name } },
handleInput: async (...args) => { calls.handleInput.push(args); },
_calls: calls,
};
}
function makeLogger() {
return { info: () => {}, debug: () => {}, warn: () => {}, error: () => {} };
}
test('forwardDemand calls handleInput("parent", canonical m3/s demand) on every machine group', async () => {
const groups = { a: makeGroup('A'), b: makeGroup('B'), c: makeGroup('C') };
const ctx = { machineGroups: groups, machines: {}, unitPolicy, logger: makeLogger() };
await manual.forwardDemand(ctx, 360);
for (const g of Object.values(groups)) {
assert.equal(g._calls.handleInput.length, 1);
assert.deepEqual(g._calls.handleInput[0], ['parent', 0.1]);
}
});
test('forwardDemand with no machineGroups but direct machines splits demand evenly', async () => {
const machines = { m1: makeMachine('M1'), m2: makeMachine('M2'), m3: makeMachine('M3'), m4: makeMachine('M4') };
const ctx = { machineGroups: {}, machines, logger: makeLogger() };
await manual.forwardDemand(ctx, 80);
for (const m of Object.values(machines)) {
assert.equal(m._calls.handleInput.length, 1);
assert.deepEqual(m._calls.handleInput[0], ['parent', 'execMovement', 20]);
}
});
test('run() is a no-op (manual mode is event-driven)', async () => {
const groups = { a: makeGroup('A') };
const ctx = { machineGroups: groups, machines: {}, unitPolicy, logger: makeLogger() };
await manual.run(ctx, { percControl: 0 });
assert.equal(groups.a._calls.handleInput.length, 0);
});
test('manual exports name === "manual"', () => {
assert.equal(manual.name, 'manual');
});