C.08 -- die Suche mit Bindestrich fand nichts. Das Feld wird per translate an "-/:.," in Leerzeichen zerlegt, die Eingabe aber nicht: "Mueller-Weiss" erzeugte das Muster mueller-weiss%, waehrend im Heuhaufen "mueller weiss" stand. Ohne Bindestrich fand man dieselbe Person. Die Trennzeichen stehen jetzt einmal in lib/employee-search.ts und werden von beiden Seiten des Vergleichs benutzt. C.09 -- der Einheitenfilter verlor jede Person mit vorgemerktem Austritt. "Laufend" war valid_to is null, aber terminate_employee setzt das Ende schon beim Erfassen, Monate vor dem Tag. Jetzt zaehlt auch, was noch laeuft (valid_to > heute). Bewusst ohne valid_from <= heute: ein geplanter Eintritt gehoert in die Liste, sonst fiele er aus dem Filter, obwohl der Status "Geplant" ihn ausdruecklich fuehrt. E.07 -- nur die Kostenstelle zu aendern war unmoeglich. update_position weist einen Aufruf ohne Aenderung ab, und die Umkontierung lief erst bei dessen Erfolg. Sie wird jetzt uebersprungen, wenn sich an den Stammangaben nichts geaendert hat. H.06 -- jedes Speichern erzeugte zusaetzlich "Wochenstunden 30.0 -> 30". Der Vergleich laeuft ueber Text, die Spalte ist numeric(4,1), und das Formular schickt 30. Der Kommentar an der Zeile nannte die Absicht richtig, nur reicht ::numeric dafuer nicht -- es muss auf die Genauigkeit der Spalte gehen.
92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { istPersonalnummer, suchMuster, TRENNZEICHEN, TRENNZEICHEN_ERSATZ } from "@/lib/employee-search";
|
|
|
|
// Der Anlass: „Winkler H" gab alle sieben Winkler zurück statt der einen
|
|
// Hannah. Das „H" wurde als Teilzeichenkette gesucht und traf damit T-h-omas,
|
|
// Kat-h-arina und CNC-Dre-h-er:in.
|
|
//
|
|
// Was hier geprüft wird, ist die Musterbildung. Dass „am Wortanfang" auch
|
|
// wirklich am Wortanfang trifft, entscheidet das SQL der Seite — und ist
|
|
// gegen die laufende Datenbank belegt: „winkler h" liefert dort genau Hannah
|
|
// Winkler, „winkler kat" die beiden Katharinas, „dreher" die CNC-Dreher:innen.
|
|
|
|
describe("istPersonalnummer", () => {
|
|
it("erkennt reine Ziffern", () => {
|
|
expect(istPersonalnummer("3038")).toBe(true);
|
|
expect(istPersonalnummer(" 3038 ")).toBe(true);
|
|
});
|
|
|
|
it("hält alles andere für einen Namen", () => {
|
|
for (const t of ["winkler", "winkler 3038", "3038a", "", " "]) {
|
|
expect(istPersonalnummer(t)).toBe(false);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("suchMuster", () => {
|
|
it("macht aus jedem Wort ein Paar: am Anfang, und nach einem Leerzeichen", () => {
|
|
expect(suchMuster("winkler")).toEqual([["winkler%", "% winkler%"]]);
|
|
});
|
|
|
|
it("behandelt jedes Wort einzeln", () => {
|
|
expect(suchMuster("winkler h")).toEqual([
|
|
["winkler%", "% winkler%"],
|
|
["h%", "% h%"],
|
|
]);
|
|
});
|
|
|
|
it("zerlegt an denselben Zeichen wie das Feld, gegen das verglichen wird", () => {
|
|
// Das Feld wird per translate an TRENNZEICHEN in Leerzeichen zerlegt. Tat
|
|
// es nur das Feld, erzeugte „Müller-Weiß" das Muster „müller-weiß%",
|
|
// während im Heuhaufen „müller weiß" stand: null Treffer, obwohl die
|
|
// Person da ist. Ohne Bindestrich fand man sie. (C.08, 29.09.)
|
|
expect(suchMuster("müller-weiß")).toEqual([
|
|
["müller%", "% müller%"],
|
|
["weiß%", "% weiß%"],
|
|
]);
|
|
});
|
|
|
|
it("zerlegt an jedem der Trennzeichen", () => {
|
|
for (const zeichen of [...TRENNZEICHEN]) {
|
|
expect(suchMuster(`abc${zeichen}def`), `„${zeichen}" trennt nicht`).toEqual([
|
|
["abc%", "% abc%"],
|
|
["def%", "% def%"],
|
|
]);
|
|
}
|
|
});
|
|
|
|
it("findet dieselbe Person mit und ohne Bindestrich", () => {
|
|
expect(suchMuster("müller-weiß")).toEqual(suchMuster("müller weiß"));
|
|
});
|
|
|
|
it("hält Trennzeichen und Ersatz gleich lang", () => {
|
|
// translate() ordnet Zeichen für Zeichen zu. Wäre der Ersatz kürzer,
|
|
// fielen die überzähligen Trennzeichen ersatzlos weg und „Müller-Weiß"
|
|
// würde im Feld zu „müllerweiß" — die Suche fände es dann wieder nicht.
|
|
expect(TRENNZEICHEN_ERSATZ).toHaveLength(TRENNZEICHEN.length);
|
|
expect(TRENNZEICHEN_ERSATZ.trim()).toBe("");
|
|
});
|
|
|
|
it("kennt keinen Platzhalter mitten im Wort", () => {
|
|
// Das ist der Kern: „h%" trifft Hannah, „%h%" träfe auch Thomas.
|
|
const [, [amAnfang]] = suchMuster("winkler h");
|
|
expect(amAnfang.startsWith("%")).toBe(false);
|
|
});
|
|
|
|
it("schreibt klein, damit der Vergleich unabhängig von der Schreibweise ist", () => {
|
|
expect(suchMuster("WINKLER")).toEqual([["winkler%", "% winkler%"]]);
|
|
});
|
|
|
|
it("verträgt beliebig viel Abstand und Rand", () => {
|
|
expect(suchMuster(" winkler h ")).toHaveLength(2);
|
|
expect(suchMuster(" ")).toEqual([]);
|
|
});
|
|
|
|
it("entschärft die Platzhalter von LIKE", () => {
|
|
// Sonst wäre „%" eine Suche nach allem und „_" nach beliebigem Zeichen.
|
|
expect(suchMuster("100%")).toEqual([["100\\%%", "% 100\\%%"]]);
|
|
expect(suchMuster("a_b")).toEqual([["a\\_b%", "% a\\_b%"]]);
|
|
expect(suchMuster("a\\b")).toEqual([["a\\\\b%", "% a\\\\b%"]]);
|
|
});
|
|
});
|