Model complete distribution board subtrees

This commit is contained in:
2026-07-31 11:51:46 +02:00
parent bd8dd09f79
commit 13693f64b1
4 changed files with 753 additions and 0 deletions
@@ -15,6 +15,7 @@ import {
updateDistributionBoardComponentSnapshot,
} from "../src/frontend/utils/distribution-board-component-editing.js";
import "./distribution-board-component-structure-project-command.repository.test.js";
import "./distribution-board-subtree.test.js";
describe("distribution board component catalog", () => {
it("defines the agreed component roles and placement zones", () => {
+200
View File
@@ -0,0 +1,200 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
assertDistributionBoardSubtreeSnapshot,
cloneDistributionBoardSubtree,
type DistributionBoardSubtreeSnapshot,
} from "../src/domain/models/distribution-board-subtree-snapshot.model.js";
import {
createDistributionBoardDeleteSubtreeProjectCommand,
createDistributionBoardInsertSubtreeProjectCommand,
} from "../src/domain/models/distribution-board-subtree-project-command.model.js";
function createSnapshot(): DistributionBoardSubtreeSnapshot {
return {
distributionBoard: {
id: "board-1",
projectId: "project-1",
name: "UV 1",
floorId: "floor-1",
supplyType: "AV",
simultaneityFactor: 0.8,
},
circuitList: {
id: "list-1",
projectId: "project-1",
distributionBoardId: "board-1",
name: "UV 1 Stromkreisliste",
},
sections: [
{
id: "section-1",
circuitListId: "list-1",
key: "lighting",
displayName: "Beleuchtung 1",
prefix: "-1F1.",
sortOrder: 10,
category: "lighting",
groupNumber: 1,
},
],
components: [
{
component: {
id: "main-1",
circuitListId: "list-1",
sectionId: null,
equipmentIdentifier: "-Q0",
name: "Hauptschalter",
role: "main_switch",
placement: "header",
sortOrder: 10,
},
protectionDevice: null,
},
{
component: {
id: "rcd-1",
circuitListId: "list-1",
sectionId: "section-1",
equipmentIdentifier: "-1Q1.0",
name: "Gruppen-FI",
role: "group_residual_current_protection",
placement: "group",
sortOrder: 20,
},
protectionDevice: {
componentId: "rcd-1",
type: "FI",
ratedCurrentA: 40,
fuseUtilizationCategory: null,
tripCharacteristic: null,
rcdType: "A",
ratedResidualCurrentMa: 30,
},
},
],
circuits: [
{
id: "circuit-1",
circuitListId: "list-1",
sectionId: "section-1",
equipmentIdentifier: "-1F1.1",
displayName: "Licht",
sortOrder: 10,
protectionType: null,
protectionRatedCurrent: null,
protectionCharacteristic: null,
cableType: "NYM-J",
cableCrossSection: "3x1,5 mm²",
cableLength: 10,
rcdAssignment: null,
terminalDesignation: null,
voltage: 230,
controlRequirement: null,
status: null,
isReserve: false,
remark: null,
deviceRows: [
{
id: "row-1",
circuitId: "circuit-1",
linkedProjectDeviceId: "device-1",
legacyConsumerId: "legacy-1",
sortOrder: 10,
name: "Leuchte",
displayName: "Leuchte",
phaseType: "single_phase",
connectionKind: null,
costGroup: null,
category: null,
level: null,
roomId: "room-1",
roomNumberSnapshot: "1.01",
roomNameSnapshot: "Büro",
quantity: 1,
powerPerUnit: 0.1,
simultaneityFactor: 1,
cosPhi: 0.9,
remark: null,
overriddenFields: null,
},
],
protectionDevice: {
circuitId: "circuit-1",
type: "LS",
ratedCurrentA: 10,
fuseUtilizationCategory: null,
tripCharacteristic: "B",
rcdType: null,
ratedResidualCurrentMa: null,
},
},
],
};
}
describe("distribution-board subtree snapshot", () => {
it("validates complete populated board structures and commands", () => {
const snapshot = createSnapshot();
assert.doesNotThrow(() =>
assertDistributionBoardSubtreeSnapshot(snapshot)
);
assert.equal(
createDistributionBoardInsertSubtreeProjectCommand(snapshot).type,
"distribution-board.insert-subtree"
);
assert.equal(
createDistributionBoardDeleteSubtreeProjectCommand(snapshot).type,
"distribution-board.delete-subtree"
);
});
it("clones every owned id while preserving project links and values", () => {
const ids = Array.from({ length: 6 }, (_, index) => `new-${index + 1}`);
const clone = cloneDistributionBoardSubtree(
createSnapshot(),
"UV 1 Kopie",
() => ids.shift()!
);
assert.equal(clone.distributionBoard.id, "new-1");
assert.equal(clone.circuitList.id, "new-1");
assert.equal(clone.distributionBoard.name, "UV 1 Kopie");
assert.equal(clone.circuitList.name, "UV 1 Kopie Stromkreisliste");
assert.equal(clone.sections[0].id, "new-2");
assert.equal(clone.circuits[0].id, "new-3");
assert.equal(clone.components[0].component.id, "new-4");
assert.equal(clone.components[1].component.id, "new-5");
assert.equal(clone.components[1].component.sectionId, "new-2");
assert.equal(clone.components[1].protectionDevice?.componentId, "new-5");
assert.equal(clone.circuits[0].sectionId, "new-2");
assert.equal(clone.circuits[0].deviceRows[0].id, "new-6");
assert.equal(clone.circuits[0].deviceRows[0].circuitId, "new-3");
assert.equal(
clone.circuits[0].deviceRows[0].linkedProjectDeviceId,
"device-1"
);
assert.equal(clone.circuits[0].deviceRows[0].roomId, "room-1");
assert.equal(clone.circuits[0].deviceRows[0].legacyConsumerId, null);
assert.equal(clone.circuits[0].protectionDevice?.circuitId, "new-3");
assert.doesNotThrow(() => assertDistributionBoardSubtreeSnapshot(clone));
});
it("rejects broken ownership and duplicate equipment identifiers", () => {
const brokenOwnership = createSnapshot();
brokenOwnership.circuits[0].sectionId = "missing";
assert.throws(
() => assertDistributionBoardSubtreeSnapshot(brokenOwnership),
/ownership/
);
const duplicateIdentifier = createSnapshot();
duplicateIdentifier.components[0].component.equipmentIdentifier =
" -1f1.1 ";
assert.throws(
() => assertDistributionBoardSubtreeSnapshot(duplicateIdentifier),
/duplicate equipment identifier/
);
});
});