Calendar/test/utils/DateCalculator.test.ts

310 lines
11 KiB
TypeScript
Raw Normal View History

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('');
});
});
});