Files
leistungsbilanz-ts/tests/project-command.model.test.ts
T

125 lines
3.2 KiB
TypeScript

import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
deserializeProjectCommand,
serializeProjectCommand,
type SerializedProjectCommand,
} from "../src/domain/models/project-command.model.js";
import {
assertCircuitUpdateProjectCommand,
createCircuitUpdateProjectCommand,
} from "../src/domain/models/circuit-project-command.model.js";
describe("serialized project commands", () => {
it("round-trips a versioned command envelope", () => {
const command: SerializedProjectCommand = {
schemaVersion: 1,
type: "circuit.update",
payload: {
circuitId: "circuit-1",
changes: {
displayName: "Werkstatt",
protectionRatedCurrent: 16,
isReserve: false,
remark: null,
},
},
};
assert.deepEqual(
deserializeProjectCommand(serializeProjectCommand(command)),
command
);
});
it("rejects values that JSON would lose or silently change", () => {
const invalidPayloads: unknown[] = [
{ value: undefined },
{ value: Number.NaN },
{ value: Number.POSITIVE_INFINITY },
{ value: new Date() },
];
for (const payload of invalidPayloads) {
assert.throws(() =>
serializeProjectCommand({
schemaVersion: 1,
type: "test.invalid",
payload: payload as never,
})
);
}
});
it("rejects cyclic payloads before persistence", () => {
const payload: Record<string, unknown> = {};
payload.self = payload;
assert.throws(
() =>
serializeProjectCommand({
schemaVersion: 1,
type: "test.cyclic",
payload: payload as never,
}),
/must not contain cycles/
);
});
it("rejects malformed serialized envelopes", () => {
assert.throws(
() =>
deserializeProjectCommand(
JSON.stringify({ schemaVersion: 0, type: "", payload: null })
),
/schema version/
);
});
});
describe("circuit update project commands", () => {
it("creates a typed command with explicit null clearing semantics", () => {
const command = createCircuitUpdateProjectCommand("circuit-1", {
displayName: null,
cableLength: 12.5,
isReserve: false,
});
assert.doesNotThrow(() => assertCircuitUpdateProjectCommand(command));
assert.deepEqual(command.payload.changes, [
{ field: "displayName", value: null },
{ field: "cableLength", value: 12.5 },
{ field: "isReserve", value: false },
]);
});
it("rejects empty, duplicate and invalid field changes", () => {
assert.throws(
() => createCircuitUpdateProjectCommand("circuit-1", {}),
/at least one change/
);
assert.throws(
() =>
assertCircuitUpdateProjectCommand({
schemaVersion: 1,
type: "circuit.update",
payload: {
circuitId: "circuit-1",
changes: [
{ field: "displayName", value: "A" },
{ field: "displayName", value: "B" },
],
},
}),
/duplicate field/
);
assert.throws(
() =>
createCircuitUpdateProjectCommand("circuit-1", {
voltage: 0,
}),
/outside its allowed range/
);
});
});