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:
parent
cc4eefcb86
commit
a8cc7eca5e
8 changed files with 269 additions and 122 deletions
|
|
@ -10,6 +10,7 @@ import { remapProjectState } from "../src/domain/models/project-transfer.model.j
|
|||
import { createNamedProjectSnapshotSchema } from "../src/shared/validation/project-snapshot.schemas.js";
|
||||
import { createDefaultExternalCsvConfiguration } from "../src/external-model/csv/external-csv-contracts.js";
|
||||
import { externalCsvTestColumns } from "./fixtures/revit-csv-fixtures.js";
|
||||
import { zodIssues } from "./support/zod-assertions.js";
|
||||
|
||||
/** Removes the fields introduced by snapshot schema version 9. */
|
||||
function withoutVersionNineFields<
|
||||
|
|
@ -425,11 +426,20 @@ describe("project state snapshot model", () => {
|
|||
|
||||
const mislabeled = protectedSnapshot();
|
||||
mislabeled.schemaVersion = 5 as typeof mislabeled.schemaVersion;
|
||||
assert.throws(() => parseProjectStateSnapshot(mislabeled));
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(mislabeled),
|
||||
zodIssues(
|
||||
["project", "unrecognized_keys", "workStage"],
|
||||
["distributionBoards.0", "unrecognized_keys", "boardNumber"]
|
||||
)
|
||||
);
|
||||
|
||||
const missingCover = structuredClone(protectedSnapshot());
|
||||
delete (missingCover.project as Record<string, unknown>).workStage;
|
||||
assert.throws(() => parseProjectStateSnapshot(missingCover));
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(missingCover),
|
||||
zodIssues(["project.workStage", "invalid_type"])
|
||||
);
|
||||
});
|
||||
|
||||
it("upgrades snapshot version 4 with the existing quantity as manual share", () => {
|
||||
|
|
@ -468,12 +478,57 @@ describe("project state snapshot model", () => {
|
|||
it("rejects malformed baseline and unknown snapshot shapes", () => {
|
||||
const outdated = structuredClone(minimalSnapshot());
|
||||
delete (outdated.project as Record<string, unknown>).description;
|
||||
assert.throws(() => parseProjectStateSnapshot(outdated));
|
||||
assert.throws(() =>
|
||||
parseProjectStateSnapshot({
|
||||
...minimalSnapshot(),
|
||||
schemaVersion: projectStateSnapshotSchemaVersion + 1,
|
||||
})
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(outdated),
|
||||
zodIssues(["project.description", "invalid_type"])
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
parseProjectStateSnapshot({
|
||||
...minimalSnapshot(),
|
||||
schemaVersion: projectStateSnapshotSchemaVersion + 1,
|
||||
}),
|
||||
zodIssues(["schemaVersion", "invalid_value"])
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects invalid structure references", () => {
|
||||
const boardFloor = protectedSnapshot();
|
||||
(boardFloor.distributionBoards[0] as { floorId: string | null }).floorId =
|
||||
"missing";
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(boardFloor),
|
||||
/distribution board floor reference is invalid/
|
||||
);
|
||||
|
||||
const roomFloor = protectedSnapshot();
|
||||
roomFloor.rooms.push({
|
||||
id: "room-1",
|
||||
projectId: "project-1",
|
||||
floorId: "missing",
|
||||
roomNumber: "001",
|
||||
roomName: "Technik",
|
||||
areaM2: null,
|
||||
});
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(roomFloor),
|
||||
/room floor reference is invalid/
|
||||
);
|
||||
|
||||
const circuitSection = protectedSnapshot();
|
||||
circuitSection.circuits[0]!.sectionId = "missing";
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(circuitSection),
|
||||
/circuit section reference is invalid/
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects circuits whose reserve state contradicts their device rows", () => {
|
||||
const withoutRows = protectedSnapshot();
|
||||
withoutRows.circuits[0]!.isReserve = false;
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(withoutRows),
|
||||
/reserve state must match its device rows/
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -580,7 +635,10 @@ describe("project state snapshot model", () => {
|
|||
const floorWithoutBuildingField = structuredClone(snapshot);
|
||||
delete (floorWithoutBuildingField.floors[1] as Record<string, unknown>)
|
||||
.buildingId;
|
||||
assert.throws(() => parseProjectStateSnapshot(floorWithoutBuildingField));
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(floorWithoutBuildingField),
|
||||
zodIssues(["floors.1.buildingId", "invalid_type"])
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps room areas and upgrades snapshot version 7 with an empty area", () => {
|
||||
|
|
@ -633,7 +691,13 @@ describe("project state snapshot model", () => {
|
|||
|
||||
const mislabeled = structuredClone(snapshot);
|
||||
mislabeled.schemaVersion = 6 as typeof mislabeled.schemaVersion;
|
||||
assert.throws(() => parseProjectStateSnapshot(mislabeled));
|
||||
assert.throws(
|
||||
() => parseProjectStateSnapshot(mislabeled),
|
||||
zodIssues(
|
||||
["", "unrecognized_keys", "buildings"],
|
||||
["floors.0", "unrecognized_keys", "buildingId"]
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -654,18 +718,26 @@ describe("named project snapshot request", () => {
|
|||
});
|
||||
|
||||
it("rejects stale-shaped and excessive input", () => {
|
||||
assert.throws(() =>
|
||||
createNamedProjectSnapshotSchema.parse({
|
||||
expectedRevision: -1,
|
||||
name: "",
|
||||
unexpected: true,
|
||||
})
|
||||
assert.throws(
|
||||
() =>
|
||||
createNamedProjectSnapshotSchema.parse({
|
||||
expectedRevision: -1,
|
||||
name: "",
|
||||
unexpected: true,
|
||||
}),
|
||||
zodIssues(
|
||||
["expectedRevision", "too_small"],
|
||||
["name", "too_small"],
|
||||
["", "unrecognized_keys", "unexpected"]
|
||||
)
|
||||
);
|
||||
assert.throws(() =>
|
||||
createNamedProjectSnapshotSchema.parse({
|
||||
expectedRevision: 0,
|
||||
name: "x".repeat(201),
|
||||
})
|
||||
assert.throws(
|
||||
() =>
|
||||
createNamedProjectSnapshotSchema.parse({
|
||||
expectedRevision: 0,
|
||||
name: "x".repeat(201),
|
||||
}),
|
||||
zodIssues(["name", "too_big"])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue