// src/hooks/queries/useWatchedItemsQuery.test.tsx import { renderHook, waitFor } from '@testing-library/react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { ReactNode } from 'react'; import { useWatchedItemsQuery } from './useWatchedItemsQuery'; import * as apiClient from '../../services/apiClient'; vi.mock('../../services/apiClient'); const mockedApiClient = vi.mocked(apiClient); describe('useWatchedItemsQuery', () => { let queryClient: QueryClient; const wrapper = ({ children }: { children: ReactNode }) => ( {children} ); beforeEach(() => { vi.resetAllMocks(); queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, }, }); }); it('should fetch watched items when enabled', async () => { const mockWatchedItems = [ { master_item_id: 1, name: 'Milk', category: 'Dairy' }, { master_item_id: 2, name: 'Bread', category: 'Bakery' }, ]; mockedApiClient.fetchWatchedItems.mockResolvedValue({ ok: true, json: () => Promise.resolve(mockWatchedItems), } as Response); const { result } = renderHook(() => useWatchedItemsQuery(true), { wrapper }); await waitFor(() => expect(result.current.isSuccess).toBe(true)); expect(mockedApiClient.fetchWatchedItems).toHaveBeenCalled(); expect(result.current.data).toEqual(mockWatchedItems); }); it('should not fetch watched items when disabled', async () => { const { result } = renderHook(() => useWatchedItemsQuery(false), { wrapper }); // Wait a bit to ensure the query doesn't run await new Promise((resolve) => setTimeout(resolve, 100)); expect(mockedApiClient.fetchWatchedItems).not.toHaveBeenCalled(); expect(result.current.isLoading).toBe(false); expect(result.current.isFetching).toBe(false); }); it('should handle API error with error message', async () => { mockedApiClient.fetchWatchedItems.mockResolvedValue({ ok: false, status: 401, json: () => Promise.resolve({ message: 'Unauthorized' }), } as Response); const { result } = renderHook(() => useWatchedItemsQuery(true), { wrapper }); await waitFor(() => expect(result.current.isError).toBe(true)); expect(result.current.error?.message).toBe('Unauthorized'); }); it('should handle API error without message', async () => { mockedApiClient.fetchWatchedItems.mockResolvedValue({ ok: false, status: 500, json: () => Promise.reject(new Error('Parse error')), } as Response); const { result } = renderHook(() => useWatchedItemsQuery(true), { wrapper }); await waitFor(() => expect(result.current.isError).toBe(true)); expect(result.current.error?.message).toBe('Request failed with status 500'); }); it('should use fallback message when error.message is empty', async () => { mockedApiClient.fetchWatchedItems.mockResolvedValue({ ok: false, status: 500, json: () => Promise.resolve({ message: '' }), } as Response); const { result } = renderHook(() => useWatchedItemsQuery(true), { wrapper }); await waitFor(() => expect(result.current.isError).toBe(true)); expect(result.current.error?.message).toBe('Failed to fetch watched items'); }); it('should return empty array for no watched items', async () => { mockedApiClient.fetchWatchedItems.mockResolvedValue({ ok: true, json: () => Promise.resolve([]), } as Response); const { result } = renderHook(() => useWatchedItemsQuery(true), { wrapper }); await waitFor(() => expect(result.current.isSuccess).toBe(true)); expect(result.current.data).toEqual([]); }); });