Files
leistungsbilanz-ts/tests/protection-device.test.ts
2026-07-31 07:45:48 +02:00

245 lines
7.0 KiB
TypeScript

import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
allowedRatedCurrentsAByProtectionDeviceType,
breakerTripCharacteristics,
fuseUtilizationCategories,
protectionDeviceTypes,
ratedResidualCurrentsMa,
rcdTypes,
} from "../src/shared/constants/protection-device.js";
import {
createDefaultCircuitProtection,
createDefaultGroupRcd,
} from "../src/domain/services/protection-device-defaults.js";
import { protectionDeviceConfigurationSchema } from "../src/shared/validation/protection-device.schemas.js";
import "./circuit-protection-project-command.repository.test.js";
import {
getCircuitProtectionEditorInitialValue,
toCircuitProtectionSnapshot,
} from "../src/frontend/utils/circuit-protection-editing.js";
describe("protection device catalog", () => {
it("contains exactly the agreed protection device types", () => {
assert.deepEqual(protectionDeviceTypes, [
"D02",
"NH000",
"NH00",
"NH0",
"NH1",
"NH2",
"NH3",
"LS",
"FI",
"FI_LS",
"AFDD",
]);
assert.equal("D01" in allowedRatedCurrentsAByProtectionDeviceType, false);
assert.equal("NH4" in allowedRatedCurrentsAByProtectionDeviceType, false);
});
it("exposes the agreed device-specific rated currents", () => {
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.D02, [
20, 25, 32, 35, 40, 50, 63,
]);
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.NH000, [
6, 10, 16, 20, 25, 32, 35, 40, 50, 63, 80, 100, 125, 160,
]);
assert.deepEqual(
allowedRatedCurrentsAByProtectionDeviceType.NH00,
allowedRatedCurrentsAByProtectionDeviceType.NH000
);
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.NH0, [
6, 10, 16, 20, 25, 32, 35, 40, 50, 63, 80, 100, 125, 160, 200, 224,
250,
]);
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.NH1, [
16, 20, 25, 32, 35, 40, 50, 63, 80, 100, 125, 160, 200, 224, 250,
]);
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.NH2, [
25, 32, 35, 40, 50, 63, 80, 100, 125, 160, 200, 224, 250, 300, 315,
355, 400,
]);
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.NH3, [
50, 63, 80, 100, 125, 160, 200, 224, 250, 315, 355, 400, 500, 630,
800,
]);
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.FI, [
16, 25, 40, 63, 80, 100, 125,
]);
assert.deepEqual(allowedRatedCurrentsAByProtectionDeviceType.LS, [
6, 10, 13, 16, 20, 25, 32, 40, 50, 63, 80, 100, 125,
]);
assert.deepEqual(
allowedRatedCurrentsAByProtectionDeviceType.FI_LS,
allowedRatedCurrentsAByProtectionDeviceType.LS
);
assert.deepEqual(
allowedRatedCurrentsAByProtectionDeviceType.AFDD,
allowedRatedCurrentsAByProtectionDeviceType.LS
);
assert.deepEqual(fuseUtilizationCategories, ["gG", "gR"]);
assert.deepEqual(breakerTripCharacteristics, ["B", "C", "D", "Z"]);
assert.deepEqual(rcdTypes, ["A", "AC", "B", "B+"]);
assert.deepEqual(ratedResidualCurrentsMa, [10, 30, 100, 300, 500]);
});
});
describe("protection device validation", () => {
it("accepts valid fuse, breaker, RCD, combined and AFDD configurations", () => {
const configurations = [
{
type: "D02",
ratedCurrentA: 20,
fuseUtilizationCategory: "gG",
},
{
type: "NH3",
ratedCurrentA: 800,
fuseUtilizationCategory: "gR",
},
{
type: "LS",
ratedCurrentA: 13,
tripCharacteristic: "Z",
},
{
type: "FI",
ratedCurrentA: 40,
rcdType: "A",
ratedResidualCurrentMa: 30,
},
{
type: "FI_LS",
ratedCurrentA: 16,
tripCharacteristic: "B",
rcdType: "A",
ratedResidualCurrentMa: 30,
},
{
type: "AFDD",
ratedCurrentA: 16,
tripCharacteristic: "B",
},
];
for (const configuration of configurations) {
const result =
protectionDeviceConfigurationSchema.safeParse(configuration);
assert.equal(
result.success,
true,
result.success
? undefined
: `${configuration.type}: ${result.error.message}`
);
}
});
it("rejects rated currents that do not belong to the selected type", () => {
assert.equal(
protectionDeviceConfigurationSchema.safeParse({
type: "D02",
ratedCurrentA: 16,
fuseUtilizationCategory: "gG",
}).success,
false
);
});
it("requires and forbids fields according to device function", () => {
assert.equal(
protectionDeviceConfigurationSchema.safeParse({
type: "LS",
ratedCurrentA: 16,
}).success,
false
);
assert.equal(
protectionDeviceConfigurationSchema.safeParse({
type: "FI",
ratedCurrentA: 40,
tripCharacteristic: "B",
rcdType: "A",
ratedResidualCurrentMa: 30,
}).success,
false
);
assert.equal(
protectionDeviceConfigurationSchema.safeParse({
type: "AFDD",
ratedCurrentA: 16,
tripCharacteristic: "B",
rcdType: "A",
ratedResidualCurrentMa: 30,
}).success,
false
);
});
});
describe("protection device defaults", () => {
it("maps editor values to complete circuit-owned snapshots", () => {
const initial = getCircuitProtectionEditorInitialValue(
"single_phase",
undefined
);
assert.deepEqual(initial, {
type: "FI_LS",
ratedCurrentA: 16,
tripCharacteristic: "B",
rcdType: "A",
ratedResidualCurrentMa: 30,
});
assert.deepEqual(
toCircuitProtectionSnapshot("circuit-1", initial),
{
circuitId: "circuit-1",
type: "FI_LS",
ratedCurrentA: 16,
fuseUtilizationCategory: null,
tripCharacteristic: "B",
rcdType: "A",
ratedResidualCurrentMa: 30,
}
);
});
it("creates the agreed circuit defaults", () => {
assert.deepEqual(createDefaultCircuitProtection("lighting"), {
type: "LS",
ratedCurrentA: 10,
tripCharacteristic: "B",
});
assert.deepEqual(createDefaultCircuitProtection("single_phase"), {
type: "FI_LS",
ratedCurrentA: 16,
tripCharacteristic: "B",
rcdType: "A",
ratedResidualCurrentMa: 30,
});
assert.deepEqual(createDefaultCircuitProtection("three_phase"), {
type: "FI_LS",
ratedCurrentA: 16,
tripCharacteristic: "B",
rcdType: "A",
ratedResidualCurrentMa: 30,
});
});
it("creates a 40 A, type A, 30 mA group RCD", () => {
assert.deepEqual(createDefaultGroupRcd(), {
type: "FI",
ratedCurrentA: 40,
rcdType: "A",
ratedResidualCurrentMa: 30,
});
});
it("returns independent default objects", () => {
const first = createDefaultCircuitProtection("lighting");
const second = createDefaultCircuitProtection("lighting");
assert.notEqual(first, second);
});
});