Tests all-day event layout calculations

Adds comprehensive tests for the AllDayManager, covering various overlap scenarios.
Tests ensure correct row and column assignments for all-day events based on date ranges and overlaps.
Replaces individual event layout calculation with batch calculation for improved performance and test coverage.
This commit is contained in:
Janus C. H. Knudsen 2025-09-25 23:44:13 +02:00
parent a624394ffb
commit a551bc59ff
2 changed files with 126 additions and 77 deletions

View file

@ -0,0 +1,40 @@
import { CalendarEvent } from '../../src/types/CalendarTypes';
/**
* Setup mock DOM for testing
*/
export function setupMockDOM(): void {
// Create basic DOM structure for testing
document.body.innerHTML = `
<div class="swp-calendar-grid" data-current="true">
<div class="swp-day-header" data-date="2024-09-22"></div>
<div class="swp-day-header" data-date="2024-09-23"></div>
<div class="swp-day-header" data-date="2024-09-24"></div>
<div class="swp-day-header" data-date="2024-09-25"></div>
<div class="swp-day-header" data-date="2024-09-26"></div>
</div>
<swp-calendar-header>
<swp-allday-container></swp-allday-container>
</swp-calendar-header>
`;
}
/**
* Create mock CalendarEvent for testing
*/
export function createMockEvent(
id: string,
title: string,
startDate: string,
endDate: string
): CalendarEvent {
return {
id,
title,
start: new Date(startDate),
end: new Date(endDate),
type: 'work',
allDay: true,
syncStatus: 'synced'
};
}

View file

