Phase 9: Tests fuer die portierte Rechenlogik
41 weitere Tests fuer Statistik, Service-Prognose und Formatierung. Die Faelle sind entlang der Regeln gewaehlt, die beim Portieren wichtig waren: Wochenbeginn Montag, Nachtspanne ueber Mitternacht, mengengewichteter Durchschnittspreis statt Mittel der Einzelpreise, Plausibilitaetsfenster beim Langzeitverbrauch, Neustart der Oelprognose ab dem letzten Wechsel samt Zeitlimit-Deckelung, BOM und Semikolon in der CSV-Ausgabe. Ein Test war zunaechst falsch: er verglich das UTC-Datum gegen eine Ortszeit-Erwartung. Der Code rechnet bewusst lokal - sonst begaenne der Monat in unserer Zeitzone einen Tag zu frueh. companion-app/README.md auf den erreichten Stand gebracht. Gesamt: 90 Unit- und Rendertests plus 9 Pruefungen gegen die laufende Home-Assistant-Instanz.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import { letzterOelwechsel, oelwechselPrognose } from "./service"
|
||||
import type { Fahrzeug } from "./profilAdapter"
|
||||
|
||||
function fahrzeug(odo: number, modus = "hersteller"): Fahrzeug {
|
||||
return {
|
||||
fin: "",
|
||||
details: "",
|
||||
erstzulassung: "",
|
||||
hu: "",
|
||||
odo,
|
||||
odoBekannt: true,
|
||||
tankPct: 0,
|
||||
reichweite: null,
|
||||
batteriespannung: null,
|
||||
gesichert: null,
|
||||
sicherheitscheck: [],
|
||||
oelwechselFaelligTs: null,
|
||||
oelwechselFaelligKm: null,
|
||||
inspektionFaelligTs: null,
|
||||
inspektionFaelligKm: null,
|
||||
smartdeal: { aktiv: false, laeuftAb: null },
|
||||
oel: { modus, km: 15000, monate: 12, herstellerKm: 30000, herstellerMonate: 24 },
|
||||
versicherung: {},
|
||||
steuer: { faellig: "" },
|
||||
reifen: { aktiv: "Sommer", anzugsmoment: null, wechsel: {}, sommer: {}, winter: {} },
|
||||
service: {},
|
||||
technik: {},
|
||||
ausstattung: [],
|
||||
}
|
||||
}
|
||||
|
||||
const BUCH = [
|
||||
{ datum: "2026-02-10", km: 40000, art: "Ölwechsel" },
|
||||
{ datum: "2025-03-05", km: 25000, art: "Inspektion" },
|
||||
]
|
||||
|
||||
describe("letzterOelwechsel", () => {
|
||||
it("findet den jüngsten Ölwechsel und ignoriert andere Arten", () => {
|
||||
expect(letzterOelwechsel(BUCH)?.datum).toBe("2026-02-10")
|
||||
})
|
||||
|
||||
it("erkennt auch die Schreibweise ohne Umlaut", () => {
|
||||
expect(letzterOelwechsel([{ datum: "2026-01-01", km: 1, art: "Oelwechsel" }])).not.toBeNull()
|
||||
})
|
||||
|
||||
it("liefert null, wenn nie einer eingetragen wurde", () => {
|
||||
expect(letzterOelwechsel([{ datum: "2026-01-01", km: 1, art: "Inspektion" }])).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe("oelwechselPrognose", () => {
|
||||
const jetzt = new Date("2026-08-11T12:00:00")
|
||||
|
||||
it("rechnet ab dem letzten Ölwechsel, nicht ab dem ersten Buchungseintrag", () => {
|
||||
// Seit 10.02. sind 182 Tage vergangen, 6000 km gefahren -> rund 33 km/Tag.
|
||||
// Ziel ist 40000 + 30000 = 70000, offen sind also 24000 km.
|
||||
const p = oelwechselPrognose(fahrzeug(46000), BUCH, jetzt)
|
||||
expect(p).not.toBeNull()
|
||||
expect(p!.restKm).toBe(24000)
|
||||
expect(p!.kmProTag).toBeGreaterThan(30)
|
||||
expect(p!.kmProTag).toBeLessThan(36)
|
||||
})
|
||||
|
||||
it("deckelt auf das Zeitlimit, wenn wenig gefahren wurde", () => {
|
||||
// Nur 100 km seit dem Wechsel: die Kilometerprognose läge Jahre entfernt,
|
||||
// das Zeitlimit von 24 Monaten greift vorher.
|
||||
const p = oelwechselPrognose(fahrzeug(40100), BUCH, jetzt)
|
||||
expect(p!.durchZeitlimit).toBe(true)
|
||||
expect(p!.datum).toBe("2028-02-10")
|
||||
})
|
||||
|
||||
it("meldet Fälligkeit sofort, wenn das Intervall überschritten ist", () => {
|
||||
const p = oelwechselPrognose(fahrzeug(75000), BUCH, jetzt)
|
||||
expect(p!.restKm).toBe(0)
|
||||
expect(p!.datum).toBe("2026-08-11")
|
||||
})
|
||||
|
||||
it("nutzt bei eigenem Intervall den kleineren der beiden Werte", () => {
|
||||
// modus "eigen": min(15000, 30000) = 15000 -> Ziel 55000, offen 9000.
|
||||
const p = oelwechselPrognose(fahrzeug(46000, "eigen"), BUCH, jetzt)
|
||||
expect(p!.restKm).toBe(9000)
|
||||
})
|
||||
|
||||
it("liefert nichts ohne bekannten Kilometerstand", () => {
|
||||
const ohne = { ...fahrzeug(0), odoBekannt: false }
|
||||
expect(oelwechselPrognose(ohne, BUCH, jetzt)).toBeNull()
|
||||
})
|
||||
|
||||
it("liefert nichts, wenn nie ein Ölwechsel eingetragen wurde", () => {
|
||||
expect(oelwechselPrognose(fahrzeug(46000), [], jetzt)).toBeNull()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user