import { describe, it, expect } from 'vitest'; import { AllDayLayoutEngine } from '../../src/utils/AllDayLayoutEngine'; import { CalendarEvent } from '../../src/types/CalendarTypes'; describe('AllDay Layout Engine - Pure Data Tests', () => { const weekDates = [ '2025-09-22', '2025-09-23', '2025-09-24', '2025-09-25', '2025-09-26', '2025-09-27', '2025-09-28' ]; const layoutEngine = new AllDayLayoutEngine(weekDates); // Test data: events med start/end datoer og forventet grid-area const testCases = [ { name: 'Single day events - no overlap', events: [ { id: '1', title: 'Event 1', start: new Date('2025-09-22'), end: new Date('2025-09-22'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '2', title: 'Event 2', start: new Date('2025-09-24'), end: new Date('2025-09-24'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent ], expected: [ { id: '1', gridArea: '1 / 1 / 2 / 2' }, // row 1, column 1 (Sept 22) { id: '2', gridArea: '1 / 3 / 2 / 4' } // row 1, column 3 (Sept 24) ] }, { name: 'Overlapping multi-day events - Autumn Equinox vs Teknisk Workshop', events: [ { id: 'autumn', title: 'Autumn Equinox', start: new Date('2025-09-22'), end: new Date('2025-09-23'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: 'workshop', title: 'Teknisk Workshop', start: new Date('2025-09-23'), end: new Date('2025-09-26'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent ], expected: [ { id: 'autumn', gridArea: '2 / 1 / 3 / 3' }, // row 2, columns 1-2 (2 dage, processed second) { id: 'workshop', gridArea: '1 / 2 / 2 / 6' } // row 1, columns 2-5 (4 dage, processed first) ] }, { name: 'Multiple events same column', events: [ { id: '1', title: 'Event 1', start: new Date('2025-09-23'), end: new Date('2025-09-23'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '2', title: 'Event 2', start: new Date('2025-09-23'), end: new Date('2025-09-23'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '3', title: 'Event 3', start: new Date('2025-09-23'), end: new Date('2025-09-23'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent ], expected: [ { id: '1', gridArea: '1 / 2 / 2 / 3' }, // row 1, column 2 (Sept 23) { id: '2', gridArea: '2 / 2 / 3 / 3' }, // row 2, column 2 (Sept 23) { id: '3', gridArea: '3 / 2 / 4 / 3' } // row 3, column 2 (Sept 23) ] }, { name: 'Partial overlaps', events: [ { id: '1', title: 'Event 1', start: new Date('2025-09-22'), end: new Date('2025-09-23'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '2', title: 'Event 2', start: new Date('2025-09-23'), end: new Date('2025-09-24'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '3', title: 'Event 3', start: new Date('2025-09-25'), end: new Date('2025-09-26'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent ], expected: [ { id: '1', gridArea: '1 / 1 / 2 / 3' }, // row 1, columns 1-2 (Sept 22-23) { id: '2', gridArea: '2 / 2 / 3 / 4' }, // row 2, columns 2-3 (Sept 23-24, overlap på column 2) { id: '3', gridArea: '1 / 4 / 2 / 6' } // row 1, columns 4-5 (Sept 25-26, no overlap) ] }, { name: 'Complex overlapping pattern', events: [ { id: '1', title: 'Long Event', start: new Date('2025-09-22'), end: new Date('2025-09-25'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '2', title: 'Short Event', start: new Date('2025-09-23'), end: new Date('2025-09-24'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '3', title: 'Another Event', start: new Date('2025-09-24'), end: new Date('2025-09-26'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent ], expected: [ { id: '1', gridArea: '1 / 1 / 2 / 5' }, // row 1, columns 1-4 (4 dage, processed first) { id: '2', gridArea: '3 / 2 / 4 / 4' }, // row 3, columns 2-3 (2 dage, processed last) { id: '3', gridArea: '2 / 3 / 3 / 6' } // row 2, columns 3-5 (3 dage, processed second) ] }, { name: 'Real-world bug scenario - Multiple overlapping events (Sept 21-28)', events: [ { id: '112', title: 'Autumn Equinox', start: new Date('2025-09-22'), end: new Date('2025-09-23'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '122', title: 'Multi-Day Conference', start: new Date('2025-09-21'), end: new Date('2025-09-24'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '123', title: 'Project Sprint', start: new Date('2025-09-22'), end: new Date('2025-09-25'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '143', title: 'Weekend Hackathon', start: new Date('2025-09-26'), end: new Date('2025-09-28'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent, { id: '161', title: 'Teknisk Workshop', start: new Date('2025-09-23'), end: new Date('2025-09-26'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent ], expected: [ { id: '112', gridArea: '4 / 1 / 5 / 3' }, // Autumn Equinox: row 4, columns 1-2 (2 dage, processed last) { id: '122', gridArea: '1 / 1 / 2 / 4' }, // Multi-Day Conference: row 1, columns 1-3 (4 dage, starts 21/9, processed first) { id: '123', gridArea: '2 / 1 / 3 / 5' }, // Project Sprint: row 2, columns 1-4 (4 dage, starts 22/9, processed second) { id: '143', gridArea: '1 / 5 / 2 / 8' }, // Weekend Hackathon: row 1, columns 5-7 (3 dage, no overlap, reuse row 1) { id: '161', gridArea: '3 / 2 / 4 / 6' } // Teknisk Workshop: row 3, columns 2-5 (4 dage, starts 23/9, processed third) ] } ]; testCases.forEach(testCase => { it(testCase.name, () => { // Calculate actual layouts using AllDayLayoutEngine const layouts = layoutEngine.calculateLayout(testCase.events); // Verify we got layouts for all events expect(layouts.size).toBe(testCase.events.length); // Check each expected result testCase.expected.forEach(expected => { const actualLayout = layouts.get(expected.id); expect(actualLayout).toBeDefined(); expect(actualLayout!.gridArea).toBe(expected.gridArea); }); }); }); it('Grid-area format validation', () => { // Test at grid-area format er korrekt const gridArea = '2 / 3 / 3 / 5'; // row 2, columns 3-4 const parts = gridArea.split(' / '); const rowStart = parseInt(parts[0]); // 2 const colStart = parseInt(parts[1]); // 3 const rowEnd = parseInt(parts[2]); // 3 const colEnd = parseInt(parts[3]); // 5 expect(rowStart).toBe(2); expect(colStart).toBe(3); expect(rowEnd).toBe(3); expect(colEnd).toBe(5); // Verify spans const rowSpan = rowEnd - rowStart; // 1 row const colSpan = colEnd - colStart; // 2 columns expect(rowSpan).toBe(1); expect(colSpan).toBe(2); }); });