@ -14,121 +14,130 @@ describe('AllDayManager - Layout Calculation', () => {
it('Scenario 1: Non-overlapping single-day events', () => { it('Scenario 1: Non-overlapping single-day events', () => {
// Event 1: Sept 22 (column 1) // Event 1: Sept 22 (column 1)
const event1 = createMockEvent('1', 'Event 1', '2024-09-22', '2024-09-22'); const event1 = createMockEvent('1', 'Event 1', '2024-09-22', '2024-09-22');
const layout1 = allDayManager.calculateAllDayEventLayout(event1);
expect(layout1.startColumn).toBe(1);
expect(layout1.row).toBe(1);
// Event 2: Sept 24 (column 3) - different column, should be row 1 // Event 2: Sept 24 (column 3) - different column, should be row 1
const event2 = createMockEvent('2', 'Event 2', '2024-09-24', '2024-09-24'); const event2 = createMockEvent('2', 'Event 2', '2024-09-24', '2024-09-24');
const layout2 = allDayManager.calculateAllDayEventLayout(event2);
expect(layout2.startColumn).toBe(3); // Test both events together using new batch method
expect(layout2.row).toBe(1); const weekDates = ['2024-09-22', '2024-09-23', '2024-09-24', '2024-09-25', '2024-09-26'];
const layouts = allDayManager.calculateAllDayEventsLayout([event1, event2], weekDates);
const layout1 = layouts.get('1');
const layout2 = layouts.get('2');
expect(layout1?.startColumn).toBe(1);
expect(layout1?.row).toBe(1);
expect(layout2?.startColumn).toBe(3);
expect(layout2?.row).toBe(1);
}); });
it('Scenario 2: Overlapping multi-day events - Autumn Equinox vs Teknisk Workshop', () => { it('Scenario 2: Overlapping multi-day events - Autumn Equinox vs Teknisk Workshop', () => {
// Autumn Equinox: Sept 22-23 (columns 1-2) // Autumn Equinox: Sept 22-23 (columns 1-2)
const autumnEvent = createMockEvent('autumn', 'Autumn Equinox', '2024-09-22', '2024-09-23'); const autumnEvent = createMockEvent('autumn', 'Autumn Equinox', '2024-09-22', '2024-09-23');
const autumnLayout = allDayManager.calculateAllDayEventLayout(autumnEvent);
expect(autumnLayout.startColumn).toBe(1);
expect(autumnLayout.endColumn).toBe(2);
expect(autumnLayout.row).toBe(1);
// Teknisk Workshop: Sept 23-26 (columns 2-5) - overlaps on Sept 23 // Teknisk Workshop: Sept 23-26 (columns 2-5) - overlaps on Sept 23
const workshopEvent = createMockEvent('workshop', 'Teknisk Workshop', '2024-09-23', '2024-09-26'); const workshopEvent = createMockEvent('workshop', 'Teknisk Workshop', '2024-09-23', '2024-09-26');
const workshopLayout = allDayManager.calculateAllDayEventLayout(workshopEvent);
expect(workshopLayout.startColumn).toBe(2); const weekDates = ['2024-09-22', '2024-09-23', '2024-09-24', '2024-09-25', '2024-09-26'];
expect(workshopLayout.endColumn).toBe(5); const layouts = allDayManager.calculateAllDayEventsLayout([autumnEvent, workshopEvent], weekDates);
expect(workshopLayout.row).toBe(2); // Should be row 2 due to overlap
const autumnLayout = layouts.get('autumn');
const workshopLayout = layouts.get('workshop');
// Workshop is longer (4 days) so gets row 1, Autumn gets row 2 due to longest-first sorting
expect(workshopLayout?.startColumn).toBe(2);
expect(workshopLayout?.endColumn).toBe(5);
expect(workshopLayout?.row).toBe(1); // Longest event gets row 1
expect(autumnLayout?.startColumn).toBe(1);
expect(autumnLayout?.endColumn).toBe(2);
expect(autumnLayout?.row).toBe(2); // Shorter overlapping event gets row 2
}); });
it('Scenario 3: Multiple events in same column', () => { it('Scenario 3: Multiple events in same column', () => {
// Event 1: Sept 23 only // All events on Sept 23 only
const event1 = createMockEvent('1', 'Event 1', '2024-09-23', '2024-09-23'); const event1 = createMockEvent('1', 'Event 1', '2024-09-23', '2024-09-23');
const layout1 = allDayManager.calculateAllDayEventLayout(event1);
expect(layout1.startColumn).toBe(2);
expect(layout1.row).toBe(1);
// Event 2: Sept 23 only - same column, should be row 2
const event2 = createMockEvent('2', 'Event 2', '2024-09-23', '2024-09-23'); const event2 = createMockEvent('2', 'Event 2', '2024-09-23', '2024-09-23');
const layout2 = allDayManager.calculateAllDayEventLayout(event2);
expect(layout2.startColumn).toBe(2);
expect(layout2.row).toBe(2);
// Event 3: Sept 23 only - same column, should be row 3
const event3 = createMockEvent('3', 'Event 3', '2024-09-23', '2024-09-23'); const event3 = createMockEvent('3', 'Event 3', '2024-09-23', '2024-09-23');
const layout3 = allDayManager.calculateAllDayEventLayout(event3);
expect(layout3.startColumn).toBe(2); const weekDates = ['2024-09-22', '2024-09-23', '2024-09-24', '2024-09-25', '2024-09-26'];
expect(layout3.row).toBe(3); const layouts = allDayManager.calculateAllDayEventsLayout([event1, event2, event3], weekDates);
const layout1 = layouts.get('1');
const layout2 = layouts.get('2');
const layout3 = layouts.get('3');
expect(layout1?.startColumn).toBe(2);
expect(layout1?.row).toBe(1);
expect(layout2?.startColumn).toBe(2);
expect(layout2?.row).toBe(2);
expect(layout3?.startColumn).toBe(2);
expect(layout3?.row).toBe(3);
}); });
it('Scenario 4: Partial overlaps', () => { it('Scenario 4: Partial overlaps', () => {
// Event 1: Sept 22-23 (columns 1-2) // Event 1: Sept 22-23 (columns 1-2)
const event1 = createMockEvent('1', 'Event 1', '2024-09-22', '2024-09-23'); const event1 = createMockEvent('1', 'Event 1', '2024-09-22', '2024-09-23');
const layout1 = allDayManager.calculateAllDayEventLayout(event1);
expect(layout1.startColumn).toBe(1);
expect(layout1.endColumn).toBe(2);
expect(layout1.row).toBe(1);
// Event 2: Sept 23-24 (columns 2-3) - overlaps on Sept 23 // Event 2: Sept 23-24 (columns 2-3) - overlaps on Sept 23
const event2 = createMockEvent('2', 'Event 2', '2024-09-23', '2024-09-24'); const event2 = createMockEvent('2', 'Event 2', '2024-09-23', '2024-09-24');
const layout2 = allDayManager.calculateAllDayEventLayout(event2);
expect(layout2.startColumn).toBe(2);
expect(layout2.endColumn).toBe(3);
expect(layout2.row).toBe(2); // Should be row 2 due to overlap
// Event 3: Sept 25-26 (columns 4-5) - no overlap, should be row 1 // Event 3: Sept 25-26 (columns 4-5) - no overlap, should be row 1
const event3 = createMockEvent('3', 'Event 3', '2024-09-25', '2024-09-26'); const event3 = createMockEvent('3', 'Event 3', '2024-09-25', '2024-09-26');
const layout3 = allDayManager.calculateAllDayEventLayout(event3);
expect(layout3.startColumn).toBe(4); const weekDates = ['2024-09-22', '2024-09-23', '2024-09-24', '2024-09-25', '2024-09-26'];
expect(layout3.endColumn).toBe(5); const layouts = allDayManager.calculateAllDayEventsLayout([event1, event2, event3], weekDates);
expect(layout3.row).toBe(1); // No overlap, back to row 1
const layout1 = layouts.get('1');
const layout2 = layouts.get('2');
const layout3 = layouts.get('3');
expect(layout1?.startColumn).toBe(1);
expect(layout1?.endColumn).toBe(2);
expect(layout1?.row).toBe(1);
expect(layout2?.startColumn).toBe(2);
expect(layout2?.endColumn).toBe(3);
expect(layout2?.row).toBe(2); // Should be row 2 due to overlap
expect(layout3?.startColumn).toBe(4);
expect(layout3?.endColumn).toBe(5);
expect(layout3?.row).toBe(1); // No overlap, back to row 1
}); });
it('Scenario 5: Complex overlapping pattern', () => { it('Scenario 5: Complex overlapping pattern', () => {
// Event 1: Sept 22-25 (columns 1-4) - spans most of week // Event 1: Sept 22-25 (columns 1-4) - spans most of week (4 days)
const event1 = createMockEvent('1', 'Long Event', '2024-09-22', '2024-09-25'); const event1 = createMockEvent('1', 'Long Event', '2024-09-22', '2024-09-25');
const layout1 = allDayManager.calculateAllDayEventLayout(event1); // Event 2: Sept 23-24 (columns 2-3) - overlaps with Event 1 (2 days)
expect(layout1.startColumn).toBe(1);
expect(layout1.endColumn).toBe(4);
expect(layout1.row).toBe(1);
// Event 2: Sept 23-24 (columns 2-3) - overlaps with Event 1
const event2 = createMockEvent('2', 'Short Event', '2024-09-23', '2024-09-24'); const event2 = createMockEvent('2', 'Short Event', '2024-09-23', '2024-09-24');
const layout2 = allDayManager.calculateAllDayEventLayout(event2); // Event 3: Sept 24-26 (columns 3-5) - overlaps with both (3 days)
expect(layout2.startColumn).toBe(2);
expect(layout2.endColumn).toBe(3);
expect(layout2.row).toBe(2);
// Event 3: Sept 24-26 (columns 3-5) - overlaps with both
const event3 = createMockEvent('3', 'Another Event', '2024-09-24', '2024-09-26'); const event3 = createMockEvent('3', 'Another Event', '2024-09-24', '2024-09-26');
const layout3 = allDayManager.calculateAllDayEventLayout(event3);
expect(layout3.startColumn).toBe(3); const weekDates = ['2024-09-22', '2024-09-23', '2024-09-24', '2024-09-25', '2024-09-26'];
expect(layout3.endColumn).toBe(5); const layouts = allDayManager.calculateAllDayEventsLayout([event1, event2, event3], weekDates);
expect(layout3.row).toBe(3); // Should be row 3 due to overlaps with both
const layout1 = layouts.get('1');
const layout2 = layouts.get('2');
const layout3 = layouts.get('3');
// Longest-first sorting: Event1 (4 days) -> Event3 (3 days) -> Event2 (2 days)
expect(layout1?.startColumn).toBe(1);
expect(layout1?.endColumn).toBe(4);
expect(layout1?.row).toBe(1); // Longest event gets row 1
expect(layout3?.startColumn).toBe(3);
expect(layout3?.endColumn).toBe(5);
expect(layout3?.row).toBe(2); // Second longest, overlaps with Event1, gets row 2
expect(layout2?.startColumn).toBe(2);
expect(layout2?.endColumn).toBe(3);
expect(layout2?.row).toBe(3); // Shortest, overlaps with both, gets row 3
}); });
it('Scenario 6: Drag-drop target date override', () => { it('Scenario 6: Single event for drag-drop simulation', () => {
// Multi-day event dragged to specific date should use single column // Single event placed at specific date
const event = createMockEvent('drag', 'Dragged Event', '2024-09-22', '2024-09-25'); const event = createMockEvent('drag', 'Dragged Event', '2024-09-24', '2024-09-24');
const layout = allDayManager.calculateAllDayEventLayout(event, '2024-09-24');
expect(layout.startColumn).toBe(3); // Sept 24 is column 3 const weekDates = ['2024-09-22', '2024-09-23', '2024-09-24', '2024-09-25', '2024-09-26'];
expect(layout.endColumn).toBe(3); // Single column when targetDate specified const layouts = allDayManager.calculateAllDayEventsLayout([event], weekDates);
expect(layout.columnSpan).toBe(1);
expect(layout.row).toBe(1); const layout = layouts.get('drag');
expect(layout?.startColumn).toBe(3); // Sept 24 is column 3
expect(layout?.endColumn).toBe(3); // Single column
expect(layout?.columnSpan).toBe(1);
expect(layout?.row).toBe(1);
}); });
}); });
}); });