leistungsbilanz-ts/tests/circuit-section-renumber-command.test.ts
Julian Appel 7222398628 Typecheck tests against current types
tsx runs tests without type checking and tsconfig.json covers only src,
so 71 type errors had accumulated unnoticed. tsconfig.tests.json now
checks every test and helper, and npm run typecheck includes it.

Fixtures gain the fields the DTOs have grown since they were written
(manualQuantity, circuit apparent power/cos phi, downstream board loads,
section totals, building, cover and board info fields). Repository
lookups that return "row ?? null" now declare the null in their type,
which their callers already handle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 13:17:45 +01:00

171 lines
4.1 KiB
TypeScript

import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
buildCircuitSectionRenumberAssignments,
} from "../src/frontend/utils/circuit-section-renumber-command.js";
import {
renumberCircuitSectionCommand,
} from "../src/frontend/utils/api.js";
import type {
CircuitTreeCircuitDto,
CircuitTreeSectionDto,
} from "../src/frontend/types.js";
function circuit(
id: string,
equipmentIdentifier: string,
sortOrder: number
): CircuitTreeCircuitDto {
return {
id,
circuitListId: "list-1",
sectionId: "section-1",
equipmentIdentifier,
sortOrder,
isReserve: true,
circuitTotalPower: 0,
circuitApparentPower: 0,
circuitCosPhi: 1,
deviceRows: [],
downstreamBoardLoads: [],
};
}
function section(
id: string,
prefix: string,
circuits: CircuitTreeCircuitDto[]
): CircuitTreeSectionDto {
return {
id,
key: id,
displayName: id,
prefix,
sortOrder: 10,
sectionTotalPower: 0,
components: [],
circuits: circuits.map((entry) => ({
...entry,
sectionId: id,
})),
};
}
describe("circuit section renumber command adapters", () => {
it("plans sequential identifiers and skips conflicts outside the section", () => {
const sections = [
section("target", "-1F", [
circuit("circuit-1", "-1F7", 10),
circuit("circuit-2", "-1F9", 20),
circuit("circuit-3", "-1F11", 30),
]),
section("other", "-2F", [
circuit("circuit-other", "-1F2", 10),
]),
];
assert.deepEqual(
buildCircuitSectionRenumberAssignments(sections, "target"),
[
{
circuitId: "circuit-1",
expectedEquipmentIdentifier: "-1F7",
targetEquipmentIdentifier: "-1F1",
},
{
circuitId: "circuit-2",
expectedEquipmentIdentifier: "-1F9",
targetEquipmentIdentifier: "-1F3",
},
{
circuitId: "circuit-3",
expectedEquipmentIdentifier: "-1F11",
targetEquipmentIdentifier: "-1F4",
},
]
);
});
it("omits an already canonical section and rejects an unknown section", () => {
const sections = [
section("target", "-2F", [
circuit("circuit-1", "-2F1", 10),
circuit("circuit-2", "-2F2", 20),
]),
];
assert.deepEqual(
buildCircuitSectionRenumberAssignments(sections, "target"),
[]
);
assert.throws(
() =>
buildCircuitSectionRenumberAssignments(
sections,
"missing"
),
/nicht gefunden/
);
});
it("sends the complete assignment set through project history", async () => {
let requestBody: Record<string, unknown> | null = null;
const originalFetch = globalThis.fetch;
globalThis.fetch = async (_input, init) => {
requestBody = JSON.parse(
String(init?.body)
) as Record<string, unknown>;
return new Response(
JSON.stringify({
revision: {
revisionId: "revision-1",
changeSetId: "change-1",
projectId: "project-1",
revisionNumber: 1,
createdAtIso: "2026-07-25T00:00:00.000Z",
},
history: {
projectId: "project-1",
currentRevision: 1,
undoDepth: 1,
redoDepth: 0,
undoChangeSetId: "change-1",
redoChangeSetId: null,
},
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
const assignments = [
{
circuitId: "circuit-1",
expectedEquipmentIdentifier: "-2F9",
targetEquipmentIdentifier: "-2F1",
},
];
try {
await renumberCircuitSectionCommand(
"project-1",
0,
"section-1",
assignments,
"renumber"
);
} finally {
globalThis.fetch = originalFetch;
}
assert.deepEqual(requestBody, {
expectedRevision: 0,
description: "renumber",
command: {
schemaVersion: 1,
type: "circuit.renumber-section",
payload: {
sectionId: "section-1",
assignments,
},
},
});
});
});