Files
Enelix-EMS/services/netplan-v4/gui/netplan-v4.test.mjs
T
dh 74a2d6c685
Tests / test (push) Successful in 1m1s
feat(workflow): publish verified forecast controls and consolidated docs
Approved by Daniel Haefliger for develop and beta. Author dh_Agent, authenticated account dh. Preserve published battery, charging and overall Energy Pie changes. No deployment or plant control authorization.
2026-10-08 10:02:58 +00:00

58 lines
3.4 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { workflowView } from './netplan-v4.js';
const now = Date.parse('2026-10-08T12:00:00Z');
const report = (state, overrides = {}) => ({
state, learningEnabled: state !== 'disabled', controlRequested: state === 'active',
controlActive: state === 'active', planningReady: ['ready', 'active'].includes(state),
reportFresh: true, checkedAt: new Date(now).toISOString(),
sourceReportAt: new Date(now - 10000).toISOString(), sourceFreshUntil: new Date(now + 110000).toISOString(),
reason: '', ...overrides
});
test('workflow reports all six states without deriving control from a plan', () => {
for (const [state, label] of Object.entries({ disabled: 'Ausgeschaltet', collecting: 'Sammelt Daten', learning: 'Lernt', ready: 'Bereit', active: 'Aktiv', interrupted: 'Unterbrochen' })) {
assert.equal(workflowView(report(state), now).label, label);
}
assert.equal(workflowView(undefined, now).label, 'Betriebsstatus nicht bestaetigt');
assert.equal(workflowView({ plan: { status: 'optimal', runMode: 'shadow' }, acknowledgement: { status: 'shadow_seen' } }, now).state, 'unknown');
});
test('missing, malformed or contradictory reports never claim active control', () => {
const malformed = [null, {}, report('other'), report('active', { checkedAt: 'invalid' }),
report('active', { checkedAt: 123 }), report('active', { controlActive: false }),
report('active', { controlRequested: false }), report('active', { planningReady: false }),
report('ready', { controlActive: true }), report('ready', { planningReady: false }),
report('active', { learningEnabled: 'true' })];
for (const input of malformed) assert.equal(workflowView(input, now).state, 'unknown');
});
test('active requires a fresh manager report and expires at its exact boundary', () => {
for (const overrides of [{ reportFresh: false }, { reportFresh: undefined }, { learningEnabled: false },
{ sourceReportAt: null }, { sourceReportAt: new Date(now + 1).toISOString() },
{ sourceFreshUntil: null }, { sourceFreshUntil: new Date(now).toISOString() },
{ sourceFreshUntil: new Date(now - 1).toISOString() }]) {
const view = workflowView(report('active', overrides), now);
assert.equal(view.state, 'interrupted'); assert.equal(view.controlActive, false);
}
assert.equal(workflowView(report('active'), now + 109999).state, 'active');
assert.equal(workflowView(report('active'), now + 110000).state, 'interrupted');
});
test('known reasons are understandable and unknown reasons remain visible as text', () => {
assert.match(workflowView(report('collecting', { reason: 'collecting_measurements' }), now).reason, /Messdaten werden gesammelt/);
assert.match(workflowView(report('active', { reason: 'manager_control_active' }), now).reason, /Manager bestaetigt/);
const reason = '<script>unexpected_reason</script>';
assert.equal(workflowView(report('interrupted', { reason }), now).reason, reason);
});
test('portal release assets match the canonical planner sources', async () => {
for (const file of ['netplan-v4.js', 'netplan-v4.css', 'netplan-v4.html']) {
const canonical = await readFile(new URL(file, import.meta.url), 'utf8');
const release = await readFile(new URL('../../license/changes/20261006-forecast-integration/public/' + file, import.meta.url), 'utf8');
assert.equal(release, canonical, file);
}
});