import { describe, expect, it } from "vitest"; import { actionBadgeStyle, ANSTEHEND_STYLES, avatarColorFor, CATEGORY_STYLES, EVENT_CATEGORY, eventBadgeStyle, eventDotStyle, STATUS_STYLES, } from "@/lib/colors"; import { EVENT_TYPE_LABELS } from "@/lib/reports"; import type { HistoryEventType } from "@/lib/types"; describe("avatarColorFor", () => { it("is deterministic for the same seed", () => { expect(avatarColorFor("Maria Gruber")).toBe(avatarColorFor("Maria Gruber")); }); it("returns a value from the fixed palette (a hex color)", () => { expect(avatarColorFor("Anna Huber")).toMatch(/^#[0-9a-f]{6}$/i); }); }); describe("STATUS_STYLES", () => { it("has an entry for every employment status", () => { expect(Object.keys(STATUS_STYLES).sort()).toEqual(["Aktiv", "Ausgetreten", "Geplant", "Karenz"].sort()); }); }); describe("actionBadgeStyle", () => { it("maps known audit actions to their category style", () => { expect(actionBadgeStyle("Austritt")).toBe(STATUS_STYLES.Ausgetreten); expect(actionBadgeStyle("Neueinstellung")).toBe(STATUS_STYLES.Aktiv); }); // Gegen CATEGORY_STYLES.brand geprüft und nicht gegen einen abgetippten // Klassennamen: welche Farbe der Chip ohne eigene Bedeutung trägt, ist eine // Frage der Palette und hat sich mit der Umstellung auf das Manner-CD schon // einmal geändert. Der Test soll die Zuordnung sichern, nicht den Farbton. it("falls back to the neutral category style for an unknown action", () => { expect(actionBadgeStyle("Irgendwas Unbekanntes")).toBe(CATEGORY_STYLES.brand); }); }); // ═══ Historie: die Sprache von employee_history, nicht die des Protokolls ═══ // // Die Uebersicht und der Historie-Reiter zeigen Ereignisse der Personalakte, // holten ihre Farbe aber aus der Tabelle der Protokoll-Aktionen. Die kennt // „Neueinstellung" und „Wiedereinstellung"; die Historie sagt „Eintritt" und // „Wiedereintritt". Genau diese zwei standen dort nicht und bekamen den // neutralen Chip — in „Letzte Aktivitaeten" war „Eintritt" rosa, waehrend die // Karte daneben ihn laengst gruen zeigte. describe("eventBadgeStyle", () => { // Aus EVENT_TYPE_LABELS abgeleitet und nicht abgeschrieben: kaeme ein // zwoelftes Ereignis dazu, prueft dieser Test es mit. const ALLE = Object.keys(EVENT_TYPE_LABELS) as HistoryEventType[]; it("kennt jedes Ereignis der Personalakte", () => { expect(ALLE.length).toBeGreaterThan(0); for (const typ of ALLE) { expect(EVENT_CATEGORY[typ], typ).toBeDefined(); } }); it("gibt keinem Ereignis den neutralen Chip", () => { // Der neutrale Chip heisst „keine eigene Bedeutung". Fuer ein Ereignis // der Personalakte ist das nie die Wahrheit, sondern immer ein // Nachschlagen, das danebengegriffen hat. for (const typ of ALLE) { expect(eventBadgeStyle(typ), typ).not.toBe(CATEGORY_STYLES.brand); } }); it("faerbt Eintritt und Wiedereintritt gruen", () => { expect(eventBadgeStyle("Eintritt")).toBe(CATEGORY_STYLES.success); expect(eventBadgeStyle("Wiedereintritt")).toBe(CATEGORY_STYLES.success); }); it("faerbt den Austritt rot", () => { expect(eventBadgeStyle("Austritt")).toBe(CATEGORY_STYLES.danger); }); it("gibt Punkt und Chip derselben Zeile dieselbe Kategorie", () => { // Beide leiten aus EVENT_CATEGORY ab; vorher lagen sie in zwei // getrennten Verzeichnissen und eines davon war das falsche. for (const typ of ALLE) { expect(eventDotStyle(typ), typ).toContain( eventBadgeStyle(typ).match(/text-([a-z]+)-text/)?.[1] ?? "###" ); } }); }); describe("Uebersicht: beide Karten meinen dasselbe", () => { // Anstehend und Letzte Aktivitaeten stehen nebeneinander. Ein Eintritt darf // links nicht anders aussehen als rechts — genau das war zu sehen. it("Eintritt, Austritt und Rueckkehr stimmen ueberein", () => { expect(ANSTEHEND_STYLES.hire).toBe(eventBadgeStyle("Eintritt")); expect(ANSTEHEND_STYLES.exit).toBe(eventBadgeStyle("Austritt")); expect(ANSTEHEND_STYLES.return).toBe(eventBadgeStyle("Rückkehr")); }); it("haelt die vier Arten voneinander getrennt", () => { const werte = Object.values(ANSTEHEND_STYLES); expect(new Set(werte).size).toBe(werte.length); }); }); // Das Protokoll behaelt seinen Rueckfall, und das ist richtig: die Aktionen // schreiben die SQL-Funktionen als freien Text, eine neue kann jederzeit // dazukommen. Ihr neutraler Chip ist dann eine ehrliche Aussage. describe("actionBadgeStyle bleibt offen", () => { it("faengt eine unbekannte Aktion mit dem neutralen Chip auf", () => { expect(actionBadgeStyle("Eine neue Aktion aus einer Migration")).toBe(CATEGORY_STYLES.brand); }); });