Files
alpenwerk-hr/tests/components/VertragTab.test.tsx
Andrei Laas 779beb4478 Hay-Grade statt Verwendungsgruppe A--F
A--F stammte aus der Spezifikation, nicht vom Kunden: sechs erfundene Stufen
mit erfundenen Beschreibungen. Der Kunde bewertet nach Hay und hat die Liste
geschickt -- 13 Stufen plus einen Generic Grade.

Dieselbe Spalte fuellt im Cornerstone-Extrakt die Grade ID. Solange dort A--F
steht, ist die Datei in jeder Zeile falsch, ohne dass es beim Erzeugen
auffaellt: das Zielsystem kennt diese Kennungen nicht.

Der Typ heisst weiter paygrade_type, ist aber jetzt eine Domain ueber text mit
CHECK statt eines Aufzaehlungstyps. Ein Enum laesst sich nicht umschreiben --
Werte entfernen geht gar nicht, und add value darf im selben Vorgang, der den
neuen Wert schreibt, nicht benutzt werden. Wichtiger: die rund zehn
SQL-Funktionen, die den Wert nach paygrade_type umwandeln, bleiben unveraendert
gueltig. Jede von ihnen neu zu erzeugen hiesse, zehnmal die Gelegenheit zu
haben, aus einer veralteten Vorlage zu kopieren.

Zwei Funktionen muessen doch angefasst werden, beide per Punktaenderung an der
laufenden Definition statt per Kopie aus einer Datei: der Vorgabewert B in
hire_employee und die Beschriftung im Protokoll von promote_employee.

Der Bestand bekommt den Generic Grade. Aus A--F liesse sich kein Hay-Grade
ableiten: andere Einteilung, andere Anzahl. Geraten saehe im Extrakt genauso
aus wie erhoben.
2026-09-28 11:13:41 +02:00

