/** * @vitest-environment happy-dom */ import { describe, it, expect, beforeEach } from 'vitest'; import { render } from '@testing-library/react'; import React from 'react'; import { Stats } from '../../../components/parts/Stats.js'; import type { Statistics } from '../../../types.js'; import { Window } from 'happy-dom'; describe('Stats', () => { beforeEach(() => { // Setup happy-dom const window = new Window(); globalThis.window = window as any; globalThis.document = window.document as any; }); const mockStats: Statistics = { localCount: 10, remoteCount: 8, worktreeCount: 3, changesCount: 2, lastUpdated: new Date('2025-01-25T12:00:00Z'), }; it('should render all statistics', () => { const { getByText } = render(); expect(getByText(/Local:/)).toBeDefined(); expect(getByText(/10/)).toBeDefined(); expect(getByText(/Remote:/)).toBeDefined(); expect(getByText(/8/)).toBeDefined(); expect(getByText(/Worktrees:/)).toBeDefined(); expect(getByText(/3/)).toBeDefined(); expect(getByText(/Changes:/)).toBeDefined(); expect(getByText(/2/)).toBeDefined(); }); it('should render with zero counts', () => { const zeroStats: Statistics = { localCount: 0, remoteCount: 0, worktreeCount: 0, changesCount: 0, lastUpdated: new Date(), }; const { getByText, getAllByText } = render(); expect(getByText(/Local:/)).toBeDefined(); const zeros = getAllByText(/0/); expect(zeros.length).toBe(4); // All 4 counts are 0 }); it('should render in a horizontal layout', () => { const { container } = render(); // Verify component renders without error expect(container).toBeDefined(); }); it('should accept custom separator', () => { const { getAllByText } = render(); const separators = getAllByText(/\|/); expect(separators.length).toBeGreaterThan(0); }); it('should handle large numbers', () => { const largeStats: Statistics = { localCount: 999, remoteCount: 888, worktreeCount: 777, changesCount: 666, lastUpdated: new Date(), }; const { getByText } = render(); expect(getByText(/999/)).toBeDefined(); expect(getByText(/888/)).toBeDefined(); expect(getByText(/777/)).toBeDefined(); expect(getByText(/666/)).toBeDefined(); }); it('should display lastUpdated when provided', () => { const now = new Date(); const lastUpdated = new Date(now.getTime() - 5000); // 5 seconds ago const { getByText } = render(); expect(getByText(/Updated:/)).toBeDefined(); expect(getByText(/ago/)).toBeDefined(); }); it('should not display lastUpdated when null', () => { const { queryByText } = render(); expect(queryByText(/Updated:/)).toBeNull(); }); it('should not display lastUpdated when not provided', () => { const { queryByText } = render(); expect(queryByText(/Updated:/)).toBeNull(); }); it('should format relative time correctly (seconds)', () => { const now = new Date(); const lastUpdated = new Date(now.getTime() - 30000); // 30 seconds ago const { getByText } = render(); expect(getByText(/30s ago/)).toBeDefined(); }); it('should format relative time correctly (minutes)', () => { const now = new Date(); const lastUpdated = new Date(now.getTime() - 120000); // 2 minutes ago const { getByText } = render(); expect(getByText(/2m ago/)).toBeDefined(); }); it('should format relative time correctly (hours)', () => { const now = new Date(); const lastUpdated = new Date(now.getTime() - 7200000); // 2 hours ago const { getByText } = render(); expect(getByText(/2h ago/)).toBeDefined(); }); });