My-Weekly-ToDo-List/tests/unit/overdue.test.ts
mARTin-B78 64f0eb73f8
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
feat: Uebersicht ueberfaelliger Aufgaben
Aufgaben, die in der Vergangenheit geplant und nicht erledigt wurden, waren bislang
praktisch unsichtbar: nur Aufgaben mit aktiviertem Rolling-Schalter (oder bei global
aktiviertem Auto-Rolling) wandern automatisch auf heute (rollOverdueTasks in
WeeklyView.tsx) -- alles andere blieb fuer immer auf seinem urspruenglichen Datum
stehen, sobald man in der Wochenansicht weitergeklickt hat.

- src/lib/weekly/overdue.ts: reine Funktionen getOverdueTasks/groupOverdueByDate
  (unerledigt, kein Someday, scheduledDate vor heute -- Datumsvergleich als String,
  damit Uhrzeit/Zeitzone keine Rolle spielen). 10 Unit-Tests.
- src/components/OverdueTasksManager.tsx: Dialog, gruppiert nach dem urspruenglich
  geplanten Tag (aelteste zuerst), Checkbox zum Erledigen, Knopf zum Verschieben auf
  heute pro Aufgabe, "Alle auf heute verschieben". Nutzt LinkifiedText (v1.128.0) --
  Titel mit URLs bleiben auch hier anklickbar. Verschieben/Erledigen laeuft ueber die
  bestehenden moveTaskToSlot/toggleTask-Pfade, keine neue API.
- Neuer Menuepunkt "Ueberfaellig" mit Anzahl-Badge neben "Wiederkehrend" in allen
  bestehenden Menue-Varianten (linke/obere Randleiste, mobile Leiste, Kopfzeile).

Verifiziert nicht nur mit Unit-Tests: lokale Instanz mit Wegwerf-Postgres (Docker)
aufgesetzt, drei ueberfaellige Aufgaben geseedet (eine mit URL im Titel), per Playwright
eingeloggt -- Badge, Gruppierung und Link-Rendering per Screenshot geprueft. Danach real
geklickt: eine Aufgabe per Checkbox erledigt, eine per Knopf auf heute verschoben, die
restlichen zwei per Sammelknopf -- alle drei Aenderungen per Datenbankabfrage bestaetigt.

Ausserdem: Typecheck, Lint (0 Fehler), 118 Unit-Tests (10 neu), Produktions-Build.

v1.129.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 18:01:05 +02:00

91 lines
3.7 KiB
TypeScript

import { test, describe } from "node:test";
import assert from "node:assert/strict";
import { getOverdueTasks, groupOverdueByDate } from "../../src/lib/weekly/overdue.ts";
import type { Task } from "../../src/lib/weekly/types.ts";
/**
* Erkennung und Gruppierung überfälliger Aufgaben. Beobachtbares Verhalten: eine
* unerledigte Aufgabe mit einem Datum vor heute gilt als überfällig, unabhängig vom
* Rolling-Status (siehe OverdueTasksManager.tsx für den fachlichen Hintergrund) --
* Someday-Aufgaben und heute fällige Aufgaben zählen bewusst nicht mit.
*/
const baseTask: Task = {
id: "t1",
title: "Test task",
completed: false,
order: 0,
updatedAt: new Date(),
userId: "u1",
};
const now = new Date(2026, 8, 14, 10, 0, 0); // Montag, 14.09.2026, 10 Uhr
describe("getOverdueTasks", () => {
test("unerledigte Aufgabe mit vergangenem Datum ist überfällig", () => {
const task = { ...baseTask, scheduledDate: "2026-09-10" };
assert.deepEqual(getOverdueTasks([task], now), [task]);
});
test("erledigte Aufgabe mit vergangenem Datum ist nicht überfällig", () => {
const task = { ...baseTask, scheduledDate: "2026-09-10", completed: true };
assert.deepEqual(getOverdueTasks([task], now), []);
});
test("heute fällige Aufgabe ist nicht überfällig, auch nachmittags nicht", () => {
const task = { ...baseTask, scheduledDate: "2026-09-14" };
assert.deepEqual(getOverdueTasks([task], now), []);
});
test("zukünftige Aufgabe ist nicht überfällig", () => {
const task = { ...baseTask, scheduledDate: "2026-09-20" };
assert.deepEqual(getOverdueTasks([task], now), []);
});
test("Aufgabe ohne Datum ist nicht überfällig", () => {
const task = { ...baseTask, scheduledDate: null };
assert.deepEqual(getOverdueTasks([task], now), []);
});
test("Someday-Aufgabe zählt nicht mit, selbst mit vergangenem Datum", () => {
const task = { ...baseTask, scheduledDate: "2026-09-10", somedayListId: "list1" };
assert.deepEqual(getOverdueTasks([task], now), []);
});
test("virtuelle wiederkehrende Instanz mit vergangenem Datum zählt mit", () => {
// Der Server materialisiert virtuelle Ids bei jedem PATCH (siehe
// VIRTUAL_ID_REGEX in api/tasks/route.ts) -- toggleTask/moveTaskToSlot
// funktionieren darauf bereits unverändert.
const task = { ...baseTask, id: "virtual-t1-2026-09-10", scheduledDate: "2026-09-10" };
assert.deepEqual(getOverdueTasks([task], now), [task]);
});
test("mehrere Aufgaben werden korrekt gefiltert", () => {
const overdueTask = { ...baseTask, id: "a", scheduledDate: "2026-09-10" };
const futureTask = { ...baseTask, id: "b", scheduledDate: "2026-09-20" };
const doneTask = { ...baseTask, id: "c", scheduledDate: "2026-09-01", completed: true };
assert.deepEqual(getOverdueTasks([overdueTask, futureTask, doneTask], now), [overdueTask]);
});
});
describe("groupOverdueByDate", () => {
test("gruppiert nach Datum, älteste Gruppe zuerst", () => {
const a = { ...baseTask, id: "a", scheduledDate: "2026-09-12" };
const b = { ...baseTask, id: "b", scheduledDate: "2026-09-10" };
const c = { ...baseTask, id: "c", scheduledDate: "2026-09-12" };
const groups = groupOverdueByDate([a, b, c]);
assert.deepEqual(
groups.map((g) => g.dateStr),
["2026-09-10", "2026-09-12"],
);
assert.deepEqual(groups[0].tasks, [b]);
assert.deepEqual(groups[1].tasks, [a, c]);
});
test("leere Liste ergibt keine Gruppen", () => {
assert.deepEqual(groupOverdueByDate([]), []);
});
});