150 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { VertragTab } from "@/components/employees/tabs/VertragTab";
import type { Database } from "@/lib/types";
type EmployeeRow = Database["public"]["Tables"]["employees"]["Row"];
// Auf dem Vertragsblatt stand ein Feld „Merkmale" mit allem Zutreffenden,
// durch Kommas getrennt — und einem Gedankenstrich, wenn nichts zutraf.
// Daraus liess sich nicht ablesen, ob jemand keinen Dienstwagen hat oder ob
// die Frage nie beantwortet wurde. Und beim Dienstwagen fehlte, worum es
// eigentlich geht: ob Verbrenner oder E-KFZ.
function mitarbeiter(teil: Partial<EmployeeRow> = {}): EmployeeRow {
return {
id: "e1",
personnel_number: 3038,
first_name: "Hannah",
last_name: "Winkler",
gender: "w",
birth_date: "1990-04-01",
sv_nummer: null,
nationality: "Österreich",
hat_aufenthaltstitel: false,
aufenthaltstitel_bis: null,
address: null,
address_country: null,
postal_code: null,
city: null,
email: null,
phone: null,
job_title: "IT-Security-Spezialist:in",
location_id: "l1",
employment_type: "Vollzeit",
weekly_hours: 38.5,
monthly_salary_gross: null,
contract_type: "unbefristet",
contract_end_date: null,
paygrade: "HG13",
source: "Extern",
status: "Aktiv",
entry_date: "2017-07-15",
exit_date: null,
exit_reason: null,
karenz_start_date: null,
karenz_return_date: null,
absence_type: null,
avatar_color: null,
worker_type: "Angestellte:r",
collective_agreement: "Handel",
work_days: ["Mo", "Di", "Mi", "Do", "Fr"],
is_betriebsrat: false,
has_dienstwagen: false,
dienstwagen_art: null,
has_kuendigungsschutz: false,
kuendigungsschutz_bis: null,
teilzeit_art: null,
teilzeit_bis: null,
is_laterale_fuehrung: false,
is_c_level: false,
title_prefix: [],
title_suffix: [],
emergency_contact_name: null,
emergency_contact_phone: null,
emergency_contact_relation: null,
created_at: "2017-07-15T00:00:00.000Z",
updated_at: "2017-07-15T00:00:00.000Z",
...teil,
} as EmployeeRow;
}
/** Der Wert, der unter einer Beschriftung steht. */
function wertZu(label: string): string {
return screen.getByText(label).parentElement!.querySelector("dd")!.textContent ?? "";
}
describe("VertragTab — Merkmale", () => {
it("führt jedes Merkmal als eigene Zeile, nicht als Aufzählung", () => {
render(<VertragTab employee={mitarbeiter()} />);
for (const label of ["Dienstwagen", "Betriebsrat", "Laterale Führung", "C-Level"]) {
expect(screen.getByText(label)).toBeInTheDocument();
}
expect(screen.queryByText("Merkmale")).not.toBeInTheDocument();
});
it("sagt Nein, statt das Feld leer zu lassen", () => {
// „–" liesse offen, ob niemand die Frage beantwortet hat.
render(<VertragTab employee={mitarbeiter()} />);
expect(wertZu("Dienstwagen")).toBe("Nein");
expect(wertZu("Betriebsrat")).toBe("Nein");
expect(wertZu("C-Level")).toBe("Nein");
});
it("nennt beim Dienstwagen die Antriebsart statt eines blossen Ja", () => {
render(<VertragTab employee={mitarbeiter({ has_dienstwagen: true, dienstwagen_art: "Elektro" })} />);
expect(wertZu("Dienstwagen")).toBe("E-KFZ");
});
it("unterscheidet den Verbrenner davon", () => {
render(<VertragTab employee={mitarbeiter({ has_dienstwagen: true, dienstwagen_art: "Verbrenner" })} />);
expect(wertZu("Dienstwagen")).toBe("Verbrenner");
});
it("zeigt gesetzte Merkmale als Ja", () => {
render(<VertragTab employee={mitarbeiter({ is_betriebsrat: true, is_c_level: true })} />);
expect(wertZu("Betriebsrat")).toBe("Ja");
expect(wertZu("C-Level")).toBe("Ja");
expect(wertZu("Laterale Führung")).toBe("Nein");
});
});
describe("VertragTab — Kündigungsschutz", () => {
it("nennt das Enddatum statt eines blossen Ja", () => {
// „Ja" allein liesse offen, ob der Schutz noch läuft — und genau danach
// fragt jemand, der auf dieses Blatt schaut.
render(<VertragTab employee={mitarbeiter({ has_kuendigungsschutz: true, kuendigungsschutz_bis: "2027-06-30" })} />);
expect(wertZu("Besonderer Kündigungsschutz")).toBe("bis 30.06.2027");
});
it("sagt es auch, wenn das Ende offen ist", () => {
render(<VertragTab employee={mitarbeiter({ has_kuendigungsschutz: true, kuendigungsschutz_bis: null })} />);
expect(wertZu("Besonderer Kündigungsschutz")).toBe("Ja (Ende offen)");
});
it("steht ohne Schutz auf Nein", () => {
render(<VertragTab employee={mitarbeiter()} />);
expect(wertZu("Besonderer Kündigungsschutz")).toBe("Nein");
});
});
// Die Teilzeitvarianten sind keine Abwesenheiten, sondern ein Zustand mit
// weniger Stunden. Damit darüber berichtet werden kann, steht die Variante an
// der Person — und dann muss sie auch am Profil zu sehen sein.
describe("VertragTab — Teilzeitvariante", () => {
it("nennt Variante und Ende", () => {
render(<VertragTab employee={mitarbeiter({ teilzeit_art: "Bildungsteilzeit", teilzeit_bis: "2027-06-30" })} />);
expect(wertZu("Teilzeitvariante")).toBe("Bildungsteilzeit bis 30.06.2027");
});
it("sagt es auch, wenn das Ende offen ist", () => {
render(<VertragTab employee={mitarbeiter({ teilzeit_art: "Elternteilzeit", teilzeit_bis: null })} />);
expect(wertZu("Teilzeitvariante")).toBe("Elternteilzeit (Ende offen)");
});
it("bleibt leer, wo keine besteht", () => {
render(<VertragTab employee={mitarbeiter()} />);
expect(wertZu("Teilzeitvariante")).toBe("–");
});
});