Files
gutscheintracker/tests/vouchers-validate.test.ts

66 lines
4.1 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { validateVoucher, formatEuro, formatWert, formatMindestbestellwert, euroToCents, parseShopUrl, parseVoucherFields, VOUCHER_SOON_DAYS, isExpiringSoon } from "../lib/vouchers";
describe("validateVoucher", () => {
it("lehnt negativen Rest und Rest über Wert ab", () => {
const base = { name: "X", anbieter: "Y", wertCents: 5000, restCents: 6000, ablaufdatum: null };
expect(validateVoucher(base)).toContain("restCents");
expect(validateVoucher({ ...base, restCents: -1 })).toContain("restCents");
});
it("prozent: 1-100 gültig, Rest entfällt, Mindest optional", () => {
const base = { name: "X", anbieter: "Y", wertTyp: "prozent", wertCents: 0, restCents: 0, prozentWert: 20, ablaufdatum: null };
expect(validateVoucher(base)).toEqual([]);
expect(validateVoucher({ ...base, prozentWert: 0 })).toContain("prozentWert");
expect(validateVoucher({ ...base, prozentWert: 101 })).toContain("prozentWert");
expect(validateVoucher({ ...base, prozentWert: 12.5 })).toContain("prozentWert");
expect(validateVoucher({ ...base, mindestbestellwertCents: 5000 })).toEqual([]);
expect(validateVoucher({ ...base, mindestbestellwertCents: -1 })).toContain("mindestbestellwertCents");
expect(validateVoucher({ ...base, wertTyp: "falsch" })).toContain("wertTyp");
});
it("euroToCents versteht Komma- und Punkteingaben", () => {
expect(euroToCents("25,50")).toBe(2550);
expect(euroToCents("25.50")).toBe(2550);
expect(euroToCents("1.000,50")).toBe(100050);
expect(euroToCents("20")).toBe(2000);
expect(euroToCents("")).toBeNull();
expect(euroToCents(undefined)).toBeNull();
expect(Number.isNaN(euroToCents("abc") as number)).toBe(true);
});
it("parseVoucherFields teilt POST- und PATCH-Logik", () => {
const euro = parseVoucherFields({ name: "X", anbieter: "Y", wertCents: 1000, restCents: 500, shopUrl: "shop.de" });
expect(euro.errors).toEqual([]);
expect(euro.fields.wertTyp).toBe("euro");
expect(euro.fields.restCents).toBe(500);
expect(euro.fields.shopUrl).toBe("https://shop.de/");
const prozent = parseVoucherFields({ name: "X", anbieter: "Y", wertTyp: "prozent", prozentWert: 20, reminderDays: [] });
expect(prozent.errors).toEqual([]);
expect(prozent.fields.explicitNone).toBe(true);
expect(prozent.fields.reminderDays).toEqual([]);
expect(parseVoucherFields({ name: "X", anbieter: "Y", wertCents: 100, shopUrl: "javascript:alert(1)" }).errors).toEqual(["shopUrl"]);
expect(parseVoucherFields({ name: "X", anbieter: "Y", wertCents: 100, providerDomain: "keine domain" }).errors).toEqual(["providerDomain"]);
expect(parseVoucherFields({ name: "X", anbieter: "Y", wertCents: 100, reminderDays: "nonsens" }).errors).toEqual(["reminderDays"]);
});
it("parseShopUrl akzeptiert nur http(s)-Links", () => {
expect(parseShopUrl("")).toEqual({ url: null, error: false });
expect(parseShopUrl(null)).toEqual({ url: null, error: false });
expect(parseShopUrl("https://shop.de/gutschein")).toEqual({ url: "https://shop.de/gutschein", error: false });
expect(parseShopUrl("shop.de")).toEqual({ url: "https://shop.de/", error: false });
expect(parseShopUrl("javascript:alert(1)")).toEqual({ url: null, error: true });
expect(parseShopUrl("ftp://shop.de")).toEqual({ url: null, error: true });
expect(parseShopUrl("keine domain")).toEqual({ url: null, error: true });
});
it("formatWert zeigt Euro oder Prozent", () => {
expect(formatWert({ wertTyp: "euro", wertCents: 2550 })).toContain("25,50");
expect(formatWert({ wertTyp: "prozent", wertCents: 0, prozentWert: 20 })).toBe("20 % Rabatt");
expect(formatMindestbestellwert(null)).toBeNull();
expect(formatMindestbestellwert(10000)).toContain("100,00");
});
it("bald-Fenster = 30 Tage (Spec)", () => {
expect(VOUCHER_SOON_DAYS).toBe(30);
const now = new Date("2026-10-18T00:00:00Z").getTime();
const in20 = new Date(now + 20 * 24 * 3600 * 1000).toISOString();
const in40 = new Date(now + 40 * 24 * 3600 * 1000).toISOString();
expect(isExpiringSoon(in20, now)).toBe(true);
expect(isExpiringSoon(in40, now)).toBe(false);
});
});