import { describe, expect, it } from 'vitest' import { useCalendar } from '../use-calendar' describe('useCalendar', () => { describe('initialization', () => { it('initializes with null date by default', () => { const { selectedDate } = useCalendar() expect(selectedDate.value).toBeNull() }) it('initializes with provided date', () => { const date = new Date(2025, 5, 15) // June 15, 2025 const { selectedDate } = useCalendar(date) expect(selectedDate.value?.getFullYear()).toBe(2025) expect(selectedDate.value?.getMonth()).toBe(5) expect(selectedDate.value?.getDate()).toBe(15) }) it('sets viewDate to today when no initial date provided', () => { const { viewDate } = useCalendar() const today = new Date() expect(viewDate.value.getFullYear()).toBe(today.getFullYear()) expect(viewDate.value.getMonth()).toBe(today.getMonth()) }) it('sets viewDate to initial date when provided', () => { const date = new Date(2025, 5, 15) const { viewDate } = useCalendar(date) expect(viewDate.value.getFullYear()).toBe(2025) expect(viewDate.value.getMonth()).toBe(5) }) }) describe('weekday headers', () => { it('returns weekday headers starting with Sunday by default', () => { const { weekdayHeaders } = useCalendar() expect(weekdayHeaders.value).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']) }) it('returns weekday headers starting with Monday when firstDay is 1', () => { const { weekdayHeaders } = useCalendar(null, { firstDay: 1 }) expect(weekdayHeaders.value).toEqual(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']) }) it('returns full weekday names for accessibility', () => { const { weekdayHeadersFull } = useCalendar() expect(weekdayHeadersFull.value).toEqual([ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]) }) }) describe('month display', () => { it('returns correct month name', () => { const date = new Date(2025, 5, 15) // June const { monthName } = useCalendar(date) expect(monthName.value).toBe('June') }) it('returns correct short month name', () => { const date = new Date(2025, 11, 25) // December const { monthNameShort } = useCalendar(date) expect(monthNameShort.value).toBe('Dec') }) }) describe('calendar days', () => { it('generates 42 days (6 weeks)', () => { const { calendarDays } = useCalendar(new Date(2025, 5, 15)) expect(calendarDays.value).toHaveLength(42) }) it('marks days outside current month', () => { const { calendarDays } = useCalendar(new Date(2025, 5, 15)) // June 2025 const outsideDays = calendarDays.value.filter(d => d.isOutsideMonth) expect(outsideDays.length).toBeGreaterThan(0) }) it('marks the selected date', () => { const date = new Date(2025, 5, 15) const { calendarDays } = useCalendar(date) const selectedDays = calendarDays.value.filter(d => d.isSelected) expect(selectedDays).toHaveLength(1) expect(selectedDays[0]?.day).toBe(15) }) it('marks today correctly', () => { const today = new Date() const { calendarDays, goToDate } = useCalendar() goToDate(today) const todayDays = calendarDays.value.filter(d => d.isToday && !d.isOutsideMonth) expect(todayDays).toHaveLength(1) expect(todayDays[0]?.day).toBe(today.getDate()) }) }) describe('navigation', () => { it('navigates to next month', () => { const { viewMonth, viewYear, nextMonth } = useCalendar(new Date(2025, 5, 15)) expect(viewMonth.value).toBe(5) nextMonth() expect(viewMonth.value).toBe(6) expect(viewYear.value).toBe(2025) }) it('navigates to previous month', () => { const { viewMonth, viewYear, prevMonth } = useCalendar(new Date(2025, 5, 15)) expect(viewMonth.value).toBe(5) prevMonth() expect(viewMonth.value).toBe(4) expect(viewYear.value).toBe(2025) }) it('handles year rollover when navigating forward', () => { const { viewMonth, viewYear, nextMonth } = useCalendar(new Date(2025, 11, 15)) expect(viewMonth.value).toBe(11) nextMonth() expect(viewMonth.value).toBe(0) expect(viewYear.value).toBe(2026) }) it('handles year rollover when navigating backward', () => { const { viewMonth, viewYear, prevMonth } = useCalendar(new Date(2025, 0, 15)) expect(viewMonth.value).toBe(0) prevMonth() expect(viewMonth.value).toBe(11) expect(viewYear.value).toBe(2024) }) it('goes to specific month', () => { const { viewMonth, goToMonth } = useCalendar(new Date(2025, 5, 15)) goToMonth(10) expect(viewMonth.value).toBe(10) }) it('goes to specific year', () => { const { viewYear, goToYear } = useCalendar(new Date(2025, 5, 15)) goToYear(2030) expect(viewYear.value).toBe(2030) }) it('goes to today', () => { const { viewMonth, viewYear, goToToday } = useCalendar(new Date(2020, 0, 1)) const today = new Date() goToToday() expect(viewMonth.value).toBe(today.getMonth()) expect(viewYear.value).toBe(today.getFullYear()) }) }) describe('selection', () => { it('selects a date', () => { const { selectedDate, selectDate } = useCalendar() const date = new Date(2025, 5, 20) selectDate(date) expect(selectedDate.value?.getDate()).toBe(20) expect(selectedDate.value?.getMonth()).toBe(5) }) it('clears selection', () => { const { selectedDate, clearSelection } = useCalendar(new Date(2025, 5, 15)) expect(selectedDate.value).not.toBeNull() clearSelection() expect(selectedDate.value).toBeNull() }) it('does not select disabled dates', () => { const minDate = new Date(2025, 5, 10) const { selectedDate, selectDate } = useCalendar(null, { minDate }) selectDate(new Date(2025, 5, 5)) // Before minDate expect(selectedDate.value).toBeNull() }) }) describe('date constraints', () => { it('marks dates before minDate as disabled', () => { const minDate = new Date(2025, 5, 15) const { calendarDays } = useCalendar(new Date(2025, 5, 20), { minDate }) const june14 = calendarDays.value.find(d => d.day === 14 && d.month === 5) const june15 = calendarDays.value.find(d => d.day === 15 && d.month === 5) expect(june14?.isDisabled).toBe(true) expect(june15?.isDisabled).toBe(false) }) it('marks dates after maxDate as disabled', () => { const maxDate = new Date(2025, 5, 15) const { calendarDays } = useCalendar(new Date(2025, 5, 10), { maxDate }) const june15 = calendarDays.value.find(d => d.day === 15 && d.month === 5) const june16 = calendarDays.value.find(d => d.day === 16 && d.month === 5) expect(june15?.isDisabled).toBe(false) expect(june16?.isDisabled).toBe(true) }) }) describe('formatting', () => { it('formats date with default format', () => { const { formatDate } = useCalendar(new Date(2025, 5, 15)) expect(formatDate()).toBe('15 Jun 2025') }) it('formats date with custom format', () => { const { formatDate } = useCalendar(new Date(2025, 5, 15)) expect(formatDate('YYYY-MM-DD')).toBe('2025-06-15') }) it('formats date with full month name', () => { const { formatDate } = useCalendar(new Date(2025, 5, 15)) expect(formatDate('MMMM D, YYYY')).toBe('June 15, 2025') }) it('returns empty string when no date selected', () => { const { formatDate } = useCalendar() expect(formatDate()).toBe('') }) }) describe('utility functions', () => { it('isSameDay returns true for same day', () => { const { isSameDay } = useCalendar() const a = new Date(2025, 5, 15, 10, 30) const b = new Date(2025, 5, 15, 20, 45) expect(isSameDay(a, b)).toBe(true) }) it('isSameDay returns false for different days', () => { const { isSameDay } = useCalendar() const a = new Date(2025, 5, 15) const b = new Date(2025, 5, 16) expect(isSameDay(a, b)).toBe(false) }) it('isSameDay handles null values', () => { const { isSameDay } = useCalendar() expect(isSameDay(null, new Date())).toBe(false) expect(isSameDay(new Date(), null)).toBe(false) expect(isSameDay(null, null)).toBe(false) }) }) })