import { fireEvent, render, screen } from "@testing-library/react" import { jobTitel, sichtbareJobs } from "@/lib/wartung" import type { Job } from "@/lib/typen" import { JobKarte } from "./JobKarte" const JETZT = 1_790_000_000 // Unix-Sekunden, fester Bezugspunkt function job(teil: Partial): Job { return { id: "j1", label: "Nach Updates suchen", state: "running", group: null, log: ["$ bash -c 'sudo apt-get update'"], returncode: null, started_at: JETZT - 120, finished_at: null, ...teil, } } describe("JobKarte", () => { it("zeigt bei einem Download Fortschritt und fragt vor dem Abbrechen nach", () => { const onAbbrechen = vi.fn() render( , ) expect(screen.getByText("Download unsloth/Qwen3.8-27B-GGUF")).toBeInTheDocument() expect(screen.getByRole("progressbar")).toHaveAttribute("aria-valuenow", "42") expect(screen.getByText("42 % · 12,0 GB von 29,0 GB · noch etwa 6 min")).toBeInTheDocument() fireEvent.click(screen.getByRole("button", { name: "Abbrechen" })) expect(screen.getByRole("dialog", { name: "Auftrag abbrechen?" })).toBeInTheDocument() expect(onAbbrechen).not.toHaveBeenCalled() fireEvent.click(screen.getByRole("button", { name: "Ja, abbrechen" })) expect(onAbbrechen).toHaveBeenCalledTimes(1) }) it("nennt einen abgebrochenen Auftrag „Abgebrochen“ und nicht „Läuft“", () => { render( {}} />) expect(screen.getByText("Abgebrochen")).toBeInTheDocument() expect(screen.queryByText("Läuft")).not.toBeInTheDocument() expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() }) it("bietet bei Updates und der Suche kein Abbrechen an und zeigt bei Fehlern die letzte Meldung", () => { const { rerender } = render( {}} />, ) expect(screen.getByText("Update Hermes")).toBeInTheDocument() expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() // Die Suche läuft als Shell-Kette wie die Updates: kein Abbrechen, das womöglich nichts stoppt. rerender( {}} />) expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() rerender( , ) expect(screen.getByText("Fehler")).toBeInTheDocument() expect(screen.getByText(/Letzte Meldung: ✗ HERMES-UPDATE FEHLGESCHLAGEN/)).toBeInTheDocument() }) }) describe("jobTitel", () => { it("nennt die Bausteine wie die Oberfläche und lässt Unbekanntes stehen", () => { expect(jobTitel({ label: "Engine-Update (llama.cpp Vulkan)" })).toBe("Update Motor (llama.cpp)") expect(jobTitel({ label: "Router-Update (llama-swap)" })).toBe("Update llama-swap") expect(jobTitel({ label: "OS-Update (apt)" })).toBe("Update Betriebssystem") expect(jobTitel({ label: "Alle aktualisieren (Engine (llama.cpp) → Router (llama-swap) → Hermes-Agent → OS (apt))" })) .toBe("Alle aktualisieren (Motor → llama-swap → Hermes → Betriebssystem)") expect(jobTitel({ label: "download unsloth/Qwen3.8-27B-GGUF" })).toBe("Download unsloth/Qwen3.8-27B-GGUF") expect(jobTitel({ label: "Nach Updates suchen" })).toBe("Nach Updates suchen") }) }) describe("sichtbareJobs", () => { it("zeigt alle laufenden Aufträge jeder Gruppe und die drei zuletzt beendeten", () => { const liste = sichtbareJobs( [ job({ id: "alt", state: "done", finished_at: JETZT - 2 * 86_400 }), job({ id: "f1", state: "done", finished_at: JETZT - 50 }), job({ id: "f2", state: "failed", finished_at: JETZT - 40 }), job({ id: "f3", state: "canceled", finished_at: JETZT - 30 }), job({ id: "f4", state: "done", finished_at: JETZT - 20 }), job({ id: "download", label: "download a/b", state: "running", group: null }), job({ id: "update", group: "maintenance", state: "queued", started_at: JETZT - 10 }), ], JETZT, ) expect(liste.map((j) => j.id)).toEqual(["download", "update", "f4", "f3", "f2"]) }) })