Added 1B, 2 and added bootstrap again for site

This commit is contained in:
2026-05-03 22:04:45 +02:00
parent b8995b3a1b
commit d1ce485572
37 changed files with 1842 additions and 89 deletions
+30
View File
@@ -0,0 +1,30 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { CircuitNumberingService } from "../src/domain/services/circuit-numbering.service.js";
describe("circuit numbering service", () => {
it("uses highest numeric suffix + 1 and does not fill gaps", async () => {
const service = new CircuitNumberingService({
sectionRepository: {
async findById() {
return { id: "s1", prefix: "-2F" } as never;
},
},
circuitRepository: {
async listBySection() {
return [
{ equipmentIdentifier: "-2F1" },
{ equipmentIdentifier: "-2F2" },
{ equipmentIdentifier: "-2F5" },
{ equipmentIdentifier: "-2FX" },
{ equipmentIdentifier: "-1F9" },
] as never[];
},
},
});
const next = await service.getNextIdentifier("s1");
assert.equal(next, "-2F6");
});
});
+18
View File
@@ -0,0 +1,18 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
calculateCircuitTotalPower,
calculateRowTotalPower,
} from "../src/domain/calculations/circuit-power-calculation.js";
describe("circuit power calculation", () => {
it("calculates row and circuit totals from device rows", () => {
assert.equal(calculateRowTotalPower(2, 1.5, 0.5), 1.5);
const total = calculateCircuitTotalPower([
{ quantity: 2, powerPerUnit: 1.5, simultaneityFactor: 0.5 },
{ quantity: 1, powerPerUnit: 3, simultaneityFactor: 1 },
]);
assert.equal(total, 4.5);
});
});
+19
View File
@@ -0,0 +1,19 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { isMissingCircuitTreeSchemaError } from "../src/server/controllers/circuit-tree.controller.js";
describe("circuit tree controller", () => {
it("detects missing circuit-first schema errors", () => {
assert.equal(
isMissingCircuitTreeSchemaError(new Error("SqliteError: no such table: circuit_sections")),
true
);
assert.equal(isMissingCircuitTreeSchemaError(new Error("SqliteError: no such table: circuits")), true);
assert.equal(
isMissingCircuitTreeSchemaError(new Error("SqliteError: no such table: circuit_device_rows")),
true
);
assert.equal(isMissingCircuitTreeSchemaError(new Error("Some other error")), false);
});
});
+178
View File
@@ -0,0 +1,178 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { CircuitWriteService } from "../src/domain/services/circuit-write.service.js";
describe("circuit write service rules", () => {
it("rejects duplicate equipment identifiers in same circuit list", async () => {
const service = new CircuitWriteService({
circuitListRepository: {
async findById() {
return { id: "list1", projectId: "p1" } as never;
},
} as never,
circuitSectionRepository: {
async findById() {
return { id: "sec1", circuitListId: "list1" } as never;
},
} as never,
circuitRepository: {
async existsByEquipmentIdentifier() {
return true;
},
} as never,
});
await assert.rejects(
() =>
service.createCircuit("p1", "list1", {
sectionId: "sec1",
equipmentIdentifier: "-2F1",
sortOrder: 10,
}),
/Duplicate equipmentIdentifier/
);
});
it("rejects section and list mismatch", async () => {
const service = new CircuitWriteService({
circuitListRepository: {
async findById() {
return { id: "list1", projectId: "p1" } as never;
},
} as never,
circuitSectionRepository: {
async findById() {
return { id: "sec1", circuitListId: "other" } as never;
},
} as never,
circuitRepository: {
async existsByEquipmentIdentifier() {
return false;
},
} as never,
});
await assert.rejects(
() =>
service.createCircuit("p1", "list1", {
sectionId: "sec1",
equipmentIdentifier: "-2F1",
sortOrder: 10,
}),
/Section does not belong to circuit list/
);
});
it("deleting last device row keeps circuit and sets reserve", async () => {
let reserveFlag = false;
const service = new CircuitWriteService({
deviceRowRepository: {
async findById() {
return { id: "r1", circuitId: "c1" } as never;
},
async delete() {
return;
},
async countByCircuit() {
return 0;
},
} as never,
circuitRepository: {
async findById() {
return {
id: "c1",
sectionId: "s1",
circuitListId: "l1",
equipmentIdentifier: "-2F1",
sortOrder: 10,
isReserve: 0,
} as never;
},
async update(_id: string, payload: { isReserve: boolean }) {
reserveFlag = payload.isReserve;
},
} as never,
});
await service.deleteDeviceRow("r1");
assert.equal(reserveFlag, true);
});
it("creating device row in reserve circuit clears reserve status", async () => {
let reserveFlag = true;
const service = new CircuitWriteService({
circuitRepository: {
async findById() {
return {
id: "c1",
sectionId: "s1",
circuitListId: "l1",
equipmentIdentifier: "-2F1",
sortOrder: 10,
isReserve: 1,
} as never;
},
async update(_id: string, payload: { isReserve: boolean }) {
reserveFlag = payload.isReserve;
},
} as never,
deviceRowRepository: {
async countByCircuit() {
return 0;
},
async create() {
return "row1";
},
async findById() {
return { id: "row1" } as never;
},
} as never,
circuitListRepository: {} as never,
circuitSectionRepository: {} as never,
projectDeviceRepository: {
async findById() {
return { id: "pd1" } as never;
},
} as never,
});
await service.createDeviceRow("c1", {
name: "Load",
displayName: "Load",
quantity: 1,
powerPerUnit: 1,
simultaneityFactor: 1,
});
assert.equal(reserveFlag, false);
});
it("renumber affects only circuits in selected section and keeps row order untouched", async () => {
const updatedIds: string[] = [];
const service = new CircuitWriteService({
circuitSectionRepository: {
async findById() {
return { id: "s1", circuitListId: "l1", prefix: "-2F" } as never;
},
} as never,
circuitRepository: {
async listBySection() {
return [
{ id: "c1", sectionId: "s1", equipmentIdentifier: "-2F7", sortOrder: 10, isReserve: 0 },
{ id: "c2", sectionId: "s1", equipmentIdentifier: "-2F9", sortOrder: 20, isReserve: 1 },
] as never[];
},
async listByCircuitList() {
return [{ id: "x1", sectionId: "s2", equipmentIdentifier: "-3F1" }] as never[];
},
async update(circuitId: string) {
updatedIds.push(circuitId);
},
} as never,
});
const result = await service.renumberSection("s1");
assert.deepEqual(updatedIds, ["c1", "c2"]);
assert.equal(result.length, 2);
});
});