import { describe, it, expect, beforeEach } from 'vitest'; import { DateCalculator } from '../../src/utils/DateCalculator'; import { CalendarConfig } from '../../src/core/CalendarConfig'; describe('DateCalculator', () => { let testConfig: CalendarConfig; beforeEach(() => { testConfig = new CalendarConfig(); DateCalculator.initialize(testConfig); }); describe('Week Operations', () => { it('should get ISO week start (Monday)', () => { // Wednesday, January 17, 2024 const date = new Date(2024, 0, 17); const weekStart = DateCalculator.getISOWeekStart(date); // Should be Monday, January 15 expect(weekStart.getDate()).toBe(15); expect(weekStart.getDay()).toBe(1); // Monday expect(weekStart.getHours()).toBe(0); expect(weekStart.getMinutes()).toBe(0); }); it('should get ISO week start for Sunday', () => { // Sunday, January 21, 2024 const date = new Date(2024, 0, 21); const weekStart = DateCalculator.getISOWeekStart(date); // Should be Monday, January 15 expect(weekStart.getDate()).toBe(15); expect(weekStart.getDay()).toBe(1); }); it('should get week end (Sunday)', () => { // Wednesday, January 17, 2024 const date = new Date(2024, 0, 17); const weekEnd = DateCalculator.getWeekEnd(date); // Should be Sunday, January 21 expect(weekEnd.getDate()).toBe(21); expect(weekEnd.getDay()).toBe(0); // Sunday expect(weekEnd.getHours()).toBe(23); expect(weekEnd.getMinutes()).toBe(59); }); it('should get work week dates (Mon-Fri)', () => { const date = new Date(2024, 0, 17); // Wednesday const workDays = DateCalculator.getWorkWeekDates(date); expect(workDays).toHaveLength(5); expect(workDays[0].getDay()).toBe(1); // Monday expect(workDays[4].getDay()).toBe(5); // Friday }); it('should get full week dates (7 days)', () => { const weekStart = new Date(2024, 0, 15); // Monday const fullWeek = DateCalculator.getFullWeekDates(weekStart); expect(fullWeek).toHaveLength(7); expect(fullWeek[0].getDay()).toBe(1); // Monday expect(fullWeek[6].getDay()).toBe(0); // Sunday }); it('should calculate ISO week number', () => { const date1 = new Date(2024, 0, 1); // January 1, 2024 const weekNum1 = DateCalculator.getWeekNumber(date1); expect(weekNum1).toBe(1); const date2 = new Date(2024, 0, 15); // January 15, 2024 const weekNum2 = DateCalculator.getWeekNumber(date2); expect(weekNum2).toBe(3); }); it('should handle year boundary for week numbers', () => { const date = new Date(2023, 11, 31); // December 31, 2023 const weekNum = DateCalculator.getWeekNumber(date); // Week 52 or 53 depending on year expect(weekNum).toBeGreaterThanOrEqual(52); }); }); describe('Date Manipulation', () => { it('should add days', () => { const date = new Date(2024, 0, 15); const newDate = DateCalculator.addDays(date, 5); expect(newDate.getDate()).toBe(20); expect(newDate.getMonth()).toBe(0); }); it('should subtract days', () => { const date = new Date(2024, 0, 15); const newDate = DateCalculator.addDays(date, -5); expect(newDate.getDate()).toBe(10); }); it('should add weeks', () => { const date = new Date(2024, 0, 15); const newDate = DateCalculator.addWeeks(date, 2); expect(newDate.getDate()).toBe(29); }); it('should subtract weeks', () => { const date = new Date(2024, 0, 15); const newDate = DateCalculator.addWeeks(date, -1); expect(newDate.getDate()).toBe(8); }); it('should handle month boundaries when adding days', () => { const date = new Date(2024, 0, 30); // January 30 const newDate = DateCalculator.addDays(date, 5); expect(newDate.getDate()).toBe(4); // February 4 expect(newDate.getMonth()).toBe(1); }); }); describe('Time Formatting', () => { it('should format time (24-hour)', () => { const date = new Date(2024, 0, 15, 14, 30, 45); const formatted = DateCalculator.formatTime(date); expect(formatted).toBe('14:30'); }); it('should format time (12-hour)', () => { const date1 = new Date(2024, 0, 15, 14, 30, 0); const formatted1 = DateCalculator.formatTime12(date1); expect(formatted1).toBe('2:30 PM'); const date2 = new Date(2024, 0, 15, 9, 15, 0); const formatted2 = DateCalculator.formatTime12(date2); expect(formatted2).toBe('9:15 AM'); const date3 = new Date(2024, 0, 15, 0, 0, 0); const formatted3 = DateCalculator.formatTime12(date3); expect(formatted3).toBe('12:00 AM'); }); it('should format ISO date', () => { const date = new Date(2024, 0, 15, 14, 30, 0); const formatted = DateCalculator.formatISODate(date); expect(formatted).toBe('2024-01-15'); }); it('should format date range', () => { const start = new Date(2024, 0, 15); const end = new Date(2024, 0, 21); const formatted = DateCalculator.formatDateRange(start, end); expect(formatted).toContain('Jan'); expect(formatted).toContain('15'); expect(formatted).toContain('21'); }); it('should get day name (short)', () => { const monday = new Date(2024, 0, 15); // Monday const dayName = DateCalculator.getDayName(monday, 'short'); expect(dayName).toBe('Mon'); }); it('should get day name (long)', () => { const monday = new Date(2024, 0, 15); // Monday const dayName = DateCalculator.getDayName(monday, 'long'); expect(dayName).toBe('Monday'); }); }); describe('Time Calculations', () => { it('should convert time string to minutes', () => { expect(DateCalculator.timeToMinutes('09:00')).toBe(540); expect(DateCalculator.timeToMinutes('14:30')).toBe(870); expect(DateCalculator.timeToMinutes('00:00')).toBe(0); expect(DateCalculator.timeToMinutes('23:59')).toBe(1439); }); it('should convert minutes to time string', () => { expect(DateCalculator.minutesToTime(540)).toBe('09:00'); expect(DateCalculator.minutesToTime(870)).toBe('14:30'); expect(DateCalculator.minutesToTime(0)).toBe('00:00'); expect(DateCalculator.minutesToTime(1439)).toBe('23:59'); }); it('should get minutes since midnight from Date', () => { const date = new Date(2024, 0, 15, 14, 30, 0); const minutes = DateCalculator.getMinutesSinceMidnight(date); expect(minutes).toBe(870); // 14*60 + 30 }); it('should get minutes since midnight from ISO string', () => { const isoString = '2024-01-15T14:30:00.000Z'; const minutes = DateCalculator.getMinutesSinceMidnight(isoString); // Note: This will be in local time after parsing expect(minutes).toBeGreaterThanOrEqual(0); expect(minutes).toBeLessThan(1440); }); it('should calculate duration in minutes', () => { const start = new Date(2024, 0, 15, 9, 0, 0); const end = new Date(2024, 0, 15, 10, 30, 0); const duration = DateCalculator.getDurationMinutes(start, end); expect(duration).toBe(90); }); it('should calculate duration from ISO strings', () => { const start = '2024-01-15T09:00:00.000Z'; const end = '2024-01-15T10:30:00.000Z'; const duration = DateCalculator.getDurationMinutes(start, end); expect(duration).toBe(90); }); it('should handle cross-midnight duration', () => { const start = new Date(2024, 0, 15, 23, 0, 0); const end = new Date(2024, 0, 16, 1, 0, 0); const duration = DateCalculator.getDurationMinutes(start, end); expect(duration).toBe(120); // 2 hours }); }); describe('Date Comparisons', () => { it('should check if date is today', () => { const today = new Date(); const yesterday = DateCalculator.addDays(new Date(), -1); expect(DateCalculator.isToday(today)).toBe(true); expect(DateCalculator.isToday(yesterday)).toBe(false); }); it('should check if same day', () => { const date1 = new Date(2024, 0, 15, 10, 0, 0); const date2 = new Date(2024, 0, 15, 14, 30, 0); const date3 = new Date(2024, 0, 16, 10, 0, 0); expect(DateCalculator.isSameDay(date1, date2)).toBe(true); expect(DateCalculator.isSameDay(date1, date3)).toBe(false); }); it('should check if multi-day event (Date objects)', () => { const start = new Date(2024, 0, 15, 10, 0, 0); const end1 = new Date(2024, 0, 15, 14, 0, 0); const end2 = new Date(2024, 0, 16, 10, 0, 0); expect(DateCalculator.isMultiDay(start, end1)).toBe(false); expect(DateCalculator.isMultiDay(start, end2)).toBe(true); }); it('should check if multi-day event (ISO strings)', () => { const start = '2024-01-15T10:00:00.000Z'; const end1 = '2024-01-15T14:00:00.000Z'; const end2 = '2024-01-16T10:00:00.000Z'; expect(DateCalculator.isMultiDay(start, end1)).toBe(false); expect(DateCalculator.isMultiDay(start, end2)).toBe(true); }); }); describe('Edge Cases', () => { it('should handle midnight', () => { const date = new Date(2024, 0, 15, 0, 0, 0); const minutes = DateCalculator.getMinutesSinceMidnight(date); expect(minutes).toBe(0); }); it('should handle end of day', () => { const date = new Date(2024, 0, 15, 23, 59, 0); const minutes = DateCalculator.getMinutesSinceMidnight(date); expect(minutes).toBe(1439); }); it('should handle leap year', () => { const date = new Date(2024, 1, 29); // February 29, 2024 (leap year) const nextDay = DateCalculator.addDays(date, 1); expect(nextDay.getDate()).toBe(1); // March 1 expect(nextDay.getMonth()).toBe(2); }); it('should handle DST transitions', () => { // This test depends on timezone, but we test the basic functionality const beforeDST = new Date(2024, 2, 30); // March 30, 2024 const afterDST = DateCalculator.addDays(beforeDST, 1); expect(afterDST.getDate()).toBe(31); }); }); describe('Error Handling', () => { it('should handle invalid dates gracefully', () => { const invalidDate = new Date('invalid'); const result = DateCalculator.formatISODate(invalidDate); expect(result).toBe(''); }); }); });