Files
ApiCore/ApiCore-Frontend/src/lib/winter-checks/winter.spec.ts
T
Nick SzaunigandClaude Opus 5.5 fac66882fa feat: Ein-/Auswinterung und Winterverluste je Volk
- WinterCheck per colony, winter and season (autumn/spring), every field
  editable; loss causes limited to the COLOSS monitoring categories.
- Summary per winter and apiary: loss rate lost/wintered, marked
  provisional while colonies are not yet checked in spring - an unchecked
  colony never counts as survived.
- A loss marks the colony deceased only on explicit request, in the same
  transaction and audited.
- Permissions winter-checks:read/create/update granted by migration to
  beekeeper and staff roles; winter checks included in backups.
- Page "Überwinterung": next action first, one button per row until the
  colony is wintered, German number format.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 17:32:03 +02:00

107 lines
2.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { Colony } from "@/lib/colonies/types";
import type { WinterCheckWithColony } from "./types";
import { buildWinterRows, winterLabel, winterYearFor } from "./winter";
function colony(overrides: Partial<Colony>): Colony {
return {
id: "c1",
code: "V-01",
apiaryId: "a",
hiveType: null,
originText: null,
colonyType: "PRODUCTION_COLONY",
status: "ACTIVE",
strength: null,
broodStatus: null,
feedStatus: null,
healthStatus: null,
notes: null,
currentQueenId: null,
createdAt: "",
updatedAt: "",
deactivatedAt: null,
...overrides,
};
}
const deadColony = {
id: "c1",
code: "V-01",
status: "DECEASED",
apiaryId: "a",
apiary: { id: "a", name: "Obstwiese" },
};
function check(overrides: Partial<WinterCheckWithColony>): WinterCheckWithColony {
return {
id: "w1",
colonyId: "c1",
userId: "u",
winterYear: 2026,
season: "AUTUMN",
date: "2026-10-01T00:00:00.000Z",
occupiedSeams: null,
feedStockKg: null,
queenPresent: null,
outcome: null,
lossCause: null,
notes: null,
createdAt: "",
updatedAt: "",
colony: { ...deadColony, status: "ACTIVE" },
...overrides,
};
}
describe("winterYearFor / winterLabel", () => {
it("maps autumn and spring to the same winter", () => {
expect(winterYearFor(new Date(2026, 9, 1))).toBe(2026);
expect(winterYearFor(new Date(2027, 2, 20))).toBe(2026);
expect(winterLabel(2026)).toBe("Winter 2026/27");
});
});
describe("buildWinterRows", () => {
it("lists living colonies without records and hides old dead ones", () => {
const groups = buildWinterRows(
[colony({ id: "c1" }), colony({ id: "c2", code: "V-02", status: "DECEASED" })],
[],
new Map([["a", "Obstwiese"]]),
);
expect(groups).toHaveLength(1);
expect(groups[0].rows.map((row) => row.colonyId)).toEqual(["c1"]);
});
it("keeps a colony that died this winter, with its loss record", () => {
const groups = buildWinterRows(
[],
[
check({ colony: deadColony }),
check({
id: "w2",
season: "SPRING",
outcome: "LOST",
lossCause: "DEAD_OR_EMPTY",
colony: deadColony,
}),
],
new Map(),
);
const [row] = groups[0].rows;
expect(row).toMatchObject({ isLiving: false });
expect(row.autumn?.id).toBe("w1");
expect(row.spring?.outcome).toBe("LOST");
expect(groups[0].apiaryName).toBe("Obstwiese");
});
it("sorts colony codes naturally", () => {
const groups = buildWinterRows(
[colony({ id: "c10", code: "V-10" }), colony({ id: "c2", code: "V-2" })],
[],
new Map([["a", "Obstwiese"]]),
);
expect(groups[0].rows.map((row) => row.code)).toEqual(["V-2", "V-10"]);
});
});