@@ -501,6 +501,70 @@ describe('calculateStreak', () => {
501501 expect ( resultLeapGap . longestStreak ) . toBe ( 1 ) ;
502502 } ) ;
503503
504+ it ( 'handles leap years vs non-leap years Feb 28 to Mar 1 timeline and asserts correct current/longest streaks' , ( ) => {
505+ const buildCustomCalendar = (
506+ daysData : { date : string ; count : number } [ ]
507+ ) : ContributionCalendar => {
508+ const weeks = [ ] ;
509+ for ( let i = 0 ; i < daysData . length ; i += 7 ) {
510+ const slice = daysData . slice ( i , i + 7 ) ;
511+ weeks . push ( {
512+ contributionDays : slice . map ( ( day ) => ( {
513+ contributionCount : day . count ,
514+ date : day . date ,
515+ } ) ) ,
516+ } ) ;
517+ }
518+ return {
519+ totalContributions : daysData . reduce ( ( sum , d ) => sum + d . count , 0 ) ,
520+ weeks,
521+ } ;
522+ } ;
523+
524+ // 1. Non-Leap Year (2021): Feb 28 to Mar 1
525+ // Calendar doesn't have Feb 29.
526+ const nonLeapCalendar = buildCustomCalendar ( [
527+ { date : '2021-02-28' , count : 1 } ,
528+ { date : '2021-03-01' , count : 1 } ,
529+ ] ) ;
530+
531+ const resultNonLeap = calculateStreak ( nonLeapCalendar , 'UTC' , new Date ( '2021-03-01T12:00:00Z' ) ) ;
532+ expect ( resultNonLeap . currentStreak ) . toBe ( 2 ) ;
533+ expect ( resultNonLeap . longestStreak ) . toBe ( 2 ) ;
534+
535+ // 2. Leap Year (2020) with missed leap day (Feb 29 has 0 commits)
536+ const leapCalendarWithGap = buildCustomCalendar ( [
537+ { date : '2020-02-28' , count : 1 } ,
538+ { date : '2020-02-29' , count : 0 } ,
539+ { date : '2020-03-01' , count : 1 } ,
540+ ] ) ;
541+
542+ const resultLeapGap = calculateStreak (
543+ leapCalendarWithGap ,
544+ 'UTC' ,
545+ new Date ( '2020-03-01T12:00:00Z' )
546+ ) ;
547+ // Since Feb 29 has 0 commits, the streak of consecutive active days is broken.
548+ // However, grace period = 1 keeps current streak alive but only for the continuous active days ending today (Mar 1).
549+ expect ( resultLeapGap . currentStreak ) . toBe ( 1 ) ;
550+ expect ( resultLeapGap . longestStreak ) . toBe ( 1 ) ;
551+
552+ // 3. Leap Year (2020) with active leap day (Feb 29 has 1 commit)
553+ const leapCalendarContinuous = buildCustomCalendar ( [
554+ { date : '2020-02-28' , count : 1 } ,
555+ { date : '2020-02-29' , count : 1 } ,
556+ { date : '2020-03-01' , count : 1 } ,
557+ ] ) ;
558+
559+ const resultLeapContinuous = calculateStreak (
560+ leapCalendarContinuous ,
561+ 'UTC' ,
562+ new Date ( '2020-03-01T12:00:00Z' )
563+ ) ;
564+ expect ( resultLeapContinuous . currentStreak ) . toBe ( 3 ) ;
565+ expect ( resultLeapContinuous . longestStreak ) . toBe ( 3 ) ;
566+ } ) ;
567+
504568 it ( 'correctly calculates current and longest streaks when commits are made exclusively on Saturdays and Sundays' , ( ) => {
505569 // 2024-01-01 is a Monday.
506570 // Days in a week: Mon, Tue, Wed, Thu, Fri, Sat, Sun
0 commit comments