@@ -303,6 +303,36 @@ describe('Recurring Tasks', () => {
303303 expect ( nextDate . getUTCDate ( ) ) . toBe ( expectedDate . getUTCDate ( ) ) ;
304304 } ) ;
305305
306+ it ( 'should not skip months for monthly_last_day when starting from 31st' , async ( ) => {
307+ // Bug fix: Jan 31 -> should go to Feb 28, not March 31
308+ const jan31 = new Date ( Date . UTC ( 2025 , 0 , 31 , 0 , 0 , 0 , 0 ) ) ;
309+
310+ const taskData = {
311+ name : 'End of Month Task' ,
312+ recurrence_type : 'monthly_last_day' ,
313+ recurrence_interval : 1 ,
314+ due_date : jan31 . toISOString ( ) . split ( 'T' ) [ 0 ] ,
315+ } ;
316+
317+ const response = await agent . post ( '/api/task' ) . send ( taskData ) ;
318+ const task = await Task . findByPk ( response . body . id ) ;
319+
320+ // First occurrence: Jan 31 -> Feb 28
321+ const nextDate1 = calculateNextDueDate ( task , jan31 ) ;
322+ expect ( nextDate1 . getUTCMonth ( ) ) . toBe ( 1 ) ; // February
323+ expect ( nextDate1 . getUTCDate ( ) ) . toBe ( 28 ) ;
324+
325+ // Second occurrence: Feb 28 -> Mar 31
326+ const nextDate2 = calculateNextDueDate ( task , nextDate1 ) ;
327+ expect ( nextDate2 . getUTCMonth ( ) ) . toBe ( 2 ) ; // March
328+ expect ( nextDate2 . getUTCDate ( ) ) . toBe ( 31 ) ;
329+
330+ // Third occurrence: Mar 31 -> Apr 30
331+ const nextDate3 = calculateNextDueDate ( task , nextDate2 ) ;
332+ expect ( nextDate3 . getUTCMonth ( ) ) . toBe ( 3 ) ; // April
333+ expect ( nextDate3 . getUTCDate ( ) ) . toBe ( 30 ) ;
334+ } ) ;
335+
306336 it ( 'should handle monthly recurrence when day does not exist in target month' , async ( ) => {
307337 // Create a task for Jan 31
308338 const jan31 = new Date ( Date . UTC ( 2024 , 0 , 31 , 0 , 0 , 0 , 0 ) ) ;
0 commit comments