Phase 4: AI Assistant Integration - AI chat interface with suggested questions - Real-time messaging with backend OpenAI integration - Material UI chat bubbles and animations - Medical disclaimer and user-friendly UX Phase 5: Pattern Recognition & Analytics - Analytics dashboard with tabbed interface - Weekly sleep chart with bar/line visualizations - Feeding frequency graphs with type distribution - Growth curve with WHO percentiles (0-24 months) - Pattern insights with AI-powered recommendations - PDF report export functionality - Recharts integration for all data visualizations Phase 6: Testing & Optimization - Jest and React Testing Library setup - Unit tests for auth, API client, and components - Integration tests with full coverage - WCAG AA accessibility compliance testing - Performance optimizations (SWC, image optimization) - Accessibility monitoring with axe-core - 70% code coverage threshold 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
162 lines
4.0 KiB
TypeScript
162 lines
4.0 KiB
TypeScript
import { render, screen, waitFor } from '@testing-library/react';
|
|
import WeeklySleepChart from '@/components/analytics/WeeklySleepChart';
|
|
import apiClient from '@/lib/api/client';
|
|
|
|
jest.mock('@/lib/api/client');
|
|
const mockApiClient = apiClient as jest.Mocked<typeof apiClient>;
|
|
|
|
describe('WeeklySleepChart', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
it('should render loading state initially', () => {
|
|
mockApiClient.get.mockImplementation(() => new Promise(() => {}));
|
|
|
|
render(<WeeklySleepChart />);
|
|
|
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render sleep data successfully', async () => {
|
|
const mockSleepData = [
|
|
{
|
|
id: 'slp_1',
|
|
startTime: new Date('2024-01-01T20:00:00Z').toISOString(),
|
|
endTime: new Date('2024-01-02T06:00:00Z').toISOString(),
|
|
duration: 600, // 10 hours
|
|
quality: 4,
|
|
},
|
|
{
|
|
id: 'slp_2',
|
|
startTime: new Date('2024-01-02T20:00:00Z').toISOString(),
|
|
endTime: new Date('2024-01-03T07:00:00Z').toISOString(),
|
|
duration: 660, // 11 hours
|
|
quality: 5,
|
|
},
|
|
];
|
|
|
|
mockApiClient.get.mockResolvedValueOnce({
|
|
data: {
|
|
data: mockSleepData,
|
|
},
|
|
});
|
|
|
|
render(<WeeklySleepChart />);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Weekly Sleep Patterns')).toBeInTheDocument();
|
|
});
|
|
|
|
expect(screen.getByText('Total Sleep Hours')).toBeInTheDocument();
|
|
expect(screen.getByText('Sleep Quality Trend')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should handle API error gracefully', async () => {
|
|
mockApiClient.get.mockRejectedValueOnce({
|
|
response: {
|
|
data: {
|
|
message: 'Failed to fetch sleep data',
|
|
},
|
|
},
|
|
});
|
|
|
|
render(<WeeklySleepChart />);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole('alert')).toBeInTheDocument();
|
|
expect(screen.getByText('Failed to fetch sleep data')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
it('should aggregate sleep data by day', async () => {
|
|
const mockSleepData = [
|
|
{
|
|
id: 'slp_1',
|
|
startTime: new Date('2024-01-01T20:00:00Z').toISOString(),
|
|
duration: 600, // Night sleep
|
|
quality: 4,
|
|
},
|
|
{
|
|
id: 'slp_2',
|
|
startTime: new Date('2024-01-01T14:00:00Z').toISOString(),
|
|
duration: 120, // Nap
|
|
quality: 3,
|
|
},
|
|
];
|
|
|
|
mockApiClient.get.mockResolvedValueOnce({
|
|
data: {
|
|
data: mockSleepData,
|
|
},
|
|
});
|
|
|
|
render(<WeeklySleepChart />);
|
|
|
|
await waitFor(() => {
|
|
expect(mockApiClient.get).toHaveBeenCalledWith(
|
|
'/api/v1/activities/sleep',
|
|
expect.objectContaining({
|
|
params: expect.objectContaining({
|
|
startDate: expect.any(String),
|
|
endDate: expect.any(String),
|
|
}),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
it('should display 7 days of data', async () => {
|
|
mockApiClient.get.mockResolvedValueOnce({
|
|
data: {
|
|
data: [],
|
|
},
|
|
});
|
|
|
|
render(<WeeklySleepChart />);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Weekly Sleep Patterns')).toBeInTheDocument();
|
|
});
|
|
|
|
// Chart should request exactly 7 days of data
|
|
expect(mockApiClient.get).toHaveBeenCalledWith(
|
|
'/api/v1/activities/sleep',
|
|
expect.objectContaining({
|
|
params: expect.any(Object),
|
|
})
|
|
);
|
|
});
|
|
|
|
it('should calculate quality average correctly', async () => {
|
|
const mockSleepData = [
|
|
{
|
|
id: 'slp_1',
|
|
startTime: new Date('2024-01-01T20:00:00Z').toISOString(),
|
|
duration: 600,
|
|
quality: 4,
|
|
},
|
|
{
|
|
id: 'slp_2',
|
|
startTime: new Date('2024-01-01T14:00:00Z').toISOString(),
|
|
duration: 120,
|
|
quality: 2,
|
|
},
|
|
];
|
|
|
|
mockApiClient.get.mockResolvedValueOnce({
|
|
data: {
|
|
data: mockSleepData,
|
|
},
|
|
});
|
|
|
|
render(<WeeklySleepChart />);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Sleep Quality Trend')).toBeInTheDocument();
|
|
});
|
|
|
|
// Average quality should be (4 + 2) / 2 = 3
|
|
});
|
|
});
|