A try of overhauling the frontend tests, bailed after 24h+
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { useSettings } from '../../../src/hooks/useSettings';
|
||||
import { SettingsProvider } from '../../../src/hooks/SettingsProvider';
|
||||
|
||||
describe('useSettings hook', () => {
|
||||
// Mock implementation of localStorage
|
||||
const localStorageMock = (() => {
|
||||
let store: Record<string, string> = {};
|
||||
return {
|
||||
getItem: vi.fn((key: string) => store[key] || null),
|
||||
setItem: vi.fn((key: string, value: string) => {
|
||||
store[key] = value.toString();
|
||||
}),
|
||||
removeItem: vi.fn((key: string) => {
|
||||
delete store[key];
|
||||
}),
|
||||
clear: vi.fn(() => {
|
||||
store = {};
|
||||
}),
|
||||
};
|
||||
})();
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('localStorage', localStorageMock);
|
||||
vi.clearAllMocks();
|
||||
// Clear the mock store
|
||||
(localStorage as any).clear();
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<SettingsProvider>{children}</SettingsProvider>
|
||||
);
|
||||
|
||||
it('should return default settings when wrapped in SettingsProvider', () => {
|
||||
const { result } = renderHook(() => useSettings(), { wrapper });
|
||||
|
||||
expect(result.current.settings).toEqual({
|
||||
dayStart: '07:00',
|
||||
dayEnd: '20:00',
|
||||
wakeupRef: '04:00',
|
||||
bedtimeRef: '19:00',
|
||||
statsInterval: 7,
|
||||
sessionsPerPage: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error when used outside of SettingsProvider', () => {
|
||||
expect(() => renderHook(() => useSettings())).toThrow(
|
||||
'useSettings must be used within a SettingsProvider'
|
||||
);
|
||||
});
|
||||
|
||||
it('should update settings correctly via the update function', () => {
|
||||
const { result } = renderHook(() => useSettings(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current.update('dayStart', '08:30');
|
||||
});
|
||||
|
||||
expect(result.current.settings.dayStart).toBe('08:30');
|
||||
// Verify other settings remain unchanged
|
||||
expect(result.current.settings.dayEnd).toBe('20:00');
|
||||
});
|
||||
|
||||
it('should persist updated settings to localStorage', () => {
|
||||
const setItemSpy = vi.spyOn(localStorage, 'setItem');
|
||||
const { result } = renderHook(() => useSettings(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current.update('statsInterval', 14);
|
||||
});
|
||||
|
||||
expect(setItemSpy).toHaveBeenCalledWith(
|
||||
'baby-sleep-settings',
|
||||
expect.stringContaining('"statsInterval":14')
|
||||
);
|
||||
});
|
||||
|
||||
it('should initialize with settings from localStorage if available', () => {
|
||||
const storedSettings = {
|
||||
dayStart: '10:00',
|
||||
dayEnd: '22:00',
|
||||
wakeupRef: '06:00',
|
||||
bedtimeRef: '21:00',
|
||||
statsInterval: 5,
|
||||
sessionsPerPage: 20,
|
||||
};
|
||||
localStorage.setItem('baby-sleep-settings', JSON.stringify(storedSettings));
|
||||
|
||||
const { result } = renderHook(() => useSettings(), { wrapper });
|
||||
|
||||
expect(result.current.settings).toEqual(storedSettings);
|
||||
});
|
||||
|
||||
it('should fallback to default settings if localStorage contains invalid JSON', () => {
|
||||
localStorage.setItem('baby-sleep-settings', 'invalid-json');
|
||||
|
||||
const { result } = renderHook(() => useSettings(), { wrapper });
|
||||
|
||||
expect(result.current.settings).toEqual({
|
||||
dayStart: '07:00',
|
||||
dayEnd: '20:00',
|
||||
wakeupRef: '04:00',
|
||||
bedtimeRef: '19:00',
|
||||
statsInterval: 7,
|
||||
sessionsPerPage: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty localStorage by using default settings', () => {
|
||||
localStorage.clear();
|
||||
const { result } = renderHook(() => useSettings(), { wrapper });
|
||||
expect(result.current.settings).toEqual({
|
||||
dayStart: '07:00',
|
||||
dayEnd: '20:00',
|
||||
wakeupRef: '04:00',
|
||||
bedtimeRef: '19:00',
|
||||
statsInterval: 7,
|
||||
sessionsPerPage: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,312 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useSleepSession, useSessions } from '../../../src/hooks/useSleepSession';
|
||||
import * as api from '../../../src/api/client';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import type { SleepSessionRead, SessionListResponse } from '../../../src/types';
|
||||
|
||||
// Mock the API client
|
||||
vi.mock('../../../src/api/client', () => ({
|
||||
fetchActiveSession: vi.fn(),
|
||||
createSession: vi.fn(),
|
||||
endSession: vi.fn(),
|
||||
fetchSessions: vi.fn(),
|
||||
deleteSession: vi.fn(),
|
||||
updateSession: vi.fn(),
|
||||
}));
|
||||
|
||||
const createTestQueryClient = () => new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
gcTime: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QueryClientProvider client={createTestQueryClient()}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
);
|
||||
vi.mock('../../../src/api/client', () => ({
|
||||
fetchActiveSession: vi.fn(),
|
||||
createSession: vi.fn(),
|
||||
endSession: vi.fn(),
|
||||
fetchSessions: vi.fn(),
|
||||
deleteSession: vi.fn(),
|
||||
updateSession: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock React Query as requested
|
||||
vi.mock('@tanstack/react-query', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@tanstack/react-query')>();
|
||||
return {
|
||||
...actual,
|
||||
useQuery: vi.fn(),
|
||||
useMutation: vi.fn(),
|
||||
useQueryClient: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('useSleepSession and useSessions hooks', () => {
|
||||
const mockInvalidateQueries = vi.fn();
|
||||
const mockQueryClient = { invalidateQueries: mockInvalidateQueries };
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
(useQueryClient as any).mockReturnValue(mockQueryClient);
|
||||
});
|
||||
|
||||
describe('useSleepSession', () => {
|
||||
const mockSession: SleepSessionRead = {
|
||||
id: 1,
|
||||
start_time: '2026-06-10T10:00:00Z',
|
||||
end_time: null,
|
||||
notes: 'Testing session',
|
||||
created_at: '2026-06-10T10:00:00Z',
|
||||
updated_at: '2026-06-10T10:00:00Z',
|
||||
};
|
||||
|
||||
it('Test Case 6 (State): should return correct loading and session states', () => {
|
||||
(useQuery as any).mockReturnValue({
|
||||
data: mockSession,
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
});
|
||||
|
||||
(useMutation as any).mockImplementation(({ mutationFn }: { mutationFn: (args: any) => Promise<any> }) => ({
|
||||
mutateAsync: vi.fn().mockImplementation(mutationFn),
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => useSleepSession());
|
||||
|
||||
expect(result.current.activeSession).toEqual(mockSession);
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
it('Test Case 1: should successfully create a session and invalidate queries', async () => {
|
||||
(useQuery as any).mockReturnValue({ data: null, isLoading: false, isFetching: false });
|
||||
(api.createSession as any).mockResolvedValue(mockSession);
|
||||
|
||||
(useMutation as any).mockImplementation(({ mutationFn, onSuccess }: { mutationFn: (args: any) => Promise<any>, onSuccess?: () => void }) => ({
|
||||
mutateAsync: async (args: any) => {
|
||||
const res = await mutationFn(args);
|
||||
if (onSuccess) onSuccess();
|
||||
return res;
|
||||
},
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => useSleepSession());
|
||||
|
||||
await result.current.createSession({ start_time: '2026-06-10T10:00:00Z' } as any);
|
||||
|
||||
expect(api.createSession).toHaveBeenCalled();
|
||||
expect(mockInvalidateQueries).toHaveBeenCalledWith({ queryKey: ['activeSession'] });
|
||||
expect(mockInvalidateQueries).toHaveBeenCalledWith({ queryKey: ['sessions'] });
|
||||
});
|
||||
|
||||
it('Test Case 2: should successfully end a session and invalidate queries', async () => {
|
||||
(useQuery as any).mockReturnValue({ data: mockSession, isLoading: false, isFetching: false });
|
||||
(api.endSession as any).mockResolvedValue({ ...mockSession, end_time: '2026-06-10T12:00:00Z' });
|
||||
|
||||
(useMutation as any).mockImplementation(({ mutationFn, onSuccess }: { mutationFn: (args: any) => Promise<any>, onSuccess?: () => void }) => ({
|
||||
mutateAsync: async (args: any) => {
|
||||
const res = await mutationFn(args);
|
||||
if (onSuccess) onSuccess();
|
||||
return res;
|
||||
},
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => useSleepSession());
|
||||
|
||||
await result.current.endSession({ sessionId: 1, endTime: '2026-06-10T12:00:00Z' } as any);
|
||||
|
||||
expect(api.endSession).toHaveBeenCalled();
|
||||
expect(mockInvalidateQueries).toHaveBeenCalledWith({ queryKey: ['activeSession'] });
|
||||
expect(mockInvalidateQueries).toHaveBeenCalledWith({ queryKey: ['sessions'] });
|
||||
});
|
||||
|
||||
it('Test Case 5 (Error Handling): should propagate errors during session creation', async () => {
|
||||
(useQuery as any).mockReturnValue({ data: null, isLoading: false, isFetching: false });
|
||||
const error = new Error('API Error');
|
||||
(api.createSession as any).mockRejectedValue(error);
|
||||
|
||||
(useMutation as any).mockImplementation(({ mutationFn }: { mutationFn: (args: any) => Promise<any> }) => ({
|
||||
mutateAsync: async (args: any) => {
|
||||
return await mutationFn(args);
|
||||
},
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => useSleepSession());
|
||||
|
||||
await expect(result.current.createSession({ start_time: '...' } as any)).rejects.toThrow('API Error');
|
||||
});
|
||||
|
||||
it('Test Case 6 (State): should show isCreating when mutation is pending', () => {
|
||||
(useQuery as any).mockReturnValue({ data: null, isLoading: false, isFetching: false });
|
||||
(useMutation as any).mockReturnValueOnce({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: true,
|
||||
}).mockReturnValueOnce({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSleepSession());
|
||||
expect(result.current.isCreating).toBe(true);
|
||||
});
|
||||
|
||||
it('Test Case 6 (State): should show isEnding when mutation is pending', () => {
|
||||
(useQuery as any).mockReturnValue({ data: mockSession, isLoading: false, isFetching: false });
|
||||
(useMutation as any).mockReturnValueOnce({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: false,
|
||||
}).mockReturnValueOnce({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: true,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSleepSession());
|
||||
expect(result.current.isEnding).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useSessions', () => {
|
||||
const mockSessionsResponse: SessionListResponse = {
|
||||
sessions: [
|
||||
{ id: 1, start_time: '2026-06-10T10:00:00Z', end_time: null, notes: null, created_at: '...', updated_at: '...' },
|
||||
{ id: 2, start_time: '2026-06-10T10:00:00Z', end_time: null, notes: null, created_at: '...', updated_at: '...' },
|
||||
],
|
||||
total: 2,
|
||||
};
|
||||
|
||||
it('Test Case 6 (State): should return correct loading and sessions states', () => {
|
||||
(useQuery as any).mockReturnValue({
|
||||
data: mockSessionsResponse,
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
(useMutation as any).mockReturnValue({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSessions());
|
||||
|
||||
expect(result.current.sessions).toEqual(mockSessionsResponse.sessions);
|
||||
expect(result.current.total).toBe(2);
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
it('Test Case 3: should successfully delete a session and invalidate queries', async () => {
|
||||
(useQuery as any).mockReturnValue({ data: mockSessionsResponse, isLoading: false });
|
||||
(api.deleteSession as any).mockResolvedValue(undefined);
|
||||
|
||||
(useMutation as any).mockImplementation(({ mutationFn, onSuccess }: { mutationFn: (args: any) => Promise<any>, onSuccess?: () => void }) => ({
|
||||
mutateAsync: async (args: any) => {
|
||||
const res = await mutationFn(args);
|
||||
if (onSuccess) onSuccess();
|
||||
return res;
|
||||
},
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => useSessions());
|
||||
|
||||
await (result.current.deleteSession as any)(1);
|
||||
|
||||
expect(api.deleteSession).toHaveBeenCalledWith(1);
|
||||
expect(mockInvalidateQueries).toHaveBeenCalledWith({ queryKey: ['sessions'] });
|
||||
});
|
||||
|
||||
it('Test Case 4: should successfully update a session and invalidate queries', async () => {
|
||||
(useQuery as any).mockReturnValue({ data: mockSessionsResponse, isLoading: false });
|
||||
const updatePayload = { end_time: '2026-06-10T12:00:00Z' };
|
||||
(api.updateSession as any).mockResolvedValue({ id: 1, ...updatePayload } as any);
|
||||
|
||||
(useMutation as any).mockImplementation(({ mutationFn, onSuccess }: { mutationFn: (args: any) => Promise<any>, onSuccess?: () => void }) => ({
|
||||
mutateAsync: async (args: any) => {
|
||||
const res = await mutationFn(args);
|
||||
if (onSuccess) onSuccess();
|
||||
return res;
|
||||
},
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => useSessions());
|
||||
|
||||
await (result.current.updateSession as any)({ sessionId: 1, payload: updatePayload });
|
||||
|
||||
expect(api.updateSession).toHaveBeenCalledWith(1, updatePayload);
|
||||
expect(mockInvalidateQueries).toHaveBeenCalledWith({ queryKey: ['sessions'] });
|
||||
});
|
||||
|
||||
it('Test Case 5 (Error Handling): should propagate errors during session deletion', async () => {
|
||||
(useQuery as any).mockReturnValue({ data: mockSessionsResponse, isLoading: false });
|
||||
const error = new Error('Delete failed');
|
||||
(api.deleteSession as any).mockRejectedValue(error);
|
||||
|
||||
(useMutation as any).mockImplementation(({ mutationFn }: { mutationFn: (args: any) => Promise<any> }) => ({
|
||||
mutateAsync: async (args: any) => {
|
||||
return await mutationFn(args);
|
||||
},
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => useSessions());
|
||||
|
||||
await expect((result.current.deleteSession as any)(1)).rejects.toThrow('Delete failed');
|
||||
});
|
||||
|
||||
it('Test Case 6 (State): should show isDeleting when mutation is pending', () => {
|
||||
(useQuery as any).mockReturnValue({ data: mockSessionsResponse, isLoading: false });
|
||||
(useMutation as any).mockReturnValue({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: true,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSessions());
|
||||
expect(result.current.isDeleting).toBe(true);
|
||||
});
|
||||
it('Test Case 7 (Data Undefined): should return empty sessions and 0 total when data is undefined', () => {
|
||||
(useQuery as any).mockReturnValue({
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
(useMutation as any).mockReturnValue({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSessions());
|
||||
|
||||
expect(result.current.sessions).toEqual([]);
|
||||
expect(result.current.total).toBe(0);
|
||||
});
|
||||
|
||||
it('Test Case 8 (Error Handling): should handle error from fetchSessions gracefully', () => {
|
||||
(useQuery as any).mockReturnValue({
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
isError: true,
|
||||
error: new Error('Fetch failed'),
|
||||
});
|
||||
|
||||
(useMutation as any).mockReturnValue({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSessions());
|
||||
|
||||
expect(result.current.sessions).toEqual([]);
|
||||
expect(result.current.total).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,162 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { useStats, useSummary } from '../../../src/hooks/useStats';
|
||||
import * as api from '../../../src/api/client';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
|
||||
// Mock the api client
|
||||
vi.mock('../../../src/api/client', () => ({
|
||||
fetchDailySummary: vi.fn(),
|
||||
fetchTimetable: vi.fn(),
|
||||
fetchWakeSleepTimes: vi.fn(),
|
||||
fetchSummary: vi.fn(),
|
||||
}));
|
||||
|
||||
const createTestQueryClient = () => new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
gcTime: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe('useStats', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QueryClientProvider client={createTestQueryClient()}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return data and correctly transform daily stats on success', async () => {
|
||||
const mockDailySummary = {
|
||||
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 },
|
||||
],
|
||||
};
|
||||
const mockTimetable = { slots: [] };
|
||||
const mockWakeupBedtime = { days: [] };
|
||||
|
||||
vi.mocked(api.fetchDailySummary).mockResolvedValueOnce(mockDailySummary);
|
||||
vi.mocked(api.fetchTimetable).mockResolvedValueOnce(mockTimetable);
|
||||
vi.mocked(api.fetchWakeSleepTimes).mockResolvedValueOnce(mockWakeupBedtime);
|
||||
|
||||
const { result } = renderHook(() => useStats('2024-01-01', '2024-01-02'), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
||||
|
||||
// Verify raw data
|
||||
expect(result.current.dailySummary).toEqual(mockDailySummary);
|
||||
|
||||
// Verify transformation (total, day/night split in hours)
|
||||
expect(result.current.transformedDailySummary).toEqual([
|
||||
{ date: '2024-01-01', daySleep: 4, nightSleep: 4, total: 8 },
|
||||
{ date: '2024-01-02', daySleep: 5, nightSleep: 4, total: 9 },
|
||||
]);
|
||||
|
||||
expect(result.current.timetable).toEqual(mockTimetable);
|
||||
expect(result.current.wakeupBedtime).toEqual(mockWakeupBedtime);
|
||||
expect(result.current.error).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle empty data from the API', async () => {
|
||||
const mockEmptyDailySummary = { days: [] };
|
||||
const mockTimetable = { slots: [] };
|
||||
const mockWakeupBedtime = { days: [] };
|
||||
|
||||
vi.mocked(api.fetchDailySummary).mockResolvedValueOnce(mockEmptyDailySummary);
|
||||
vi.mocked(api.fetchTimetable).mockResolvedValueOnce(mockTimetable);
|
||||
vi.mocked(api.fetchWakeSleepTimes).mockResolvedValueOnce(mockWakeupBedtime);
|
||||
|
||||
const { result } = renderHook(() => useStats('2024-01-01', '2024-01-02'), { wrapper });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
||||
|
||||
expect(result.current.dailySummary).toEqual(mockEmptyDailySummary);
|
||||
expect(result.current.transformedDailySummary).toEqual([]);
|
||||
expect(result.current.error).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle error state when the API request fails', async () => {
|
||||
const error = new Error('API Failure');
|
||||
vi.mocked(api.fetchDailySummary).mockRejectedValueOnce(error);
|
||||
vi.mocked(api.fetchTimetable).mockResolvedValueOnce({ slots: [] });
|
||||
vi.mocked(api.fetchWakeSleepTimes).mockResolvedValueOnce({ days: [] });
|
||||
|
||||
const { result } = renderHook(() => useStats('2024-01-01', '2024-01-02'), { wrapper });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
||||
|
||||
expect(result.current.error).toBeDefined();
|
||||
expect(result.current.error).toEqual(error);
|
||||
});
|
||||
|
||||
it('should handle loading state transitions', async () => {
|
||||
let resolvePromise: (value: any) => void;
|
||||
const pendingPromise = new Promise((resolve) => {
|
||||
resolvePromise = resolve;
|
||||
});
|
||||
|
||||
vi.mocked(api.fetchDailySummary).mockReturnValueOnce(pendingPromise as any);
|
||||
vi.mocked(api.fetchTimetable).mockResolvedValueOnce({ slots: [] });
|
||||
vi.mocked(api.fetchWakeSleepTimes).mockResolvedValueOnce({ days: [] });
|
||||
|
||||
const { result } = renderHook(() => useStats('2024-01-01', '2024-01-02'), { wrapper });
|
||||
|
||||
// Should be loading while promise is pending
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
// Resolve the promise
|
||||
resolvePromise!({ days: [] });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
||||
});
|
||||
});
|
||||
|
||||
describe('useSummary', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QueryClientProvider client={createTestQueryClient()}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return data on success', async () => {
|
||||
const mockSummary = {
|
||||
total_sleeps: 10,
|
||||
avg_sleeps_per_day: 2,
|
||||
total_sleeps_all_time: 100,
|
||||
avg_sleeps_per_day_all_time: 2.5,
|
||||
};
|
||||
vi.mocked(api.fetchSummary).mockResolvedValueOnce(mockSummary);
|
||||
|
||||
const { result } = renderHook(() => useSummary('2024-01-01', '2024-01-02'), { wrapper });
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
||||
|
||||
expect(result.current.data).toEqual(mockSummary);
|
||||
expect(api.fetchSummary).toHaveBeenCalledWith('2024-01-01', '2024-01-02');
|
||||
});
|
||||
|
||||
it('should handle error on failure', async () => {
|
||||
const error = new Error('API Failure');
|
||||
vi.mocked(api.fetchSummary).mockRejectedValueOnce(error);
|
||||
|
||||
const { result } = renderHook(() => useSummary('2024-01-01', '2024-01-02'), { wrapper });
|
||||
|
||||
await waitFor(() => expect(result.current.isError).toBe(true));
|
||||
|
||||
expect(result.current.error).toEqual(error);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user