import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { buildFeederCircuitSnapshot, getDefaultFeederCircuitSection, getNextFeederCircuitIdentifier, } from "../src/frontend/utils/distribution-board-feeder-circuit.js"; import type { CircuitTreeResponseDto } from "../src/frontend/types.js"; import { createFeederCircuitAndUpdateDistributionBoard } from "../src/frontend/utils/api.js"; function tree(): CircuitTreeResponseDto { return { circuitListId: "list-main", distributionBoardId: "board-main", distributionBoardName: "NSHV", currentRevision: 2, singlePhaseVoltageV: 230, threePhaseVoltageV: 400, distributionBoardSimultaneityFactor: 1, distributionBoardTotalPower: 0, distributionBoardTotalPowerWithSimultaneityFactor: 0, headerComponents: [], footerComponents: [], sections: [ { id: "single", key: "single_phase", category: "single_phase", groupNumber: 1, displayName: "1-phasig 1", prefix: "-2F1.", sortOrder: 10, sectionTotalPower: 0, components: [], circuits: [], }, { id: "three", key: "three_phase", category: "three_phase", groupNumber: 1, displayName: "3-phasig 1", prefix: "-3F1.", sortOrder: 20, sectionTotalPower: 0, components: [], circuits: [ { id: "existing-2", circuitListId: "list-main", sectionId: "three", equipmentIdentifier: "-3F1.2", sortOrder: 10, isReserve: true, circuitTotalPower: 0, circuitApparentPower: 0, circuitCosPhi: 1, deviceRows: [], downstreamBoardLoads: [], }, { id: "existing-5", circuitListId: "list-main", sectionId: "three", equipmentIdentifier: "-3F1.5", sortOrder: 30, isReserve: true, circuitTotalPower: 0, circuitApparentPower: 0, circuitCosPhi: 1, deviceRows: [], downstreamBoardLoads: [], }, ], }, ], }; } describe("distribution-board feeder circuit planning", () => { it("prefers a three-phase section and does not fill BMK gaps", () => { const input = tree(); const section = getDefaultFeederCircuitSection(input)!; assert.equal(section.id, "three"); assert.equal(getNextFeederCircuitIdentifier(section), "-3F1.6"); }); it("builds an empty circuit with stable id, optional name and defaults", () => { const input = tree(); const snapshot = buildFeederCircuitSnapshot({ id: "new-feeder", tree: input, sectionId: "three", displayName: " ", }); assert.equal(snapshot.id, "new-feeder"); assert.equal(snapshot.equipmentIdentifier, "-3F1.6"); assert.equal(snapshot.displayName, null); assert.equal(snapshot.sortOrder, 40); assert.equal(snapshot.voltage, 400); assert.equal(snapshot.isReserve, true); assert.deepEqual(snapshot.deviceRows, []); assert.equal(snapshot.protectionDevice, null); }); it("sends circuit creation and board linking as one project command", async () => { const input = tree(); const circuit = buildFeederCircuitSnapshot({ id: "new-feeder", tree: input, sectionId: "three", displayName: "", }); type FeederCommandBody = { expectedRevision: number; command: { type: string; payload: { circuit: { id: string }; boardUpdate: { payload: { changes: Array<{ field: string; value: unknown }> } }; }; }; }; const requests: Array<{ url: string; method: string; body: FeederCommandBody }> = []; const originalFetch = globalThis.fetch; globalThis.fetch = async (request, init) => { requests.push({ url: String(request), method: init?.method ?? "GET", body: JSON.parse(String(init?.body)), }); return new Response(JSON.stringify({}), { status: 200, headers: { "Content-Type": "application/json" }, }); }; try { await createFeederCircuitAndUpdateDistributionBoard( "project-1", "board-child", { floorId: null, supplyType: "AV", simultaneityFactor: 0.8, feedingDistributionBoardId: "board-main", feedingCircuitId: circuit.id, }, circuit, 7 ); } finally { globalThis.fetch = originalFetch; } assert.equal(requests.length, 1); assert.equal(requests[0].url, "/api/projects/project-1/commands"); assert.equal(requests[0].method, "POST"); assert.equal(requests[0].body.expectedRevision, 7); assert.equal( requests[0].body.command.type, "distribution-board.create-feeder-circuit" ); assert.equal(requests[0].body.command.payload.circuit.id, "new-feeder"); assert.deepEqual( requests[0].body.command.payload.boardUpdate.payload.changes .filter((change: { field: string }) => change.field.startsWith("feeding") ) .map((change: { field: string; value: unknown }) => [ change.field, change.value, ]), [ ["feedingDistributionBoardId", "board-main"], ["feedingCircuitId", "new-feeder"], ] ); }); });