import { TestBed } from '@angular/core/testing'; import { provideZonelessChangeDetection } from '@angular/core'; import { CalendarSettingsService } from './calendar-settings-service'; import { vi } from '../../testing/vitest-compat'; describe('CalendarSettingsService', () => { let service: CalendarSettingsService; beforeEach(() => { localStorage.clear(); vi.useFakeTimers({ toFake: ['Date'] }); vi.setSystemTime(new Date('2026-10-04T22:30:00Z')); TestBed.configureTestingModule({ providers: [provideZonelessChangeDetection()], }); service = TestBed.inject(CalendarSettingsService); }); afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); localStorage.clear(); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('defaults to the Paris date and displays the day before the anniversary as the last planning date', () => { expect(service.planningDates()).toEqual({ start: '2026-10-05', lastPlanningDate: '2027-10-04', }); expect(service.planningHorizon()).toEqual({ start: '2026-10-05', end: '2027-10-05' }); expect(localStorage.getItem('calendarSettings.planningDates')).toBeNull(); }); it('saves and restores fixed historical dates before applying a later default', () => { service.setPlanningDates('2024-02-29', '2026-02-28'); vi.setSystemTime(new Date('2029-08-01T12:00:00Z')); const restored = TestBed.runInInjectionContext(() => new CalendarSettingsService()); expect(restored.planningDates()).toEqual({ start: '2024-02-29', lastPlanningDate: '2026-02-28', }); expect(restored.planningHorizon()).toEqual({ start: '2024-02-29', end: '2026-03-01' }); }); it('uses the existing February 29 anniversary convention for the unsaved default', () => { vi.setSystemTime(new Date('2024-02-29T12:00:00Z')); const leapDay = TestBed.runInInjectionContext(() => new CalendarSettingsService()); expect(leapDay.planningDates()).toEqual({ start: '2024-02-29', lastPlanningDate: '2025-02-27', }); expect(leapDay.planningHorizon()).toEqual({ start: '2024-02-29', end: '2025-02-28' }); }); it.each([ ['2024-02-29', '2024-03-01'], ['2026-03-29', '2026-03-30'], ['2026-10-25', '2026-10-26'], ['2026-12-31', '2027-01-01'], ])( 'converts a single inclusive planning date %s across leap days, clock changes and years', (date, end) => { const previousTimeZone = process.env['TZ']; process.env['TZ'] = 'Pacific/Auckland'; try { service.setPlanningDates(date, date); expect(service.planningHorizon()).toEqual({ start: date, end }); } finally { if (previousTimeZone === undefined) delete process.env['TZ']; else process.env['TZ'] = previousTimeZone; } }, ); it.each([ ['2024-02-30', '2024-03-01', 'invalidDate'], ['2024-02-29', '2024-13-01', 'invalidDate'], ['29/02/2024', '2024-03-01', 'invalidDate'], ['', '2024-03-01', 'invalidDate'], ['2024-03-02', '2024-03-01', 'horizonOrder'], ])( 'keeps invalid input visible without replacing the last valid saved dates (%s, %s)', (start, last, error) => { service.setPlanningDates('2024-02-29', '2027-02-28'); service.setPlanningDates(start, last); expect(service.planningDates()).toEqual({ start, lastPlanningDate: last }); expect(service.planningHorizon()).toBeNull(); expect(service.planningHorizonError()).toBe(error); const restored = TestBed.runInInjectionContext(() => new CalendarSettingsService()); expect(restored.planningHorizon()).toEqual({ start: '2024-02-29', end: '2027-03-01' }); }, ); it.each([ '{', 'null', '{}', '{"start":"2024-02-30","lastPlanningDate":"2024-03-01"}', '{"start":"2024-03-02","lastPlanningDate":"2024-03-01"}', ])('uses an unsaved default when saved dates are unreadable: %s', (saved) => { vi.spyOn(console, 'warn').mockImplementation(() => {}); localStorage.setItem('calendarSettings.planningDates', saved); const restored = TestBed.runInInjectionContext(() => new CalendarSettingsService()); expect(restored.planningHorizon()).toEqual({ start: '2026-10-05', end: '2027-10-05' }); expect(localStorage.getItem('calendarSettings.planningDates')).toBe(saved); }); it('should initialize with default values', () => { expect(service.get('showWeekNumbers')()).toBe(false); }); it('should allow updating showWeekNumbers', () => { service.get('showWeekNumbers').set(true); expect(service.get('showWeekNumbers')()).toBe(true); }); it('should provide settings array for UI iteration', () => { const settingsArray = service.settingsArray; expect(settingsArray.length).toBe(1); expect(settingsArray[0].id).toBe('showWeekNumbers'); }); it('should return correct descriptions', () => { expect(service.getDescription('showWeekNumbers')).toBe('Afficher les numéros de semaine'); }); });