Files
alpenwerk-hr/tests/unit/format.test.ts
Maximilian Stubhan 901c5c426e Consolidation pass: HR-only access, effective-dated mutations, data integrity guards, test suite
Reworks the app from a two-role (hr_admin/manager) model to a single
HR-only role gated by profiles.is_active, fixes transfer/promote/karenz/
reorg RPCs to actually defer future-dated changes via a new
pending_org_changes table instead of writing them immediately (applied
by a daily Vercel Cron route), makes reorg undo append-only instead of
deleting history, adds Karenz-return and history-date integrity guards,
deprecates the salary column, and adds explicit schema grants + perf
indexes needed to run against a fresh (non-hosted) Postgres instance.

Adds vitest unit + integration test suites (the latter against a real
local Supabase instance) covering all of the above, plus lint/typecheck/
build wiring (`npm run check`).
2026-07-14 20:32:20 +02:00

79 lines
2.6 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 { describe, expect, it } from "vitest";
import { daysBetween, fmtAge, fmtDate, initials, tenure } from "@/lib/format";
describe("fmtDate", () => {
it("formats an ISO date string in de-AT order", () => {
expect(fmtDate("2026-03-05")).toBe("05.03.2026");
});
it("returns an em dash for null/undefined/empty input", () => {
expect(fmtDate(null)).toBe("");
expect(fmtDate(undefined)).toBe("");
expect(fmtDate("")).toBe("");
});
it("returns an em dash for an invalid date string", () => {
expect(fmtDate("not-a-date")).toBe("");
});
});
describe("initials", () => {
it("uppercases the first letter of each name", () => {
expect(initials("maria", "gruber")).toBe("MG");
});
it("trims surrounding whitespace before taking the first letter", () => {
expect(initials(" Anna", "Huber ")).toBe("AH");
});
});
describe("fmtAge", () => {
it("computes age correctly when the birthday has already passed this year", () => {
const today = new Date();
const birthDate = new Date(today.getFullYear() - 30, 0, 1); // Jan 1, definitely passed
expect(fmtAge(birthDate)).toBe(30);
});
it("subtracts one year when the birthday has not yet occurred this year", () => {
const today = new Date();
const future = new Date(today.getFullYear() - 30, 11, 31); // Dec 31, likely not yet passed
if (today.getMonth() === 11 && today.getDate() === 31) return; // skip on the one day this'd be flaky
expect(fmtAge(future)).toBe(29);
});
});
describe("tenure", () => {
it("formats whole years and months since entry", () => {
const start = new Date(2020, 0, 15);
const end = new Date(2023, 2, 15); // exactly 3 years, 2 months later
expect(tenure(start, end)).toBe("3 Jahre, 2 Monate");
});
it("uses singular Jahr/Monat for exactly 1", () => {
const start = new Date(2020, 0, 1);
const end = new Date(2021, 1, 1); // 1 year, 1 month
expect(tenure(start, end)).toBe("1 Jahr, 1 Monat");
});
it("falls back to 'unter 1 Monat' for less than a month", () => {
const start = new Date(2024, 0, 1);
const end = new Date(2024, 0, 15);
expect(tenure(start, end)).toBe("unter 1 Monat");
});
it("defaults the end date to today when no end date is given", () => {
const start = new Date();
expect(tenure(start)).toBe("unter 1 Monat");
});
});
describe("daysBetween", () => {
it("computes whole days between two dates", () => {
expect(daysBetween("2026-01-01", "2026-01-11")).toBe(10);
});
it("returns a negative number when the second date precedes the first", () => {
expect(daysBetween("2026-01-11", "2026-01-01")).toBe(-10);
});
});