Files
mission-control-v2/frontend/src/components/cockpit/JobKarte.test.tsx
T
HitonabiandClaude Opus 5.5 bc1106ddc8 durchsicht: Rueckfragen passen aufs kleine Handy, ehrlichere Texte, Abbrechen nur wo es stoppt
Befunde der Schlussdurchsicht (Attrappe des Backends, 320 x 568 bis 1440 px):
- Rueckfragen: Bei 320 x 568 lagen "Installieren"/"Abbrechen" unter dem Bildschirmrand
  und liessen sich nicht erreichen (Dialog 791 px hoch, kein Scrollen). Jetzt hoechstens
  Bildschirmhoehe, der Text scrollt, die Knoepfe bleiben unten stehen. Gilt fuer alle.
- Installieren: Die Rueckfrage sagt jetzt, dass llama-swap beim Eintragen sofort neu laedt
  (--watch-config): laufende Antworten von Lucy/OpenChamber brechen ab, mit Rolle nach dem
  Download noch einmal. Der Ersatz-Hinweis nennt, dass das bisherige Modell "heavy" behaelt.
- Abbrechen nur noch bei Downloads (eigener Prozess). Updates und die Suche laufen als
  Shell-Kette, ein Abbruch stoppt dort nicht sicher alles.
- Auftragstitel in den Worten der Oberflaeche ("Update Motor (llama.cpp)" statt
  "Engine-Update (llama.cpp Vulkan)"); "Laeuft seit ... min" zaehlt weiter, auch wenn der
  Auftrag nichts schreibt; Ueberschriftenebene passend zum Panel.
- Updates: "Alles jetzt aktualisieren" richtet sich wie die Zeilen nach den frischen
  Details (vorher nur nach dem bis zu 10 min alten Start-Stand); "Nach Neuem suchen"
  sperrt, solange eine Suche laeuft (zwei apt-get update stolpern ueber die Sperre);
  Rueckfragetext sagt genau, was gesichert wird.
- Nach Auftragsende nur nachladen, was betroffen ist (Download: Modelle/Platte; sonst
  Versionen/Verlauf/Sicherungen) - die Update-Pruefung fragt GitHub, apt und git.
- Radar "Uebernehmen"/"Verwerfen" und "Endgueltig loeschen": Ja-Knopf gesperrt, solange
  die Aktion laeuft, und ein zweiter Klick waehrend des Schliessens loest nichts mehr aus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 17:44:40 +02:00

100 lines
4.6 KiB
TypeScript

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>): 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(
<JobKarte
job={job({
label: "download unsloth/Qwen3.8-27B-GGUF", progress: 42,
done_bytes: 12 * 1024 ** 3, total_bytes: 29 * 1024 ** 3, eta_s: 360,
})}
onAbbrechen={onAbbrechen}
/>,
)
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(<JobKarte job={job({ state: "canceled", finished_at: JETZT })} onAbbrechen={() => {}} />)
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(
<JobKarte job={job({ label: "Hermes-Agent-Update", group: "maintenance" })} onAbbrechen={() => {}} />,
)
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(<JobKarte job={job({ label: "Nach Updates suchen" })} onAbbrechen={() => {}} />)
expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument()
rerender(
<JobKarte
job={job({
label: "Hermes-Agent-Update", group: "maintenance", state: "failed", finished_at: JETZT,
log: ["$ bash -c …", "✗ HERMES-UPDATE FEHLGESCHLAGEN (Dienste laufen wieder, aber alter Stand)", ""],
})}
/>,
)
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"])
})
})