import { describe, it, expect, vi, afterEach } from 'vitest'; import { getWeekStart, prevWeek, nextWeek, weekDays, isToday, formatWeekRange, formatDayLabel } from './week'; describe('getWeekStart', () => { it('returns Monday for a Monday input', () => { // 2026-03-30 is a Monday const d = new Date('2026-03-30T12:00:00Z'); expect(getWeekStart(d)).toBe('2026-03-30'); }); it('returns Monday for a Wednesday input', () => { // 2026-04-01 is a Wednesday → week starts 2026-03-30 const d = new Date('2026-04-01T12:00:00Z'); expect(getWeekStart(d)).toBe('2026-03-30'); }); it('returns Monday for a Sunday input (edge case — goes back 6 days)', () => { // 2026-04-05 is a Sunday → week starts 2026-03-30 const d = new Date('2026-04-05T12:00:00Z'); expect(getWeekStart(d)).toBe('2026-03-30'); }); it('returns Monday for a Saturday input', () => { // 2026-04-04 is a Saturday → week starts 2026-03-30 const d = new Date('2026-04-04T12:00:00Z'); expect(getWeekStart(d)).toBe('2026-03-30'); }); it('handles year boundary correctly (Dec 28 2025 → week starts Dec 22 2025)', () => { const d = new Date('2025-12-28T12:00:00Z'); expect(getWeekStart(d)).toBe('2025-12-22'); }); }); describe('prevWeek', () => { it('returns the Monday 7 days before', () => { expect(prevWeek('2026-03-30')).toBe('2026-03-23'); }); it('handles month boundary', () => { expect(prevWeek('2026-04-06')).toBe('2026-03-30'); }); it('handles year boundary', () => { expect(prevWeek('2026-01-05')).toBe('2025-12-29'); }); }); describe('nextWeek', () => { it('returns the Monday 7 days after', () => { expect(nextWeek('2026-03-30')).toBe('2026-04-06'); }); it('handles month boundary', () => { expect(nextWeek('2026-03-30')).toBe('2026-04-06'); }); it('handles year boundary', () => { expect(nextWeek('2025-12-29')).toBe('2026-01-05'); }); }); describe('weekDays', () => { it('returns exactly 7 dates', () => { expect(weekDays('2026-03-30')).toHaveLength(7); }); it('starts on the given weekStart', () => { const days = weekDays('2026-03-30'); expect(days[0]).toBe('2026-03-30'); }); it('ends 6 days after weekStart', () => { const days = weekDays('2026-03-30'); expect(days[6]).toBe('2026-04-05'); }); it('has consecutive daily dates', () => { const days = weekDays('2026-03-30'); for (let i = 1; i < 7; i++) { const prev = new Date(days[i - 1] + 'T00:00:00Z'); const curr = new Date(days[i] + 'T00:00:00Z'); expect(curr.getTime() - prev.getTime()).toBe(86400000); } }); it('handles month boundary correctly', () => { const days = weekDays('2026-03-30'); expect(days[1]).toBe('2026-03-31'); expect(days[2]).toBe('2026-04-01'); }); }); describe('isToday', () => { afterEach(() => { vi.useRealTimers(); }); it('returns true for today (UTC)', () => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-04-03T10:00:00Z')); expect(isToday('2026-04-03')).toBe(true); }); it('returns false for yesterday', () => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-04-03T10:00:00Z')); expect(isToday('2026-04-02')).toBe(false); }); it('returns false for tomorrow', () => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-04-03T10:00:00Z')); expect(isToday('2026-04-04')).toBe(false); }); }); describe('formatWeekRange', () => { it('returns a non-empty string', () => { expect(formatWeekRange('2026-03-30')).toBeTruthy(); }); it('contains both start and end month info', () => { const range = formatWeekRange('2026-03-30'); // Start is March 30, end is April 5 — range should span both months expect(range).toContain('–'); }); }); describe('formatDayLabel', () => { it('returns a non-empty string', () => { expect(formatDayLabel('2026-03-30')).toBeTruthy(); }); it('contains a comma separator', () => { expect(formatDayLabel('2026-03-30')).toContain(','); }); });