Skip to content

Commit 1e1b33d

Browse files
authored
test(calculate): verify streak calculations across leap and non-leap years (JhaSourav07#1777)
## Description Fixes JhaSourav07#1471 ## Pillar - [ ] 🎨 Pillar 1 — New Theme Design - [ ] 📐 Pillar 2 — Geometric SVG Improvement - [ ] 🕐 Pillar 3 — Timezone Logic Optimization - [x] 🛠️ Other (Bug fix, refactoring, docs, testing) ## Visual Preview N/A — Test suite addition. No user interface or SVG layout modifications were made. ## Checklist before requesting a review: - [x] I have read the `CONTRIBUTING.md` file. - [x] I have tested these changes locally (`localhost:3000/api/streak?user=YOUR_USERNAME`). - [x] I have run `npm run format` and `npm run lint` locally and resolved all errors (CI will fail otherwise). - [x] My commits follow the Conventional Commits format (e.g., `feat(themes): ...`, `fix(calculate): ...`). - [x] I have updated `README.md` if I added a new theme or URL parameter. - [x] I have starred the repo. - [x] I have made sure that i have only one commit to merge in this PR. - [x] The SVG output matches the CommitPulse "premium quality" aesthetic standard (no raw elements, smooth animations, correct fonts). - [x] (Recommended) I joined the CommitPulse Discord community for contributor discussions, mentorship, and faster PR support.
2 parents 37414fb + ea757c6 commit 1e1b33d

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

lib/calculate.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,84 @@ describe('calculateStreak', () => {
270270
expect(result.longestStreak).toBe(10);
271271
expect(result.currentStreak).toBe(5);
272272
});
273+
274+
it('correctly handles leap years and non-leap years during the Feb 28 to Mar 1 transition', () => {
275+
// Helper to construct a ContributionCalendar with explicit dates
276+
const buildCustomCalendar = (
277+
daysData: { date: string; count: number }[]
278+
): ContributionCalendar => {
279+
const weeks = [];
280+
for (let i = 0; i < daysData.length; i += 7) {
281+
const slice = daysData.slice(i, i + 7);
282+
weeks.push({
283+
contributionDays: slice.map((day) => ({
284+
contributionCount: day.count,
285+
date: day.date,
286+
})),
287+
});
288+
}
289+
return {
290+
totalContributions: daysData.reduce((sum, d) => sum + d.count, 0),
291+
weeks,
292+
};
293+
};
294+
295+
// --- Case 1: Non-Leap Year (2023) ---
296+
// In 2023, Feb has 28 days. Feb 28 is followed directly by Mar 1.
297+
const nonLeapCalendar = buildCustomCalendar([
298+
{ date: '2023-02-27', count: 1 },
299+
{ date: '2023-02-28', count: 1 },
300+
{ date: '2023-03-01', count: 1 },
301+
{ date: '2023-03-02', count: 1 },
302+
]);
303+
304+
// Evaluating on March 2, 2023:
305+
// With commits on Feb 27, Feb 28, Mar 1, and Mar 2, the streak should be continuous (4 days).
306+
const resultNonLeap = calculateStreak(nonLeapCalendar, 'UTC', new Date('2023-03-02T12:00:00Z'));
307+
expect(nonLeapCalendar.totalContributions).toBe(4);
308+
expect(resultNonLeap.currentStreak).toBe(4);
309+
expect(resultNonLeap.longestStreak).toBe(4);
310+
311+
// --- Case 2: Leap Year (2024) ---
312+
// In 2024, Feb has 29 days.
313+
// If they commit on Feb 28, Feb 29, and Mar 1: streak should be 3.
314+
const leapCalendarContinuous = buildCustomCalendar([
315+
{ date: '2024-02-27', count: 0 },
316+
{ date: '2024-02-28', count: 1 },
317+
{ date: '2024-02-29', count: 1 },
318+
{ date: '2024-03-01', count: 1 },
319+
]);
320+
321+
const resultLeapContinuous = calculateStreak(
322+
leapCalendarContinuous,
323+
'UTC',
324+
new Date('2024-03-01T12:00:00Z')
325+
);
326+
expect(resultLeapContinuous.currentStreak).toBe(3);
327+
expect(resultLeapContinuous.longestStreak).toBe(3);
328+
329+
// --- Case 3: Leap Year (2024) with a gap on Feb 29 ---
330+
// In 2024, if they commit on Feb 28 and Mar 1 but miss Feb 29:
331+
// Evaluating on Mar 1 (grace period = 1):
332+
// Today (Mar 1) has 1 commit. Yesterday (Feb 29) has 0 commits.
333+
// Since grace is 1, the streak is alive.
334+
// However, since Feb 29 is 0, the backward count stops after today (Mar 1).
335+
// So the current streak should be 1, and the longest streak should be 1.
336+
const leapCalendarWithGap = buildCustomCalendar([
337+
{ date: '2024-02-27', count: 0 },
338+
{ date: '2024-02-28', count: 1 },
339+
{ date: '2024-02-29', count: 0 }, // Gap on leap day!
340+
{ date: '2024-03-01', count: 1 },
341+
]);
342+
343+
const resultLeapGap = calculateStreak(
344+
leapCalendarWithGap,
345+
'UTC',
346+
new Date('2024-03-01T12:00:00Z')
347+
);
348+
expect(resultLeapGap.currentStreak).toBe(1);
349+
expect(resultLeapGap.longestStreak).toBe(1);
350+
});
273351
});
274352
it('handles massive single-day commit spike timeline', () => {
275353
const calendar = buildCalendar([

0 commit comments

Comments
 (0)