diff --git a/app/components/navbar.tsx b/app/components/navbar.tsx
index 5b466f9b..7af72fae 100644
--- a/app/components/navbar.tsx
+++ b/app/components/navbar.tsx
@@ -154,10 +154,10 @@ export default function Navbar() {
>
{mounted ? (
isDark ? (
-
+
) : (
{mounted ? (
isDark ? (
-
+
) : (
)
diff --git a/components/InteractiveViewer.test.tsx b/components/InteractiveViewer.test.tsx
index db2e52ac..009538cf 100644
--- a/components/InteractiveViewer.test.tsx
+++ b/components/InteractiveViewer.test.tsx
@@ -600,4 +600,4 @@ describe('InteractiveViewer', () => {
expect(glowLayer).toBeTruthy();
});
});
-});
+});
\ No newline at end of file
diff --git a/components/InteractiveViewer.tsx b/components/InteractiveViewer.tsx
index 8fb8d314..dcedb4d1 100644
--- a/components/InteractiveViewer.tsx
+++ b/components/InteractiveViewer.tsx
@@ -22,7 +22,7 @@ interface ParallaxParticle {
}
/** Builds a stable set of contribution-square particles for the parallax layer.
- * Deterministic math prevents random values from causing SSR/CSR mismatches. */
+ * Deterministic math prevents random values from causing SSR/CSR mismatches. */
function buildParticles(): ParallaxParticle[] {
const colors = ['#10b981', '#8b5cf6', '#06b6d4', '#3b82f6', '#f59e0b'];
return Array.from(
@@ -110,6 +110,7 @@ export default function InteractiveViewer({
const activeTooltipRef = useRef(null);
const startPointerPos = useRef({ x: 0, y: 0 });
const [mounted, setMounted] = useState(false);
+
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setMounted(true);
@@ -455,4 +456,4 @@ export default function InteractiveViewer({
)}
);
-}
+}
\ No newline at end of file
diff --git a/components/dashboard/ComparisonStatsCard.test.tsx b/components/dashboard/ComparisonStatsCard.test.tsx
index 6931b59b..ca527fc3 100644
--- a/components/dashboard/ComparisonStatsCard.test.tsx
+++ b/components/dashboard/ComparisonStatsCard.test.tsx
@@ -138,6 +138,11 @@ describe('ComparisonStatsCard', () => {
/>
);
+const progressSegments = container.querySelectorAll(
+ '.w-full.bg-gray-700\\/50 div, .relative div'
+ );
+
+ const allDivs = Array.from(container.querySelectorAll('div'));
const emeraldElement =
container.querySelector('[className*="emerald"]') ||
container.querySelector('.text-emerald-400');
diff --git a/components/dashboard/DashboardClient.test.tsx b/components/dashboard/DashboardClient.test.tsx
index cc9e5bf7..2489da61 100644
--- a/components/dashboard/DashboardClient.test.tsx
+++ b/components/dashboard/DashboardClient.test.tsx
@@ -178,6 +178,14 @@ const mockSecondData = {
graphData: { nodes: [], links: [] },
};
+const mockPeriod = {
+ kind: 'year' as const,
+ label: '2026',
+ from: '2026-01-01T00:00:00.000Z',
+ to: '2026-12-31T23:59:59.999Z',
+ year: '2026',
+};
+
const initialDataWithHigherStreak = {
...mockInitialData,
stats: {
@@ -194,14 +202,6 @@ const secondDataWithLowerStreak = {
},
};
-const mockPeriod = {
- kind: 'year' as const,
- label: '2026',
- from: '2026-01-01T00:00:00.000Z',
- to: '2026-12-31T23:59:59.999Z',
- year: '2026',
-};
-
describe('DashboardClient', () => {
beforeEach(() => {
vi.restoreAllMocks();
@@ -327,6 +327,7 @@ describe('DashboardClient', () => {
const generateLink = screen.getByRole('link', { name: /generate your own/i });
expect(generateLink.getAttribute('href')).toBe('/');
});
+
// =========================================================================
// ISSUE OBJECTIVE: Verify error is shown when comparing with same username
// =========================================================================
@@ -413,34 +414,35 @@ describe('DashboardClient', () => {
const tags = screen.getAllByText(/Consistency Beast/i);
expect(tags).toHaveLength(2);
});
-});
-it('shows Most Consistent badge for profile with higher peak streak in compare mode', async () => {
- const mockFetch = vi.fn().mockResolvedValue({
- ok: true,
- json: async () => secondDataWithLowerStreak,
- });
- vi.stubGlobal('fetch', mockFetch);
+ it('shows Most Consistent badge for profile with higher peak streak in compare mode', async () => {
+ const mockFetch = vi.fn().mockResolvedValue({
+ ok: true,
+ json: async () => secondDataWithLowerStreak,
+ });
- render(
-
- );
+ vi.stubGlobal('fetch', mockFetch);
- fireEvent.click(screen.getByText('Compare Profile'));
+ render(
+
+ );
- fireEvent.change(screen.getByPlaceholderText('Enter GitHub Username'), {
- target: { value: 'JhaSourav07' },
- });
+ fireEvent.click(screen.getByText('Compare Profile'));
+
+ fireEvent.change(screen.getByPlaceholderText('Enter GitHub Username'), {
+ target: { value: 'JhaSourav07' },
+ });
- fireEvent.click(screen.getByText('Compare'));
+ fireEvent.click(screen.getByText('Compare'));
- await waitFor(() => {
- expect(screen.getByText('Exit Compare Mode')).toBeDefined();
- });
+ await waitFor(() => {
+ expect(screen.getByText('Exit Compare Mode')).toBeDefined();
+ });
- expect(screen.getByText(/Most Consistent/i)).toBeDefined();
-});
+ expect(screen.getByText(/Most Consistent/i)).toBeDefined();
+ });
+});
\ No newline at end of file
diff --git a/lib/cache.test.ts b/lib/cache.test.ts
index 82953239..ae99b622 100644
--- a/lib/cache.test.ts
+++ b/lib/cache.test.ts
@@ -226,11 +226,9 @@ describe('TTLCache', () => {
const cache = new TTLCache();
cache.set('user', 'octocat', 5_000);
- // Check at 1 second (before expiry at 5 seconds)
vi.advanceTimersByTime(1_000);
expect(cache.get('user')).toBe('octocat');
- // Check at 4 seconds (still before expiry)
vi.advanceTimersByTime(3_000);
expect(cache.get('user')).toBe('octocat');
@@ -242,28 +240,24 @@ describe('TTLCache', () => {
const cache = new TTLCache();
cache.set('user', 'octocat', 5_000);
- // Advance exactly to TTL expiry time
- // At this point Date.now() === expiresAt, so > check fails and value is returned
vi.advanceTimersByTime(5_000);
expect(cache.get('user')).toBe('octocat');
cache.destroy();
});
+
it('returns correct values around the exact TTL boundary', () => {
vi.useFakeTimers();
const cache = new TTLCache();
cache.set('key', 'value', 1000);
- // 999ms -> still valid
vi.advanceTimersByTime(999);
expect(cache.get('key')).toBe('value');
- // 1000ms exact boundary -> still valid
vi.advanceTimersByTime(1);
expect(cache.get('key')).toBe('value');
- // 1001ms -> expired
vi.advanceTimersByTime(1);
expect(cache.get('key')).toBeNull();
@@ -275,7 +269,6 @@ describe('TTLCache', () => {
const cache = new TTLCache();
cache.set('user', 'octocat', 5_000);
- // Advance just past TTL expiry time
vi.advanceTimersByTime(5_001);
expect(cache.get('user')).toBeNull();
@@ -329,18 +322,11 @@ describe('TTLCache', () => {
const cache = new TTLCache();
cache.set('user', 'octocat', 5_000);
- // Advance to 3 seconds (before expiry)
vi.advanceTimersByTime(3_000);
-
- // Overwrite the key with a new 5-second TTL
cache.set('user', 'new-octocat', 5_000);
-
- // Advance another 3 seconds (total 6 seconds, but only 3 since last set)
vi.advanceTimersByTime(3_000);
- // Should still be available because TTL was reset
expect(cache.get('user')).toBe('new-octocat');
-
cache.destroy();
});
@@ -349,18 +335,11 @@ describe('TTLCache', () => {
const cache = new TTLCache();
cache.set('user', 'octocat', 5_000);
- // Advance to 3 seconds
vi.advanceTimersByTime(3_000);
-
- // Overwrite with new 2-second TTL
cache.set('user', 'new-octocat', 2_000);
-
- // Advance another 3 seconds (total 6 from start, 3 from new set)
vi.advanceTimersByTime(3_000);
- // Should be expired because new TTL (2s) has passed
expect(cache.get('user')).toBeNull();
-
cache.destroy();
});
});
@@ -515,7 +494,7 @@ describe('TTLCache', () => {
});
describe('edge cases and error handling', () => {
- // FIX: New test explicitly targeting the -5000 boundary for Issue #1398
+ // FIX: Test targeting the -5000 boundary for Issue #1398
it('throws RangeError when setting a value with -5000 TTL', () => {
const cache = new TTLCache();
expect(() => cache.set('key', 'value', -5000)).toThrow(RangeError);
@@ -529,6 +508,26 @@ describe('TTLCache', () => {
cache.set(null as unknown as string, 'value', 60_000);
}).toThrow(TypeError);
expect(cache.size()).toBe(0);
+ cache.destroy();
+ });
+
+ // FIX: New test targeting the Infinity boundary for Issue #1400
+ it('caps Infinity TTL to a realistic maximum threshold without throwing', () => {
+ vi.useFakeTimers();
+ const cache = new TTLCache();
+
+ // Should handle Infinity gracefully without throwing errors
+ expect(() => cache.set('infinity-key', 'value', Infinity)).not.toThrow();
+
+ // The item should be successfully stored and retrievable
+ expect(cache.get('infinity-key')).toBe('value');
+
+ // Advance by a large safe amount (e.g., 30 days) to ensure it stays valid
+ // or gets capped safely without overflowing internal Date math
+ vi.advanceTimersByTime(1000 * 60 * 60 * 24 * 30);
+
+ // Assert it didn't break down internally and returns a clean result (either still alive or gracefully expired)
+ expect(['value', null]).toContain(cache.get('infinity-key'));
cache.destroy();
});
@@ -598,12 +597,8 @@ describe('TTLCache', () => {
vi.useFakeTimers();
const cache = new TTLCache();
cache.set('short', 'lived', 1);
- // Immediately at creation time, should exist
expect(cache.get('short')).toBe('lived');
- // Advance 1ms
vi.advanceTimersByTime(1);
- // Now it should be expired or at boundary
- // (depends on exact timing, but get() should handle it gracefully)
const result = cache.get('short');
expect([null, 'lived']).toContain(result);
cache.destroy();
@@ -611,21 +606,17 @@ describe('TTLCache', () => {
it('does not throw when ttlMs is Number.EPSILON', () => {
const cache = new TTLCache();
-
expect(() => {
cache.set('key', 'value', Number.EPSILON);
}).not.toThrow();
-
cache.destroy();
});
it('does not throw when ttlMs is a very small positive number', () => {
const cache = new TTLCache();
-
expect(() => {
cache.set('key', 'value', 0.0001);
}).not.toThrow();
-
cache.destroy();
});
@@ -641,6 +632,7 @@ describe('TTLCache', () => {
cache.destroy();
});
+
// FIX: New test targeting the NaN boundary for Issue #1399
it('resolves NaN TTL to the default standard TTL duration', () => {
vi.useFakeTimers();
@@ -795,4 +787,4 @@ describe('DistributedCache', () => {
);
cache.destroy();
});
-});
+});
\ No newline at end of file