Hotfix: Ensure fixed days are counted in days off
This commit is contained in:
@@ -78,7 +78,7 @@
|
|||||||
} else if (isOptimizedDayOff(day)) {
|
} else if (isOptimizedDayOff(day)) {
|
||||||
return 'Day off (calculated)';
|
return 'Day off (calculated)';
|
||||||
} else {
|
} else {
|
||||||
return 'Tap to select fixed day off';
|
return 'Tap to add fixed day off';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.clickable:hover {
|
.clickable:hover {
|
||||||
opacity: 0.8;
|
opacity: 0.7;
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
transition: transform 0.1s, opacity 0.1s;
|
transition: transform 0.1s, opacity 0.1s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,31 +46,40 @@
|
|||||||
|
|
||||||
$: selectedCountryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry) || '';
|
$: selectedCountryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry) || '';
|
||||||
|
|
||||||
$: if (selectedCountryCode || selectedStateCode || daysOff || year || startDate) {
|
// Reactive: when year changes, load start date and fixed days off for that year
|
||||||
|
$: if (year !== undefined && year && typeof window !== 'undefined') {
|
||||||
|
startDate = getStartDate(year);
|
||||||
|
loadFixedDaysOff(year);
|
||||||
|
// Adjust daysOff to include fixed days off if they exist
|
||||||
|
// Calculate base days off (total - fixed days)
|
||||||
|
const baseDaysOff = Math.max(0, daysOff - fixedDaysOff.length);
|
||||||
|
// If we have fixed days but base is 0, get the country default and add fixed days
|
||||||
|
if (fixedDaysOff.length > 0 && baseDaysOff === 0 && daysOff < fixedDaysOff.length) {
|
||||||
|
const countryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry) || '';
|
||||||
|
const currentDefaultDaysOff = ptoData[countryCode] || 0;
|
||||||
|
daysOff = currentDefaultDaysOff + fixedDaysOff.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (selectedCountryCode && year !== undefined && year) {
|
||||||
updateHolidays();
|
updateHolidays();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reactive: when fixedDaysOff changes, update calculations
|
// Reactive: when fixedDaysOff changes, update calculations
|
||||||
$: if (fixedDaysOff) {
|
$: if (fixedDaysOff && year !== undefined && year) {
|
||||||
updateHolidays();
|
updateHolidays();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reactive: when year changes, load start date and fixed days off for that year
|
|
||||||
$: if (year !== undefined && year) {
|
|
||||||
startDate = getStartDate(year);
|
|
||||||
loadFixedDaysOff(year);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reactive: when startDate or year changes, update excluded months visibility
|
// Reactive: when startDate or year changes, update excluded months visibility
|
||||||
$: if (year !== undefined && year && startDate) {
|
$: if (year !== undefined && year && startDate) {
|
||||||
showExcludedMonths = !hasExcludedMonths();
|
showExcludedMonths = !hasExcludedMonths();
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (daysOff) {
|
$: if (daysOff !== undefined && typeof window !== 'undefined') {
|
||||||
localStorage.setItem('daysOff', daysOff.toString());
|
localStorage.setItem('daysOff', daysOff.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (year) {
|
$: if (year && typeof window !== 'undefined') {
|
||||||
localStorage.setItem('year', year.toString());
|
localStorage.setItem('year', year.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +113,6 @@
|
|||||||
|
|
||||||
year = storedYear ? parseInt(storedYear, 10) : defaultYear;
|
year = storedYear ? parseInt(storedYear, 10) : defaultYear;
|
||||||
selectedCountry = storedCountry || defaultCountry;
|
selectedCountry = storedCountry || defaultCountry;
|
||||||
daysOff = storedDaysOff ? parseInt(storedDaysOff, 10) : defaultDaysOff;
|
|
||||||
|
|
||||||
// Load state per country
|
// Load state per country
|
||||||
const countryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry) || '';
|
const countryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry) || '';
|
||||||
@@ -115,8 +123,39 @@
|
|||||||
selectedState = '';
|
selectedState = '';
|
||||||
selectedStateCode = '';
|
selectedStateCode = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the current country's default days off
|
||||||
|
const currentDefaultDaysOff = ptoData[countryCode] || 0;
|
||||||
|
|
||||||
startDate = getStartDate(year);
|
startDate = getStartDate(year);
|
||||||
loadFixedDaysOff(year);
|
loadFixedDaysOff(year);
|
||||||
|
|
||||||
|
// Initialize daysOff: use stored value if it exists, otherwise use country default
|
||||||
|
// Then add fixed days off to it
|
||||||
|
if (storedDaysOff !== null && storedDaysOff !== '') {
|
||||||
|
const storedValue = parseInt(storedDaysOff, 10);
|
||||||
|
// If stored value is 0 and there are no fixed days, use default instead
|
||||||
|
if (storedValue === 0 && fixedDaysOff.length === 0) {
|
||||||
|
daysOff = currentDefaultDaysOff;
|
||||||
|
} else {
|
||||||
|
daysOff = storedValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No stored value, use country default
|
||||||
|
daysOff = currentDefaultDaysOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add fixed days off to the base days off
|
||||||
|
if (fixedDaysOff.length > 0) {
|
||||||
|
// Calculate base: if daysOff is less than fixed days, base is 0, otherwise subtract fixed days
|
||||||
|
const baseDaysOff = Math.max(0, daysOff - fixedDaysOff.length);
|
||||||
|
// If base is 0 and we have fixed days, set base to default and add fixed days
|
||||||
|
if (baseDaysOff === 0 && daysOff < fixedDaysOff.length) {
|
||||||
|
daysOff = currentDefaultDaysOff + fixedDaysOff.length;
|
||||||
|
} else {
|
||||||
|
daysOff = baseDaysOff + fixedDaysOff.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
// showExcludedMonths will be set by reactive statement
|
// showExcludedMonths will be set by reactive statement
|
||||||
updateHolidays();
|
updateHolidays();
|
||||||
});
|
});
|
||||||
@@ -166,7 +205,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateHolidays() {
|
function updateHolidays() {
|
||||||
if (selectedCountryCode) {
|
if (selectedCountryCode && year !== undefined && year) {
|
||||||
updateStatesList(selectedCountryCode);
|
updateStatesList(selectedCountryCode);
|
||||||
let allHolidays = getHolidaysForYear(selectedCountryCode, year, selectedStateCode);
|
let allHolidays = getHolidaysForYear(selectedCountryCode, year, selectedStateCode);
|
||||||
holidays = allHolidays.map(holiday => ({
|
holidays = allHolidays.map(holiday => ({
|
||||||
@@ -175,7 +214,10 @@
|
|||||||
hidden: isHolidayHidden(holiday)
|
hidden: isHolidayHidden(holiday)
|
||||||
}));
|
}));
|
||||||
const visibleHolidays = holidays.filter(h => !h.hidden);
|
const visibleHolidays = holidays.filter(h => !h.hidden);
|
||||||
optimizedDaysOff = optimizeDaysOff(visibleHolidays, year, daysOff, weekendDays, startDate, fixedDaysOff);
|
// Use baseDaysOff for optimization (not including fixed days in the budget)
|
||||||
|
// Calculate it here to ensure it's always defined
|
||||||
|
const budgetDaysOff = Math.max(0, (daysOff || 0) - (fixedDaysOff?.length || 0));
|
||||||
|
optimizedDaysOff = optimizeDaysOff(visibleHolidays, year, budgetDaysOff, weekendDays, startDate, fixedDaysOff);
|
||||||
consecutiveDaysOff = calculateConsecutiveDaysOff(visibleHolidays, optimizedDaysOff, year, weekendDays, startDate, fixedDaysOff);
|
consecutiveDaysOff = calculateConsecutiveDaysOff(visibleHolidays, optimizedDaysOff, year, weekendDays, startDate, fixedDaysOff);
|
||||||
} else {
|
} else {
|
||||||
holidays = [];
|
holidays = [];
|
||||||
@@ -189,21 +231,32 @@
|
|||||||
const normalizedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
const normalizedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||||
const dateKeyStr = dateKey(normalizedDate);
|
const dateKeyStr = dateKey(normalizedDate);
|
||||||
|
|
||||||
|
// Check if this day is already a day off for any reason (holiday, weekend, or optimized)
|
||||||
|
const isWeekendDay = weekendDays.includes(normalizedDate.getDay());
|
||||||
|
const isHolidayDay = holidays.some(h => datesMatch(h.date, normalizedDate));
|
||||||
|
const isOptimizedDay = optimizedDaysOff.some(d => datesMatch(d, normalizedDate));
|
||||||
|
const isAlreadyDayOff = isWeekendDay || isHolidayDay || isOptimizedDay;
|
||||||
|
|
||||||
// Check if date is already in fixedDaysOff
|
// Check if date is already in fixedDaysOff
|
||||||
const existingIndex = fixedDaysOff.findIndex(d => dateKey(d) === dateKeyStr);
|
const existingIndex = fixedDaysOff.findIndex(d => dateKey(d) === dateKeyStr);
|
||||||
|
|
||||||
if (existingIndex >= 0) {
|
if (existingIndex >= 0) {
|
||||||
// Remove if already exists
|
// Remove if already exists - don't subtract from days off count
|
||||||
fixedDaysOff = fixedDaysOff.filter((_, i) => i !== existingIndex);
|
fixedDaysOff = fixedDaysOff.filter((_, i) => i !== existingIndex);
|
||||||
} else {
|
} else {
|
||||||
// Add if doesn't exist
|
// Add if doesn't exist
|
||||||
fixedDaysOff = [...fixedDaysOff, normalizedDate];
|
fixedDaysOff = [...fixedDaysOff, normalizedDate];
|
||||||
|
// Only increase days off if this day isn't already a day off for another reason
|
||||||
|
if (!isAlreadyDayOff) {
|
||||||
|
daysOff++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to localStorage
|
// Save to localStorage
|
||||||
saveFixedDaysOff(year);
|
saveFixedDaysOff(year);
|
||||||
|
localStorage.setItem('daysOff', daysOff.toString());
|
||||||
|
|
||||||
// Update calculations
|
// Update calculations (using baseDaysOff for optimization)
|
||||||
updateHolidays();
|
updateHolidays();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +296,8 @@
|
|||||||
break;
|
break;
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (daysOff > 0) {
|
const minDaysOff = fixedDaysOff.length;
|
||||||
|
if (daysOff > minDaysOff) {
|
||||||
daysOff--;
|
daysOff--;
|
||||||
updateHolidays();
|
updateHolidays();
|
||||||
}
|
}
|
||||||
@@ -374,6 +428,13 @@
|
|||||||
return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a date matches another date (ignoring time)
|
||||||
|
function datesMatch(date1: Date, date2: Date): boolean {
|
||||||
|
return date1.getFullYear() === date2.getFullYear() &&
|
||||||
|
date1.getMonth() === date2.getMonth() &&
|
||||||
|
date1.getDate() === date2.getDate();
|
||||||
|
}
|
||||||
|
|
||||||
// Load fixed days off for a given year from localStorage
|
// Load fixed days off for a given year from localStorage
|
||||||
function loadFixedDaysOff(year: number) {
|
function loadFixedDaysOff(year: number) {
|
||||||
try {
|
try {
|
||||||
@@ -1115,7 +1176,7 @@
|
|||||||
aria-label="Select country" />
|
aria-label="Select country" />
|
||||||
and have
|
and have
|
||||||
<span class="arrow-controls">
|
<span class="arrow-controls">
|
||||||
<button on:click={() => { if (daysOff > 0) { daysOff--; updateHolidays(); } }} aria-label="Decrease days off">▼</button>
|
<button on:click={() => { const minDaysOff = fixedDaysOff.length; if (daysOff > minDaysOff) { daysOff--; updateHolidays(); } }} aria-label="Decrease days off">▼</button>
|
||||||
<span class="bold">{daysOff}</span>
|
<span class="bold">{daysOff}</span>
|
||||||
<button on:click={() => { daysOff++; updateHolidays(); }} aria-label="Increase days off">▲</button>
|
<button on:click={() => { daysOff++; updateHolidays(); }} aria-label="Increase days off">▲</button>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
317
src/routes/page.test.ts
Normal file
317
src/routes/page.test.ts
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
import { describe, it, expect, beforeEach } from 'vitest';
|
||||||
|
|
||||||
|
// Helper function to create a date key (same as in +page.svelte)
|
||||||
|
function dateKey(date: Date): string {
|
||||||
|
return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a day is already a day off
|
||||||
|
function isAlreadyDayOff(
|
||||||
|
date: Date,
|
||||||
|
weekendDays: number[],
|
||||||
|
holidays: Array<{ date: Date; name: string }>,
|
||||||
|
optimizedDaysOff: Date[]
|
||||||
|
): boolean {
|
||||||
|
const isWeekendDay = weekendDays.includes(date.getDay());
|
||||||
|
const isHolidayDay = holidays.some(h =>
|
||||||
|
h.date.getFullYear() === date.getFullYear() &&
|
||||||
|
h.date.getMonth() === date.getMonth() &&
|
||||||
|
h.date.getDate() === date.getDate()
|
||||||
|
);
|
||||||
|
const isOptimizedDay = optimizedDaysOff.some(d =>
|
||||||
|
d.getFullYear() === date.getFullYear() &&
|
||||||
|
d.getMonth() === date.getMonth() &&
|
||||||
|
d.getDate() === date.getDate()
|
||||||
|
);
|
||||||
|
return isWeekendDay || isHolidayDay || isOptimizedDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate toggleFixedDayOff logic
|
||||||
|
function simulateToggleFixedDayOff(
|
||||||
|
date: Date,
|
||||||
|
fixedDaysOff: Date[],
|
||||||
|
daysOff: number,
|
||||||
|
weekendDays: number[],
|
||||||
|
holidays: Array<{ date: Date; name: string }>,
|
||||||
|
optimizedDaysOff: Date[]
|
||||||
|
): { fixedDaysOff: Date[]; daysOff: number } {
|
||||||
|
const normalizedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||||
|
const dateKeyStr = dateKey(normalizedDate);
|
||||||
|
|
||||||
|
const isAlreadyDayOffDay = isAlreadyDayOff(normalizedDate, weekendDays, holidays, optimizedDaysOff);
|
||||||
|
|
||||||
|
const existingIndex = fixedDaysOff.findIndex(d => dateKey(d) === dateKeyStr);
|
||||||
|
|
||||||
|
let newFixedDaysOff: Date[];
|
||||||
|
let newDaysOff = daysOff;
|
||||||
|
|
||||||
|
if (existingIndex >= 0) {
|
||||||
|
// Remove if already exists - don't subtract from days off count
|
||||||
|
newFixedDaysOff = fixedDaysOff.filter((_, i) => i !== existingIndex);
|
||||||
|
} else {
|
||||||
|
// Add if doesn't exist
|
||||||
|
newFixedDaysOff = [...fixedDaysOff, normalizedDate];
|
||||||
|
// Only increase days off if this day isn't already a day off for another reason
|
||||||
|
if (!isAlreadyDayOffDay) {
|
||||||
|
newDaysOff = daysOff + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fixedDaysOff: newFixedDaysOff, daysOff: newDaysOff };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to check minimum days off validation
|
||||||
|
function canDecreaseDaysOff(daysOff: number, fixedDaysOffCount: number): boolean {
|
||||||
|
return daysOff > fixedDaysOffCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Fixed Days Off Logic', () => {
|
||||||
|
const TEST_YEAR = 2024;
|
||||||
|
const WEEKEND_DAYS = [0, 6]; // Sunday, Saturday
|
||||||
|
|
||||||
|
describe('toggleFixedDayOff behavior', () => {
|
||||||
|
it('should increase days off when adding a fixed day off to a regular day', () => {
|
||||||
|
const regularDay = new Date(TEST_YEAR, 0, 15); // Monday, Jan 15
|
||||||
|
const fixedDaysOff: Date[] = [];
|
||||||
|
const daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
const optimizedDaysOff: Date[] = [];
|
||||||
|
|
||||||
|
const result = simulateToggleFixedDayOff(
|
||||||
|
regularDay,
|
||||||
|
fixedDaysOff,
|
||||||
|
daysOff,
|
||||||
|
WEEKEND_DAYS,
|
||||||
|
holidays,
|
||||||
|
optimizedDaysOff
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.fixedDaysOff.length).toBe(1);
|
||||||
|
expect(result.daysOff).toBe(11); // Increased by 1
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT increase days off when adding a fixed day off to a weekend', () => {
|
||||||
|
const weekendDay = new Date(TEST_YEAR, 0, 13); // Saturday, Jan 13
|
||||||
|
const fixedDaysOff: Date[] = [];
|
||||||
|
const daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
const optimizedDaysOff: Date[] = [];
|
||||||
|
|
||||||
|
const result = simulateToggleFixedDayOff(
|
||||||
|
weekendDay,
|
||||||
|
fixedDaysOff,
|
||||||
|
daysOff,
|
||||||
|
WEEKEND_DAYS,
|
||||||
|
holidays,
|
||||||
|
optimizedDaysOff
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.fixedDaysOff.length).toBe(1);
|
||||||
|
expect(result.daysOff).toBe(10); // Not increased
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT increase days off when adding a fixed day off to a holiday', () => {
|
||||||
|
const holidayDate = new Date(TEST_YEAR, 0, 1); // New Year's Day
|
||||||
|
const fixedDaysOff: Date[] = [];
|
||||||
|
const daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [
|
||||||
|
{ date: new Date(TEST_YEAR, 0, 1), name: 'New Year\'s Day' }
|
||||||
|
];
|
||||||
|
const optimizedDaysOff: Date[] = [];
|
||||||
|
|
||||||
|
const result = simulateToggleFixedDayOff(
|
||||||
|
holidayDate,
|
||||||
|
fixedDaysOff,
|
||||||
|
daysOff,
|
||||||
|
WEEKEND_DAYS,
|
||||||
|
holidays,
|
||||||
|
optimizedDaysOff
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.fixedDaysOff.length).toBe(1);
|
||||||
|
expect(result.daysOff).toBe(10); // Not increased
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT increase days off when adding a fixed day off to an optimized day', () => {
|
||||||
|
const optimizedDay = new Date(TEST_YEAR, 0, 15); // Monday, Jan 15
|
||||||
|
const fixedDaysOff: Date[] = [];
|
||||||
|
const daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
const optimizedDaysOff: Date[] = [new Date(TEST_YEAR, 0, 15)];
|
||||||
|
|
||||||
|
const result = simulateToggleFixedDayOff(
|
||||||
|
optimizedDay,
|
||||||
|
fixedDaysOff,
|
||||||
|
daysOff,
|
||||||
|
WEEKEND_DAYS,
|
||||||
|
holidays,
|
||||||
|
optimizedDaysOff
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.fixedDaysOff.length).toBe(1);
|
||||||
|
expect(result.daysOff).toBe(10); // Not increased
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT decrease days off when removing a fixed day off', () => {
|
||||||
|
const fixedDay = new Date(TEST_YEAR, 0, 15);
|
||||||
|
const fixedDaysOff: Date[] = [fixedDay];
|
||||||
|
const daysOff = 11;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
const optimizedDaysOff: Date[] = [];
|
||||||
|
|
||||||
|
const result = simulateToggleFixedDayOff(
|
||||||
|
fixedDay,
|
||||||
|
fixedDaysOff,
|
||||||
|
daysOff,
|
||||||
|
WEEKEND_DAYS,
|
||||||
|
holidays,
|
||||||
|
optimizedDaysOff
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.fixedDaysOff.length).toBe(0);
|
||||||
|
expect(result.daysOff).toBe(11); // Not decreased
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT decrease days off when removing a fixed day off that was on a weekend', () => {
|
||||||
|
const weekendDay = new Date(TEST_YEAR, 0, 13); // Saturday
|
||||||
|
const fixedDaysOff: Date[] = [weekendDay];
|
||||||
|
const daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
const optimizedDaysOff: Date[] = [];
|
||||||
|
|
||||||
|
const result = simulateToggleFixedDayOff(
|
||||||
|
weekendDay,
|
||||||
|
fixedDaysOff,
|
||||||
|
daysOff,
|
||||||
|
WEEKEND_DAYS,
|
||||||
|
holidays,
|
||||||
|
optimizedDaysOff
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.fixedDaysOff.length).toBe(0);
|
||||||
|
expect(result.daysOff).toBe(10); // Not decreased
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle multiple fixed days off correctly', () => {
|
||||||
|
const day1 = new Date(TEST_YEAR, 0, 15);
|
||||||
|
const day2 = new Date(TEST_YEAR, 0, 16);
|
||||||
|
const day3 = new Date(TEST_YEAR, 0, 17);
|
||||||
|
let fixedDaysOff: Date[] = [];
|
||||||
|
let daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
const optimizedDaysOff: Date[] = [];
|
||||||
|
|
||||||
|
// Add first day
|
||||||
|
let result = simulateToggleFixedDayOff(day1, fixedDaysOff, daysOff, WEEKEND_DAYS, holidays, optimizedDaysOff);
|
||||||
|
fixedDaysOff = result.fixedDaysOff;
|
||||||
|
daysOff = result.daysOff;
|
||||||
|
expect(daysOff).toBe(11);
|
||||||
|
|
||||||
|
// Add second day
|
||||||
|
result = simulateToggleFixedDayOff(day2, fixedDaysOff, daysOff, WEEKEND_DAYS, holidays, optimizedDaysOff);
|
||||||
|
fixedDaysOff = result.fixedDaysOff;
|
||||||
|
daysOff = result.daysOff;
|
||||||
|
expect(daysOff).toBe(12);
|
||||||
|
|
||||||
|
// Add third day
|
||||||
|
result = simulateToggleFixedDayOff(day3, fixedDaysOff, daysOff, WEEKEND_DAYS, holidays, optimizedDaysOff);
|
||||||
|
fixedDaysOff = result.fixedDaysOff;
|
||||||
|
daysOff = result.daysOff;
|
||||||
|
expect(daysOff).toBe(13);
|
||||||
|
|
||||||
|
// Remove one day - count should stay the same
|
||||||
|
result = simulateToggleFixedDayOff(day2, fixedDaysOff, daysOff, WEEKEND_DAYS, holidays, optimizedDaysOff);
|
||||||
|
expect(result.fixedDaysOff.length).toBe(2);
|
||||||
|
expect(result.daysOff).toBe(13); // Not decreased
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Minimum days off validation', () => {
|
||||||
|
it('should allow decreasing when days off is greater than fixed days off count', () => {
|
||||||
|
const daysOff = 15;
|
||||||
|
const fixedDaysOffCount = 5;
|
||||||
|
|
||||||
|
expect(canDecreaseDaysOff(daysOff, fixedDaysOffCount)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT allow decreasing when days off equals fixed days off count', () => {
|
||||||
|
const daysOff = 5;
|
||||||
|
const fixedDaysOffCount = 5;
|
||||||
|
|
||||||
|
expect(canDecreaseDaysOff(daysOff, fixedDaysOffCount)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT allow decreasing when days off is less than fixed days off count', () => {
|
||||||
|
const daysOff = 3;
|
||||||
|
const fixedDaysOffCount = 5;
|
||||||
|
|
||||||
|
expect(canDecreaseDaysOff(daysOff, fixedDaysOffCount)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow decreasing when there are no fixed days off', () => {
|
||||||
|
const daysOff = 10;
|
||||||
|
const fixedDaysOffCount = 0;
|
||||||
|
|
||||||
|
expect(canDecreaseDaysOff(daysOff, fixedDaysOffCount)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT allow decreasing when days off is 0 and there are no fixed days off', () => {
|
||||||
|
const daysOff = 0;
|
||||||
|
const fixedDaysOffCount = 0;
|
||||||
|
|
||||||
|
expect(canDecreaseDaysOff(daysOff, fixedDaysOffCount)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Edge cases', () => {
|
||||||
|
it('should handle adding and removing the same day multiple times', () => {
|
||||||
|
const day = new Date(TEST_YEAR, 0, 15);
|
||||||
|
let fixedDaysOff: Date[] = [];
|
||||||
|
let daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
const optimizedDaysOff: Date[] = [];
|
||||||
|
|
||||||
|
// Add
|
||||||
|
let result = simulateToggleFixedDayOff(day, fixedDaysOff, daysOff, WEEKEND_DAYS, holidays, optimizedDaysOff);
|
||||||
|
fixedDaysOff = result.fixedDaysOff;
|
||||||
|
daysOff = result.daysOff;
|
||||||
|
expect(fixedDaysOff.length).toBe(1);
|
||||||
|
expect(daysOff).toBe(11);
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
result = simulateToggleFixedDayOff(day, fixedDaysOff, daysOff, WEEKEND_DAYS, holidays, optimizedDaysOff);
|
||||||
|
fixedDaysOff = result.fixedDaysOff;
|
||||||
|
daysOff = result.daysOff;
|
||||||
|
expect(fixedDaysOff.length).toBe(0);
|
||||||
|
expect(daysOff).toBe(11); // Not decreased
|
||||||
|
|
||||||
|
// Add again
|
||||||
|
result = simulateToggleFixedDayOff(day, fixedDaysOff, daysOff, WEEKEND_DAYS, holidays, optimizedDaysOff);
|
||||||
|
expect(result.fixedDaysOff.length).toBe(1);
|
||||||
|
expect(result.daysOff).toBe(12); // Increased again
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle fixed day off on a day that becomes optimized later', () => {
|
||||||
|
const day = new Date(TEST_YEAR, 0, 15);
|
||||||
|
const fixedDaysOff: Date[] = [day];
|
||||||
|
const daysOff = 10;
|
||||||
|
const holidays: Array<{ date: Date; name: string }> = [];
|
||||||
|
// Day is now optimized
|
||||||
|
const optimizedDaysOff: Date[] = [day];
|
||||||
|
|
||||||
|
// Removing fixed day off should not decrease count since it's now optimized
|
||||||
|
const result = simulateToggleFixedDayOff(
|
||||||
|
day,
|
||||||
|
fixedDaysOff,
|
||||||
|
daysOff,
|
||||||
|
WEEKEND_DAYS,
|
||||||
|
holidays,
|
||||||
|
optimizedDaysOff
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.fixedDaysOff.length).toBe(0);
|
||||||
|
expect(result.daysOff).toBe(10); // Not decreased
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user