Calendar/test/utils/DateService.test.ts
Janus C. H. Knudsen b5dfd57d9e Migrates date handling from date-fns to day.js
Replaces date-fns library with day.js to reduce bundle size and improve tree-shaking

- Centralizes all date logic in DateService
- Reduces library footprint from 576 KB to 29 KB
- Maintains 99.4% test coverage during migration
- Adds timezone and formatting plugins for day.js

Improves overall library performance and reduces dependency complexity
2025-11-12 23:51:48 +01:00

261 lines
No EOL
8.6 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import { DateService } from '../../src/utils/DateService';
import { createTestConfig } from '../helpers/config-helpers';
describe('DateService', () => {
let dateService: DateService;
beforeEach(() => {
const config = createTestConfig();
dateService = new DateService(config);
});
describe('Core Conversions', () => {
it('should convert local date to UTC', () => {
// 2024-01-15 10:00:00 Copenhagen (UTC+1 in winter)
const localDate = new Date(2024, 0, 15, 10, 0, 0);
const utcString = dateService.toUTC(localDate);
// Should be 09:00:00 UTC
expect(utcString).toContain('2024-01-15T09:00:00');
expect(utcString).toContain('Z');
});
it('should convert UTC to local date', () => {
const utcString = '2024-01-15T09:00:00.000Z';
const localDate = dateService.fromUTC(utcString);
// Should be 10:00 in Copenhagen (UTC+1)
expect(localDate.getHours()).toBe(10);
expect(localDate.getMinutes()).toBe(0);
});
it('should handle summer time (DST)', () => {
// 2024-07-15 10:00:00 Copenhagen (UTC+2 in summer)
const localDate = new Date(2024, 6, 15, 10, 0, 0);
const utcString = dateService.toUTC(localDate);
// Should be 08:00:00 UTC
expect(utcString).toContain('2024-07-15T08:00:00');
});
});
describe('Time Formatting', () => {
it('should format time without seconds', () => {
const date = new Date(2024, 0, 15, 14, 30, 45);
const formatted = dateService.formatTime(date);
expect(formatted).toBe('14:30');
});
it('should format time with seconds', () => {
const date = new Date(2024, 0, 15, 14, 30, 45);
const formatted = dateService.formatTime(date, true);
expect(formatted).toBe('14:30:45');
});
it('should format time range', () => {
const start = new Date(2024, 0, 15, 9, 0, 0);
const end = new Date(2024, 0, 15, 10, 30, 0);
const formatted = dateService.formatTimeRange(start, end);
expect(formatted).toBe('09:00 - 10:30');
});
it('should format technical datetime', () => {
const date = new Date(2024, 0, 15, 14, 30, 45);
const formatted = dateService.formatTechnicalDateTime(date);
expect(formatted).toBe('2024-01-15 14:30:45');
});
it('should format date as ISO', () => {
const date = new Date(2024, 0, 15, 14, 30, 0);
const formatted = dateService.formatDate(date);
expect(formatted).toBe('2024-01-15');
});
});
describe('Time Calculations', () => {
it('should convert time string to minutes', () => {
expect(dateService.timeToMinutes('09:00')).toBe(540);
expect(dateService.timeToMinutes('14:30')).toBe(870);
expect(dateService.timeToMinutes('00:00')).toBe(0);
expect(dateService.timeToMinutes('23:59')).toBe(1439);
});
it('should convert minutes to time string', () => {
expect(dateService.minutesToTime(540)).toBe('09:00');
expect(dateService.minutesToTime(870)).toBe('14:30');
expect(dateService.minutesToTime(0)).toBe('00:00');
expect(dateService.minutesToTime(1439)).toBe('23:59');
});
it('should get minutes since midnight', () => {
const date = new Date(2024, 0, 15, 14, 30, 0);
const minutes = dateService.getMinutesSinceMidnight(date);
expect(minutes).toBe(870); // 14*60 + 30
});
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 = dateService.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 = dateService.getDurationMinutes(start, end);
expect(duration).toBe(90);
});
});
describe('Week Operations', () => {
it('should get week bounds (Monday to Sunday)', () => {
// Wednesday, January 17, 2024
const date = new Date(2024, 0, 17);
const bounds = dateService.getWeekBounds(date);
// Should start on Monday, January 15
expect(bounds.start.getDate()).toBe(15);
expect(bounds.start.getDay()).toBe(1); // Monday
// Should end on Sunday, January 21
expect(bounds.end.getDate()).toBe(21);
expect(bounds.end.getDay()).toBe(0); // Sunday
});
it('should add weeks', () => {
const date = new Date(2024, 0, 15);
const newDate = dateService.addWeeks(date, 2);
expect(newDate.getDate()).toBe(29);
});
it('should subtract weeks', () => {
const date = new Date(2024, 0, 15);
const newDate = dateService.addWeeks(date, -1);
expect(newDate.getDate()).toBe(8);
});
});
describe('Grid Helpers', () => {
it('should create date at specific time', () => {
const baseDate = new Date(2024, 0, 15);
const date = dateService.createDateAtTime(baseDate, 870); // 14:30
expect(date.getHours()).toBe(14);
expect(date.getMinutes()).toBe(30);
expect(date.getDate()).toBe(15);
});
it('should snap to 15-minute interval', () => {
const date = new Date(2024, 0, 15, 14, 37, 0); // 14:37
const snapped = dateService.snapToInterval(date, 15);
// 14:37 is closer to 14:30 than 14:45, so should snap to 14:30
expect(snapped.getHours()).toBe(14);
expect(snapped.getMinutes()).toBe(30);
});
it('should snap to 30-minute interval', () => {
const date = new Date(2024, 0, 15, 14, 20, 0); // 14:20
const snapped = dateService.snapToInterval(date, 30);
// Should snap to 14:30
expect(snapped.getHours()).toBe(14);
expect(snapped.getMinutes()).toBe(30);
});
});
describe('Utility Methods', () => {
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(dateService.isSameDay(date1, date2)).toBe(true);
expect(dateService.isSameDay(date1, date3)).toBe(false);
});
it('should get start of day', () => {
const date = new Date(2024, 0, 15, 14, 30, 45);
const start = dateService.startOfDay(date);
expect(start.getHours()).toBe(0);
expect(start.getMinutes()).toBe(0);
expect(start.getSeconds()).toBe(0);
});
it('should get end of day', () => {
const date = new Date(2024, 0, 15, 14, 30, 45);
const end = dateService.endOfDay(date);
expect(end.getHours()).toBe(23);
expect(end.getMinutes()).toBe(59);
expect(end.getSeconds()).toBe(59);
});
it('should add days', () => {
const date = new Date(2024, 0, 15);
const newDate = dateService.addDays(date, 5);
expect(newDate.getDate()).toBe(20);
});
it('should add minutes', () => {
const date = new Date(2024, 0, 15, 10, 0, 0);
const newDate = dateService.addMinutes(date, 90);
expect(newDate.getHours()).toBe(11);
expect(newDate.getMinutes()).toBe(30);
});
it('should parse ISO string', () => {
const isoString = '2024-01-15T10:30:00.000Z';
const date = dateService.parseISO(isoString);
expect(date.toISOString()).toBe(isoString);
});
it('should validate dates', () => {
const validDate = new Date(2024, 0, 15);
const invalidDate = new Date('invalid');
expect(dateService.isValid(validDate)).toBe(true);
expect(dateService.isValid(invalidDate)).toBe(false);
});
});
describe('Edge Cases', () => {
it('should handle midnight', () => {
const date = new Date(2024, 0, 15, 0, 0, 0);
const minutes = dateService.getMinutesSinceMidnight(date);
expect(minutes).toBe(0);
});
it('should handle end of day', () => {
const date = new Date(2024, 0, 15, 23, 59, 0);
const minutes = dateService.getMinutesSinceMidnight(date);
expect(minutes).toBe(1439);
});
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 = dateService.getDurationMinutes(start, end);
expect(duration).toBe(120); // 2 hours
});
});
});