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>
91 lines
3.7 KiB
TypeScript
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([]), []);
|
|
});
|
|
});
|