Tighten rejection tests to their expected errors

Every assert.throws now names the error it expects, so a broken fixture
or an unrelated failure can no longer satisfy a rejection test. Zod
rejections are matched by issue path and code via tests/support/zod-assertions.ts.

Restore snapshot coverage lost with the release baseline: invalid board
floor, room floor and circuit section references and a reserve state
that contradicts the device rows are rejected again under test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Julian Appel 2026-10-29 12:27:46 +01:00
parent cc4eefcb86
commit a8cc7eca5e
8 changed files with 269 additions and 122 deletions

View file

@ -35,6 +35,7 @@ import {
type EstimateBalanceSnapshot,
type EstimateRowSnapshot,
} from "../src/shared/estimate-balance/estimate-balance.js";
import { zodIssues, type ExpectedZodIssue } from "./support/zod-assertions.js";
const round2 = (value: number) => roundEstimateValue(value, 2);
let nextId = 0;
@ -236,22 +237,25 @@ describe("estimate balance snapshots and commands", () => {
it("validates snapshots strictly", () => {
const valid = templateExample();
assert.equal(parseEstimateBalanceSnapshot(valid).groups[4]!.rows[3]!.sortOrder, 3);
const invalid: Array<(balance: EstimateBalanceSnapshot) => void> = [
(balance) => (balance.groups[0]!.rows[0]!.cosPhi = 0),
(balance) => (balance.groups[0]!.rows[0]!.simultaneityFactor = 1.5),
(balance) => (balance.groups[0]!.rows[0]!.quantity = -1),
(balance) => (balance.groups[0]!.rows[0]!.name = " Leerzeichen "),
(balance) => (balance.groups[0]!.rows[0]!.supply = ""),
(balance) => (balance.groups[0]!.title = ""),
(balance) => (balance.dateIso = "30.06.2023"),
(balance) => (balance.reserveAvPercent = 101),
(balance) => (balance.groups[1]!.rows[0]!.id = balance.groups[0]!.rows[0]!.id),
(balance) => ((balance.groups[0]!.rows[0] as unknown as Record<string, unknown>).extra = 1),
const invalid: Array<[(balance: EstimateBalanceSnapshot) => void, ExpectedZodIssue]> = [
[(balance) => (balance.groups[0]!.rows[0]!.cosPhi = 0), ["groups.0.rows.0.cosPhi", "too_small"]],
[(balance) => (balance.groups[0]!.rows[0]!.simultaneityFactor = 1.5), ["groups.0.rows.0.simultaneityFactor", "too_big"]],
[(balance) => (balance.groups[0]!.rows[0]!.quantity = -1), ["groups.0.rows.0.quantity", "too_small"]],
[(balance) => (balance.groups[0]!.rows[0]!.name = " Leerzeichen "), ["groups.0.rows.0.name", "custom"]],
[(balance) => (balance.groups[0]!.rows[0]!.supply = ""), ["groups.0.rows.0.supply", "custom"]],
[(balance) => (balance.groups[0]!.title = ""), ["groups.0.title", "custom"]],
[(balance) => (balance.dateIso = "30.06.2023"), ["dateIso", "invalid_format"]],
[(balance) => (balance.reserveAvPercent = 101), ["reserveAvPercent", "too_big"]],
[(balance) => (balance.groups[1]!.rows[0]!.id = balance.groups[0]!.rows[0]!.id), ["groups", "custom"]],
[
(balance) => ((balance.groups[0]!.rows[0] as unknown as Record<string, unknown>).extra = 1),
["groups.0.rows.0", "unrecognized_keys", "extra"],
],
];
for (const mutate of invalid) {
for (const [mutate, expectedIssue] of invalid) {
const balance = structuredClone(valid);
mutate(balance);
assert.throws(() => parseEstimateBalanceSnapshot(balance));
assert.throws(() => parseEstimateBalanceSnapshot(balance), zodIssues(expectedIssue));
}
assert.equal(
createEstimateBalanceRequestSchema.safeParse({