import { describe, it, expect } from "vitest"; import { addDaysToKey, berlinDayEnd, berlinDayStart, dayKey, formatDayHeading, keyToLocalDate, localDateToKey, } from "@/src/modules/courses/lib/course-days"; describe("dayKey", () => { it("ordnet einen Kurs aus dem Datumsfeld seinem Tag zu", () => { // "2026-10-15" aus dem Formular landet als UTC-Mitternacht in der DB. expect(dayKey("2026-10-15T00:00:00.000Z")).toBe("2026-10-15"); expect(dayKey("2026-12-01T01:00:00.000Z")).toBe("2026-12-01"); }); it("ordnet einen auf Berliner Mitternacht datierten Kurs dem richtigen Tag zu", () => { // In UTC wäre es noch der 1. Oktober. expect(dayKey("2026-10-01T22:00:00.000Z")).toBe("2026-10-02"); // Winterzeit: Mitternacht Berlin = 23:00 UTC am Vortag. expect(dayKey("2026-12-01T23:00:00.000Z")).toBe("2026-12-02"); }); }); describe("addDaysToKey", () => { it("überspringt die Zeitumstellung ohne Tag doppelt oder gar nicht zu zählen", () => { // 25. Oktober 2026: Umstellung auf Winterzeit, der Tag hat 25 Stunden. expect(addDaysToKey("2026-10-24", 1)).toBe("2026-10-25"); expect(addDaysToKey("2026-10-25", 1)).toBe("2026-10-26"); expect(addDaysToKey("2026-03-28", 2)).toBe("2026-03-30"); }); }); describe("berlinDayStart / berlinDayEnd", () => { it("liefert Mitternacht Berliner Zeit, im Sommer wie im Winter", () => { expect(berlinDayStart("2026-10-15").toISOString()).toBe("2026-10-14T22:00:00.000Z"); expect(berlinDayStart("2026-12-01").toISOString()).toBe("2026-11-30T23:00:00.000Z"); expect(berlinDayEnd("2026-10-15").toISOString()).toBe("2026-10-15T21:59:59.999Z"); }); it("stimmt auch an den Tagen der Zeitumstellung", () => { // Umstellung jeweils um 01:00 UTC - die Mitternacht davor gilt noch die alte Zeit. expect(berlinDayStart("2026-10-25").toISOString()).toBe("2026-10-24T22:00:00.000Z"); expect(berlinDayEnd("2026-10-25").toISOString()).toBe("2026-10-25T22:59:59.999Z"); expect(berlinDayStart("2026-03-29").toISOString()).toBe("2026-03-28T23:00:00.000Z"); expect(berlinDayEnd("2026-03-29").toISOString()).toBe("2026-03-29T21:59:59.999Z"); }); it("schließt einen Kurs am letzten Tag des Fensters ein", () => { // Der gemeldete Fall: heute 1.10., Fenster bis einschließlich 15.10. - der // Kurs liegt als 2026-10-15T00:00Z in der DB und fiel bisher heraus. const course = new Date("2026-10-15T00:00:00.000Z"); const windowTo = berlinDayEnd(addDaysToKey("2026-10-01", 14)); expect(course <= windowTo).toBe(true); // "Mehr laden" beginnt direkt danach, ohne Lücke. expect(new Date(windowTo.getTime() + 1)).toEqual(berlinDayStart("2026-10-16")); }); }); describe("formatDayHeading", () => { it("benennt heute und morgen", () => { expect(formatDayHeading("2026-10-01", "2026-10-01")).toMatch(/^Heute · Donnerstag/); expect(formatDayHeading("2026-10-02", "2026-10-01")).toMatch(/^Morgen · Freitag/); expect(formatDayHeading("2026-10-30", "2026-10-01")).toBe("Freitag, 30. Oktober"); }); }); describe("Kalender-Umrechnung", () => { it("führt einen Tag verlustfrei hin und zurück", () => { expect(localDateToKey(keyToLocalDate("2026-10-30"))).toBe("2026-10-30"); }); }); import { durationMinutes, startOfWeekKey, weekDayKeys, } from "@/src/modules/courses/lib/course-days"; describe("Wochen", () => { it("beginnt montags - auch wenn heute Sonntag ist", () => { expect(startOfWeekKey("2026-10-01")).toBe("2026-09-28"); // Donnerstag expect(startOfWeekKey("2026-10-04")).toBe("2026-09-28"); // Sonntag expect(startOfWeekKey("2026-10-05")).toBe("2026-10-05"); // Montag }); it("liefert sieben Tage über die Zeitumstellung hinweg", () => { expect(weekDayKeys("2026-10-19")).toEqual([ "2026-10-19", "2026-10-20", "2026-10-21", "2026-10-22", "2026-10-23", "2026-10-24", "2026-10-25", ]); }); }); describe("durationMinutes", () => { it("berechnet die Dauer und verwirft Unsinn", () => { expect(durationMinutes("07:30", "08:45")).toBe(75); expect(durationMinutes("08:00", "07:00")).toBeNull(); }); });