import { describe, expect, it } from "vitest" import { alsCsv } from "./screens/csv" import { kalenderDatei } from "./screens/kalender" import { dauer, de, deOderStrich, eur, isoTag, schnittpreis, summe } from "./format" describe("Zahlen im deutschen Format", () => { it("setzt Punkt als Tausender- und Komma als Dezimaltrennzeichen", () => { expect(de(48250)).toBe("48.250") expect(de(1234.5, 1)).toBe("1.234,5") expect(eur(89.1)).toBe("89,10") }) it("macht aus fehlenden Werten eine Null, nicht NaN", () => { expect(de(null)).toBe("0") expect(de(undefined)).toBe("0") }) it("unterscheidet mit deOderStrich zwischen null und unbekannt", () => { expect(deOderStrich(0)).toBe("0") expect(deOderStrich(null)).toBe("–") }) }) describe("dauer", () => { it("zeigt unter einer Stunde nur Minuten", () => { expect(dauer(2700)).toBe("45 Min.") }) it("zeigt darüber Stunden und Minuten zweistellig", () => { expect(dauer(8040)).toBe("2 h 14 Min.") }) it("zeigt einen Strich statt „0 min", () => { expect(dauer(0)).toBe("–") expect(dauer(null)).toBe("–") }) }) describe("schnittpreis", () => { it("gewichtet nach Menge, nicht nach Anzahl der Tankungen", () => { // 10 l zu 2,00 € und 90 l zu 1,00 €: der Schnitt muss nahe 1,10 liegen, // nicht bei 1,50 (dem Mittel der Einzelpreise). const schnitt = schnittpreis([ { liters: 10, fuel_total_eur: 20 }, { liters: 90, fuel_total_eur: 90 }, ]) expect(schnitt).toBeCloseTo(1.1, 2) }) it("liefert 0 statt einer Division durch null", () => { expect(schnittpreis([])).toBe(0) expect(schnittpreis([{ liters: 0, fuel_total_eur: 10 }])).toBe(0) }) }) describe("summe", () => { it("überspringt fehlende Werte", () => { expect(summe([{ a: 1 }, { a: null }, { a: 3 }], (e) => e.a ?? 0)).toBe(4) }) }) describe("isoTag", () => { it("gibt das lokale Datum aus, nicht das UTC-Datum", () => { // 23:30 Ortszeit ist in UTC schon der Folgetag — der Tag darf nicht kippen. const spaet = new Date(2026, 7, 11, 23, 30) expect(isoTag(spaet)).toBe("2026-08-11") }) }) describe("CSV-Ausgabe", () => { it("trennt mit Semikolon und schreibt Dezimalkomma", () => { const csv = alsCsv(["Strecke", "Ort"], [[42.5, "München"]]) expect(csv).toContain("Strecke;Ort") expect(csv).toContain("42,5;München") }) it("beginnt mit einem BOM, damit Excel die Umlaute richtig liest", () => { expect(alsCsv(["a"], [])[0]).toBe("") }) it("schützt Felder mit Semikolon oder Anführungszeichen", () => { const csv = alsCsv(["Text"], [['Er sagte "hallo"; dann ging er']]) expect(csv).toContain('"Er sagte ""hallo""; dann ging er"') }) }) describe("Kalenderdatei", () => { it("erzeugt einen ganztägigen Termin mit Erinnerung zwei Tage vorher", () => { const ics = kalenderDatei("Ölwechsel", "2027-03-14", "laut Prognose") expect(ics).toContain("BEGIN:VCALENDAR") expect(ics).toContain("DTSTART;VALUE=DATE:20270314") expect(ics).toContain("SUMMARY:Ölwechsel") expect(ics).toContain("TRIGGER:-P2D") expect(ics.trimEnd().endsWith("END:VCALENDAR")).toBe(true) }) it("schützt Sonderzeichen im Titel", () => { expect(kalenderDatei("Service; Öl, Filter", "2027-01-01")).toContain( "SUMMARY:Service\\; Öl\\, Filter", ) }) })