150 lines
4.8 KiB
TypeScript
150 lines
4.8 KiB
TypeScript
import { render, screen } from '@testing-library/react';
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import DailySummary from '../../../../src/components/stats/DailySummary';
|
|
import { useStats } from '../../../../src/hooks/useStats';
|
|
import { XAxis, Tooltip } from 'recharts';
|
|
import { formatMinutes } from '../../../../src/utils/time';
|
|
|
|
vi.mock('../../../../src/hooks/useStats', () => ({
|
|
useStats: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('recharts', async () => {
|
|
const actual = await vi.importActual<typeof import('recharts')>('recharts');
|
|
return {
|
|
...actual,
|
|
ResponsiveContainer: ({ children }: any) => <div data-testid="responsive-container">{children}</div>,
|
|
BarChart: ({ children }: any) => <div data-testid="bar-chart">{children}</div>,
|
|
XAxis: vi.fn(({ tickFormatter }) => <div data-testid="x-axis" data-tick-formatter={String(tickFormatter)} />),
|
|
YAxis: vi.fn(() => <div data-testid="y-axis" />),
|
|
CartesianGrid: vi.fn(),
|
|
Tooltip: vi.fn(({ formatter }) => <div data-testid="tooltip" />),
|
|
Bar: vi.fn(),
|
|
};
|
|
});
|
|
|
|
describe('DailySummary', () => {
|
|
const props = {
|
|
from_date: '2024-01-01',
|
|
to_date: '2024-01-02',
|
|
day_start: '07:00',
|
|
day_end: '20:00',
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('renders loading state', () => {
|
|
vi.mocked(useStats).mockReturnValue({
|
|
dailySummary: undefined,
|
|
isLoading: true,
|
|
} as any);
|
|
|
|
render(<DailySummary {...props} />);
|
|
expect(screen.getByText(/Loading summary.../i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders empty state when dailySummary.days is undefined', () => {
|
|
vi.mocked(useStats).mockReturnValue({
|
|
dailySummary: undefined,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(<DailySummary {...props} />);
|
|
expect(screen.getByText(/No data available for this period./i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders empty state when dailySummary.days is an empty array', () => {
|
|
vi.mocked(useStats).mockReturnValue({
|
|
dailySummary: { days: [] },
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(<DailySummary {...props} />);
|
|
expect(screen.getByText(/No data available for this period./i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders chart and average stats correctly with multiple days', () => {
|
|
vi.mocked(useStats).mockReturnValue({
|
|
dailySummary: {
|
|
days: [
|
|
{ date: '2024-01-01', total_minutes: 480, day_minutes: 240, night_minutes: 240 },
|
|
{ date: '2024-01-02', total_minutes: 540, day_minutes: 300, night_minutes: 240 },
|
|
],
|
|
},
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(<DailySummary {...props} />);
|
|
|
|
expect(screen.getByText(/Daily Summary/i)).toBeInTheDocument();
|
|
|
|
// Totals: (480 + 540) / 2 = 510 mins -> 8h 30m
|
|
// Day: (240 + 300) / 2 = 270 mins -> 4h 30m
|
|
// Night: (240 + 240) / 2 = 240 mins -> 4h 0m
|
|
expect(screen.getByText(/8h 30m/i)).toBeInTheDocument();
|
|
expect(screen.getByText(/4h 30m/i)).toBeInTheDocument();
|
|
expect(screen.getByText(/4h 0m/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('handles single day data correctly', () => {
|
|
vi.mocked(useStats).mockReturnValue({
|
|
dailySummary: {
|
|
days: [
|
|
{ date: '2024-01-01', total_minutes: 600, day_minutes: 300, night_minutes: 300 },
|
|
],
|
|
},
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(<DailySummary {...props} />);
|
|
|
|
expect(screen.getByText(/10h 0m/i)).toBeInTheDocument();
|
|
const avgTimes = screen.getAllByText(/5h 0m/i);
|
|
expect(avgTimes).toHaveLength(2);
|
|
});
|
|
|
|
it('uses correct formatters for XAxis and Tooltip', () => {
|
|
vi.mocked(useStats).mockReturnValue({
|
|
dailySummary: {
|
|
days: [
|
|
{ date: '2024-01-01', total_minutes: 480, day_minutes: 240, night_minutes: 240 },
|
|
],
|
|
},
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(<DailySummary {...props} />);
|
|
|
|
// Check XAxis tickFormatter
|
|
const xAxisCall = vi.mocked(XAxis).mock.calls[0][0];
|
|
expect(xAxisCall.tickFormatter).toBeDefined();
|
|
expect(xAxisCall.tickFormatter(10)).toBe('10h');
|
|
expect(xAxisCall.tickFormatter(5.5)).toBe('6h');
|
|
|
|
// Check Tooltip formatter
|
|
const tooltipCall = vi.mocked(Tooltip).mock.calls[0][0];
|
|
expect(tooltipCall.formatter).toBeDefined();
|
|
|
|
// Test Tooltip formatter with a single number (e.g., daySleep)
|
|
const [val1, name1] = tooltipCall.formatter(8, 'daySleep');
|
|
expect(val1).toBe('8h 0m');
|
|
expect(name1).toBe('Day');
|
|
|
|
const [val2, name2] = tooltipCall.formatter(7, 'nightSleep');
|
|
expect(val2).toBe('7h 0m');
|
|
expect(name2).toBe('Night');
|
|
|
|
// Test Tooltip formatter with an array
|
|
const [val3, name3] = tooltipCall.formatter([10], 'daySleep');
|
|
expect(val3).toBe('10h 0m');
|
|
expect(name3).toBe('Day');
|
|
|
|
// Test Tooltip formatter with undefined/null
|
|
const [val4, name4] = tooltipCall.formatter(undefined, 'daySleep');
|
|
expect(val4).toBe('0m');
|
|
expect(name4).toBe('Day');
|
|
});
|
|
});
|