import { describe, expect, it } from 'vitest'; import { groupDocuments } from './groupDocuments'; type Doc = { id: string; documentDate?: string | null; sender?: { displayName: string } | null; receivers?: { displayName: string }[]; }; const doc = (overrides: Partial & { id: string }): Doc => ({ documentDate: null, sender: null, receivers: [], ...overrides }); // ─── DATE sort ─────────────────────────────────────────────────────────────── describe('groupDocuments — DATE sort', () => { it('produces one group per distinct year', () => { const docs = [ doc({ id: 'a', documentDate: '1923-04-12' }), doc({ id: 'b', documentDate: '1938-01-01' }), doc({ id: 'c', documentDate: '1965-08-03' }) ]; const groups = groupDocuments(docs, 'DATE', 'Undatiert'); expect(groups.map((g) => g.label)).toEqual(['1923', '1938', '1965']); expect(groups.every((g) => g.documents.length === 1)).toBe(true); }); it('puts multiple docs from the same year into one group', () => { const docs = [ doc({ id: 'a', documentDate: '1938-03-01' }), doc({ id: 'b', documentDate: '1938-11-15' }) ]; const groups = groupDocuments(docs, 'DATE', 'Undatiert'); expect(groups).toHaveLength(1); expect(groups[0].label).toBe('1938'); expect(groups[0].documents).toHaveLength(2); }); it('places undated docs in the fallback group at the bottom', () => { const docs = [ doc({ id: 'a', documentDate: '1938-01-01' }), doc({ id: 'b', documentDate: null }), doc({ id: 'c', documentDate: null }) ]; const groups = groupDocuments(docs, 'DATE', 'Undatiert'); expect(groups).toHaveLength(2); expect(groups[0].label).toBe('1938'); expect(groups[1].label).toBe('Undatiert'); expect(groups[1].documents.map((d) => d.id)).toEqual(['b', 'c']); }); it('returns one group with fallback label when all docs are undated', () => { const docs = [doc({ id: 'a' }), doc({ id: 'b' })]; const groups = groupDocuments(docs, 'DATE', 'Undatiert'); expect(groups).toHaveLength(1); expect(groups[0].label).toBe('Undatiert'); }); it('returns one group when all docs are from the same year', () => { const docs = [ doc({ id: 'a', documentDate: '1938-01-01' }), doc({ id: 'b', documentDate: '1938-06-15' }) ]; const groups = groupDocuments(docs, 'DATE', 'Undatiert'); expect(groups).toHaveLength(1); }); }); // ─── SENDER sort ───────────────────────────────────────────────────────────── describe('groupDocuments — SENDER sort', () => { it('produces one group per distinct sender', () => { const docs = [ doc({ id: 'a', sender: { displayName: 'Anna Müller' } }), doc({ id: 'b', sender: { displayName: 'Karl Bauer' } }), doc({ id: 'c', sender: { displayName: 'Anna Müller' } }) ]; const groups = groupDocuments(docs, 'SENDER', 'Unbekannt'); expect(groups.map((g) => g.label)).toEqual(['Anna Müller', 'Karl Bauer']); expect(groups[0].documents).toHaveLength(2); expect(groups[1].documents).toHaveLength(1); }); it('places docs with no sender in the fallback group at the bottom', () => { const docs = [ doc({ id: 'a', sender: { displayName: 'Anna Müller' } }), doc({ id: 'b', sender: null }) ]; const groups = groupDocuments(docs, 'SENDER', 'Unbekannt'); expect(groups).toHaveLength(2); expect(groups[0].label).toBe('Anna Müller'); expect(groups[1].label).toBe('Unbekannt'); expect(groups[1].documents[0].id).toBe('b'); }); }); // ─── RECEIVER sort ─────────────────────────────────────────────────────────── describe('groupDocuments — RECEIVER sort', () => { it('a doc with two receivers appears in both receiver groups', () => { const docs = [ doc({ id: 'a', receivers: [{ displayName: 'Anna' }, { displayName: 'Karl' }] }) ]; const groups = groupDocuments(docs, 'RECEIVER', 'Unbekannt'); expect(groups.map((g) => g.label)).toEqual(['Anna', 'Karl']); expect(groups[0].documents[0].id).toBe('a'); expect(groups[1].documents[0].id).toBe('a'); }); it('places docs with no receivers in the fallback group at the bottom', () => { const docs = [ doc({ id: 'a', receivers: [{ displayName: 'Anna' }] }), doc({ id: 'b', receivers: [] }) ]; const groups = groupDocuments(docs, 'RECEIVER', 'Unbekannt'); expect(groups).toHaveLength(2); expect(groups[0].label).toBe('Anna'); expect(groups[1].label).toBe('Unbekannt'); expect(groups[1].documents[0].id).toBe('b'); }); it('composite keys are unique: groupLabel + doc.id identifies each item', () => { const docs = [ doc({ id: 'a', receivers: [{ displayName: 'Anna' }, { displayName: 'Karl' }] }), doc({ id: 'b', receivers: [{ displayName: 'Anna' }] }) ]; const groups = groupDocuments(docs, 'RECEIVER', 'Unbekannt'); const keys = groups.flatMap((g) => g.documents.map((d) => `${g.label}-${d.id}`)); const uniqueKeys = new Set(keys); expect(uniqueKeys.size).toBe(keys.length); }); }); // ─── Non-groupable sorts ────────────────────────────────────────────────────── describe('groupDocuments — non-groupable sorts', () => { it('TITLE sort returns one group containing all documents', () => { const docs = [doc({ id: 'a' }), doc({ id: 'b' })]; const groups = groupDocuments(docs, 'TITLE', 'Undatiert'); expect(groups).toHaveLength(1); expect(groups[0].documents).toHaveLength(2); }); it('UPLOAD_DATE sort returns one group containing all documents', () => { const docs = [doc({ id: 'a' }), doc({ id: 'b' })]; const groups = groupDocuments(docs, 'UPLOAD_DATE', 'Undatiert'); expect(groups).toHaveLength(1); expect(groups[0].documents).toHaveLength(2); }); }); // ─── Edge cases ────────────────────────────────────────────────────────────── describe('groupDocuments — edge cases', () => { it('returns empty array for an empty document list', () => { expect(groupDocuments([], 'DATE', 'Undatiert')).toEqual([]); }); });