Kuma/tests/products/product-schema.test.ts
2026-10-02 14:30:54 +02:00

58 lines
2 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { productSchema, type ProductInput } from "@/src/modules/products/schemas/product-schema";
import { cardServiceFeeCents, pricePerUnitCents } from "@/src/modules/products/lib/card-pricing";
const valid: ProductInput = {
name: "10er-Karte",
description: "",
credits: 10,
priceCents: 12000,
validityMonths: 6,
sports: ["pilates", "pilates", "yoga"],
design: { style: "solid", color: "#112233", secondaryColor: "#445566", imageUrl: null },
isActive: true,
};
describe("productSchema", () => {
it("normalisiert leere Beschreibung zu null und entfernt doppelte Kursarten", () => {
const result = productSchema.safeParse(valid);
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.description).toBeNull();
expect(result.data.sports).toEqual(["pilates", "yoga"]);
}
});
it.each([
["0 Einheiten", { credits: 0 }],
["101 Einheiten", { credits: 101 }],
["halbe Einheiten", { credits: 2.5 }],
["Preis unter 1 €", { priceCents: 99 }],
["leerer Name", { name: " " }],
["0 Monate gültig", { validityMonths: 0 }],
])("lehnt %s ab", (_label, patch) => {
expect(productSchema.safeParse({ ...valid, ...patch }).success).toBe(false);
});
it("meldet leere Zahlenfelder auf Deutsch statt als NaN", () => {
const result = productSchema.safeParse({ ...valid, priceCents: Number.NaN });
expect(result.success).toBe(false);
if (!result.success) {
expect(result.error.issues[0].message).toBe("Bitte gib einen Preis an");
}
});
it("erlaubt unbegrenzte Gültigkeit", () => {
expect(productSchema.safeParse({ ...valid, validityMonths: null }).success).toBe(true);
});
});
describe("card-pricing", () => {
it("berechnet die Servicegebühr pro Einheit", () => {
expect(cardServiceFeeCents(10, 50)).toBe(500);
});
it("rundet den Preis pro Einheit auf ganze Cents", () => {
expect(pricePerUnitCents(10000, 3)).toBe(3333);
});
});