import { describe, expect, test } from 'vitest' import { alsTitel, sendungFrisch, spiegelSendung, TITEL_MAX, uebernahmeEntscheiden, type Bestand, type Fund, } from '@/lib/integration' function fund(teile: Partial = {}): Fund { return { ref: 'T-1', titel: 'Drucker klemmt', ...teile } } function bestand(teile: Partial = {}): Bestand { return { titel: 'Drucker klemmt', notiz: null, quelleUrl: null, faelligAm: null, prioritaet: 3, aufwandMinuten: null, erledigt: false, ...teile, } } describe('uebernahmeEntscheiden', () => { test('legt an, was es hier noch nicht gibt', () => { expect(uebernahmeEntscheiden(fund(), null)).toEqual({ tun: 'anlegen' }) }) test('legt nichts an, was drüben schon erledigt ist', () => { expect(uebernahmeEntscheiden(fund({ erledigt: true }), null)).toEqual({ tun: 'nichts', grund: 'schon-erledigt', }) }) test('erkennt den unveränderten Fall', () => { expect(uebernahmeEntscheiden(fund(), bestand())).toEqual({ tun: 'nichts', grund: 'unveraendert', }) }) test('übernimmt einen geänderten Titel', () => { const entscheidung = uebernahmeEntscheiden( fund({ titel: 'Drucker klemmt weiterhin' }), bestand(), ) expect(entscheidung).toEqual({ tun: 'aktualisieren', felder: { titel: 'Drucker klemmt weiterhin' }, }) }) test('übernimmt eine neue Fälligkeit', () => { const faelligAm = new Date('2026-04-01T00:00:00.000Z') expect(uebernahmeEntscheiden(fund({ faelligAm }), bestand())).toEqual({ tun: 'aktualisieren', felder: { faelligAm }, }) }) test('vergleicht Datumswerte nach Zeitpunkt, nicht nach Objekt', () => { const faelligAm = new Date('2026-04-01T00:00:00.000Z') const entscheidung = uebernahmeEntscheiden( fund({ faelligAm: new Date(faelligAm.getTime()) }), bestand({ faelligAm }), ) expect(entscheidung).toEqual({ tun: 'nichts', grund: 'unveraendert' }) }) test('rührt Priorität und Aufwand nicht an', () => { // Beides wird hier geschätzt, nicht drüben. Ein Abgleich, der die // Schätzung wegräumt, macht die Wochenplanung kaputt. const entscheidung = uebernahmeEntscheiden( fund({ prioritaet: 1, aufwandMinuten: 30 }), bestand({ prioritaet: 4, aufwandMinuten: 90 }), ) expect(entscheidung).toEqual({ tun: 'nichts', grund: 'unveraendert' }) }) test('schließt, was drüben erledigt wurde', () => { expect(uebernahmeEntscheiden(fund({ erledigt: true }), bestand())).toEqual({ tun: 'schliessen', }) }) test('schließt nicht zweimal', () => { expect( uebernahmeEntscheiden(fund({ erledigt: true }), bestand({ erledigt: true })), ).toEqual({ tun: 'nichts', grund: 'schon-erledigt' }) }) test('holt eine hier erledigte Aufgabe zurück, wenn sie drüben wieder offen ist', () => { const entscheidung = uebernahmeEntscheiden(fund(), bestand({ erledigt: true })) // Das Ursprungssystem führt den Zustand; wer dort neu öffnet, meint es so. expect(entscheidung).toEqual({ tun: 'nichts', grund: 'unveraendert' }) }) }) describe('alsTitel', () => { test('lässt kurze Texte in Ruhe', () => { expect(alsTitel('Angebot schreiben')).toEqual({ titel: 'Angebot schreiben', rest: null, }) }) test('macht aus Zeilenumbrüchen Leerzeichen', () => { expect(alsTitel('Angebot\n\nschreiben ')).toEqual({ titel: 'Angebot schreiben', rest: null, }) }) test('kürzt lange Texte und hebt den Rest auf', () => { const lang = `${'wort '.repeat(60)}ende` const { titel, rest } = alsTitel(lang) expect(titel.length).toBeLessThanOrEqual(TITEL_MAX + 1) expect(titel.endsWith('…')).toBe(true) expect(rest).not.toBeNull() expect(rest?.endsWith('ende')).toBe(true) }) test('trennt nicht mitten im Wort, wenn eine Fuge in der Nähe ist', () => { const lang = `${'a'.repeat(60)} ${'b'.repeat(80)}` const { titel } = alsTitel(lang) expect(titel).toBe(`${'a'.repeat(60)}…`) }) test('trennt hart, wenn es keine Fuge gibt', () => { const { titel } = alsTitel('x'.repeat(200)) expect(titel).toBe(`${'x'.repeat(TITEL_MAX)}…`) }) }) describe('sendungFrisch', () => { const jetzt = new Date('2026-03-17T08:20:00.000Z') test('nimmt an, was gerade erst losgeschickt wurde', () => { expect(sendungFrisch(new Date('2026-03-17T08:18:00.000Z'), jetzt)).toBe(true) }) test('lehnt ein altes Paket ab', () => { expect(sendungFrisch(new Date('2026-03-17T08:10:00.000Z'), jetzt)).toBe(false) }) test('lehnt auch ein Paket aus der Zukunft ab', () => { // Eine verstellte Uhr auf der Gegenseite ist genauso verdächtig. expect(sendungFrisch(new Date('2026-03-17T08:40:00.000Z'), jetzt)).toBe(false) }) }) describe('spiegelSendung', () => { test('nimmt ein vollständiges Paket an', () => { const gelesen = spiegelSendung.safeParse({ gesendetAm: '2026-03-17T08:20:00.000Z', belegungen: [ { ref: 'zb-1', beginn: '2026-03-17T09:00:00.000Z', ende: '2026-03-17T10:00:00.000Z', }, ], aufgaben: [{ ref: 'a-1', titel: 'Angebot schreiben' }], }) expect(gelesen.success).toBe(true) expect(gelesen.success && gelesen.data.aufgaben[0]?.erledigt).toBe(false) }) test('weist ein Paket ohne Zeitstempel ab', () => { const gelesen = spiegelSendung.safeParse({ belegungen: [], aufgaben: [] }) expect(gelesen.success).toBe(false) }) test('weist eine Belegung mit kaputtem Datum ab', () => { const gelesen = spiegelSendung.safeParse({ gesendetAm: '2026-03-17T08:20:00.000Z', belegungen: [{ ref: 'zb-1', beginn: 'morgen', ende: 'später' }], aufgaben: [], }) expect(gelesen.success).toBe(false) }) })