Tests / test (push) Successful in 1m1s
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.
58 lines
3.4 KiB
JavaScript
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);
|
|
}
|
|
});
|