Files
vac-optimizer/src/app/services/calendar-settings-service.spec.ts
T
nessar 2edf2004f5 feat(planner): implement cancellation for planning calculations
- Refactor leave-planner.worker.ts to support cancellation of ongoing calculations.
- Introduce `calculatePlanningAsyncInternal` for asynchronous planning calculations.
- Add cancellation handling in the worker message event.
- Update planning-date.ts with new utility functions for date manipulation.
- Extend translation-service.ts and translation files (en.json, de.json, es.json, fr.json) to include new strings related to planning horizon and cancellation.
- Create documentation for the cancellation feature in planner-cancellation.md.
- Add unit tests for cancellation functionality in leave-planner-cancellation.spec.ts and leave-planner.worker.spec.ts.

#57 #58
2026-10-05 15:34:07 +02:00

131 lines
4.7 KiB
TypeScript

import { TestBed } from '@angular/core/testing';
import { provideZonelessChangeDetection } from '@angular/core';
import { CalendarSettingsService } from './calendar-settings-service';
import { vi } from 'vitest';
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');
});
});