From a4346bebfc6bc046f5ba53d898d3b5965a13d701 Mon Sep 17 00:00:00 2001 From: Aanya Date: Wed, 3 Jun 2026 18:35:41 +0530 Subject: [PATCH 1/3] test: add type compiler tests for tooltipUtils --- .../tooltipUtils.type-compiler.test.ts | 58 +++++++++++++++++++ package-lock.json | 1 - 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 components/dashboard/tooltipUtils.type-compiler.test.ts diff --git a/components/dashboard/tooltipUtils.type-compiler.test.ts b/components/dashboard/tooltipUtils.type-compiler.test.ts new file mode 100644 index 000000000..d46aefc2c --- /dev/null +++ b/components/dashboard/tooltipUtils.type-compiler.test.ts @@ -0,0 +1,58 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import type { ActivityData } from '@/types/dashboard'; + +describe('tooltipUtils type compiler tests', () => { + it('validates ActivityData structure correctly', () => { + const validData: ActivityData = { + date: '2024-01-01', + count: 5, + intensity: 2, + }; + + expectTypeOf(validData.date).toBeString(); + expectTypeOf(validData.count).toBeNumber(); + expectTypeOf(validData.intensity).toBeNumber(); + }); + + it('ensures ActivityData array typing works', () => { + const data: ActivityData[] = [ + { + date: '2024-01-01', + count: 1, + intensity: 1, + }, + ]; + + expectTypeOf(data).toBeArray(); + }); + + it('accepts optional compatible values safely', () => { + const data: ActivityData = { + date: '2024-01-02', + count: 0, + intensity: 0, + }; + + expectTypeOf(data.count).toEqualTypeOf(); + }); + it('rejects invalid property types during compilation', () => { + expectTypeOf().toBeObject(); + + const invalidCount: ActivityData = { + date: '2024-01-01', + // @ts-expect-error count must be number + count: 'five', + intensity: 2, + }; + }); + + it('rejects missing required properties', () => { + expectTypeOf().toBeObject(); + + // @ts-expect-error intensity is required + const invalidData: ActivityData = { + date: '2024-01-01', + count: 5, + }; + }); +}); diff --git a/package-lock.json b/package-lock.json index 0259b992d..f468167e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@resvg/resvg-js": "^2.6.2", "@tailwindcss/postcss": "^4.2.2", - "@unrs/resolver-binding-linux-x64-gnu": "*", "@vercel/analytics": "^1.6.1", "dompurify": "^3.4.7", "framer-motion": "^12.38.0", From d519228c800c31ba2932db241f5b2e8566326ef3 Mon Sep 17 00:00:00 2001 From: Aanya Date: Wed, 3 Jun 2026 20:44:34 +0530 Subject: [PATCH 2/3] test: add mock integration tests for tooltipUtils --- .../tooltipUtils.mock-integrations.test.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 components/dashboard/tooltipUtils.mock-integrations.test.ts diff --git a/components/dashboard/tooltipUtils.mock-integrations.test.ts b/components/dashboard/tooltipUtils.mock-integrations.test.ts new file mode 100644 index 000000000..44da3baa5 --- /dev/null +++ b/components/dashboard/tooltipUtils.mock-integrations.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it, vi } from 'vitest'; +import { + formatTooltipDate, + getActivityInsight, + getContributionLabel, + getLocalActiveStreak, + getStreakLabel, +} from './tooltipUtils'; + +describe('tooltipUtils mock integrations', () => { + it('mocks async contribution fetch successfully', async () => { + const mockFetch = vi.fn().mockResolvedValue({ + count: 5, + }); + + const result = await mockFetch(); + + expect(result.count).toBe(5); + expect(mockFetch).toHaveBeenCalled(); + }); + + it('uses cached tooltip label when available', () => { + const cache = new Map(); + + cache.set('label', getContributionLabel(3)); + + expect(cache.get('label')).toBe('3 contributions'); + }); + + it('formats cached tooltip dates correctly', () => { + const cacheDate = formatTooltipDate('2024-01-10'); + + expect(cacheDate).toBe('Jan 10, 2024'); + }); + + it('falls back safely during async timeout simulation', async () => { + const mockTimeout = vi.fn().mockRejectedValue(new Error('Timeout')); + + await expect(mockTimeout()).rejects.toThrow('Timeout'); + }); + + it('syncs streak cache correctly after async update', async () => { + const mockData = [ + { date: '2024-01-01', count: 1, intensity: 1 }, + { date: '2024-01-02', count: 2, intensity: 2 }, + ]; + + const mockSync = vi.fn().mockResolvedValue(mockData); + + const result = await mockSync(); + + expect(getLocalActiveStreak(result, 0)).toBe(2); + expect(getActivityInsight(2, 2)).toBe('Steady contribution day'); + expect(getStreakLabel(2)).toBe('2-day active streak'); + }); +}); From dba02b74ff7f936d3ade2ed091f0cbbf67dda316 Mon Sep 17 00:00:00 2001 From: Aanya Date: Thu, 4 Jun 2026 01:35:50 +0530 Subject: [PATCH 3/3] test(tooltipUtils): add timezone boundary coverage --- .../tooltipUtils.timezone-boundaries.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 components/dashboard/tooltipUtils.timezone-boundaries.test.ts diff --git a/components/dashboard/tooltipUtils.timezone-boundaries.test.ts b/components/dashboard/tooltipUtils.timezone-boundaries.test.ts new file mode 100644 index 000000000..84200c452 --- /dev/null +++ b/components/dashboard/tooltipUtils.timezone-boundaries.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from 'vitest'; +import { formatTooltipDate, getLocalActiveStreak, getStreakLabel } from './tooltipUtils'; + +describe('tooltipUtils timezone boundaries', () => { + it('keeps UTC date stable across timezone boundaries', () => { + expect(formatTooltipDate('2024-01-01')).toBe('Jan 1, 2024'); + }); + + it('correctly formats leap year boundary dates', () => { + expect(formatTooltipDate('2024-02-29')).toBe('Feb 29, 2024'); + }); + + it('correctly formats year-end boundary dates', () => { + expect(formatTooltipDate('2024-12-31')).toBe('Dec 31, 2024'); + }); + + it('preserves active streak across consecutive calendar days', () => { + const data: { + date: string; + count: number; + intensity: 1 | 2 | 3 | 4; + }[] = [ + { date: '2024-01-01', count: 1, intensity: 1 }, + { date: '2024-01-02', count: 2, intensity: 2 }, + { date: '2024-01-03', count: 3, intensity: 3 }, + ]; + + expect(getLocalActiveStreak(data, 1)).toBe(3); + }); + + it('returns correct streak label after boundary calculations', () => { + expect(getStreakLabel(3)).toBe('3-day active streak'); + }); +});