Files
flyer-crawler.projectium.com/src/hooks/useFlyers.test.tsx
Torben Sorensen 77454b04c2
Some checks are pending
Deploy to Test Environment / deploy-to-test (push) Has started running
Add comprehensive tests for hooks, middleware, and routes
- Implement tests for `useFlyers`, `useMasterItems`, `useModal`, `useUserData` hooks to ensure correct functionality and error handling.
- Create tests for `fileUpload.middleware` and `validation.middleware` to validate file uploads and request data.
- Add tests for `AddressForm` and `AuthView` components to verify rendering, user interactions, and API calls.
- Develop tests for `deals.routes` to check authentication and response for best prices on watched items.
2025-12-13 21:30:43 -08:00

140 lines
5.0 KiB
TypeScript

// src/hooks/useFlyers.test.tsx
import React, { ReactNode } from 'react';
import { renderHook, act } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { FlyersProvider, useFlyers } from './useFlyers';
import { useInfiniteQuery } from './useInfiniteQuery';
import type { Flyer } from '../types';
// 1. Mock the useInfiniteQuery hook, which is the dependency of our FlyersProvider.
vi.mock('./useInfiniteQuery');
// 2. Create a typed mock of the hook for type safety and autocompletion.
const mockedUseInfiniteQuery = vi.mocked(useInfiniteQuery);
// 3. A simple wrapper component that renders our provider.
// This is necessary because the useFlyers hook needs to be a child of FlyersProvider.
const wrapper = ({ children }: { children: ReactNode }) => <FlyersProvider>{children}</FlyersProvider>;
describe('useFlyers Hook and FlyersProvider', () => {
// Create mock functions that we can spy on to see if they are called.
const mockFetchNextPage = vi.fn();
const mockRefetch = vi.fn();
beforeEach(() => {
// Clear mock history before each test to ensure test isolation.
vi.clearAllMocks();
});
it('should throw an error if useFlyers is used outside of FlyersProvider', () => {
// Suppress the expected console.error for this test to keep the output clean.
const originalError = console.error;
console.error = vi.fn();
// Expecting renderHook to throw an error because there's no provider.
expect(() => renderHook(() => useFlyers())).toThrow('useFlyers must be used within a FlyersProvider');
// Restore the original console.error function.
console.error = originalError;
});
it('should return the initial loading state correctly', () => {
// Arrange: Configure the mocked hook to return a loading state.
mockedUseInfiniteQuery.mockReturnValue({
data: [],
isLoading: true,
error: null,
fetchNextPage: mockFetchNextPage,
hasNextPage: false,
refetch: mockRefetch,
isRefetching: false,
isFetchingNextPage: false,
});
// Act: Render the hook within the provider wrapper.
const { result } = renderHook(() => useFlyers(), { wrapper });
// Assert: Check that the context values match the loading state.
expect(result.current.isLoadingFlyers).toBe(true);
expect(result.current.flyers).toEqual([]);
expect(result.current.flyersError).toBeNull();
});
it('should return flyers data and hasNextPage on successful fetch', () => {
// Arrange: Mock a successful data fetch.
const mockFlyers: Flyer[] = [
{ flyer_id: 1, file_name: 'flyer1.jpg', image_url: 'url1', item_count: 5, created_at: '2024-01-01' },
];
mockedUseInfiniteQuery.mockReturnValue({
data: mockFlyers,
isLoading: false,
error: null,
fetchNextPage: mockFetchNextPage,
hasNextPage: true,
refetch: mockRefetch,
isRefetching: false,
isFetchingNextPage: false,
});
// Act
const { result } = renderHook(() => useFlyers(), { wrapper });
// Assert
expect(result.current.isLoadingFlyers).toBe(false);
expect(result.current.flyers).toEqual(mockFlyers);
expect(result.current.hasNextFlyersPage).toBe(true);
});
it('should return an error state if the fetch fails', () => {
// Arrange: Mock a failed data fetch.
const mockError = new Error('Failed to fetch');
mockedUseInfiniteQuery.mockReturnValue({
data: [],
isLoading: false,
error: mockError,
fetchNextPage: mockFetchNextPage,
hasNextPage: false,
refetch: mockRefetch,
isRefetching: false,
isFetchingNextPage: false,
});
// Act
const { result } = renderHook(() => useFlyers(), { wrapper });
// Assert
expect(result.current.isLoadingFlyers).toBe(false);
expect(result.current.flyers).toEqual([]);
expect(result.current.flyersError).toBe(mockError);
});
it('should call fetchNextFlyersPage when the context function is invoked', () => {
// Arrange
mockedUseInfiniteQuery.mockReturnValue({
data: [], isLoading: false, error: null, hasNextPage: true, isRefetching: false, isFetchingNextPage: false,
fetchNextPage: mockFetchNextPage, // Pass the mock function
refetch: mockRefetch,
});
const { result } = renderHook(() => useFlyers(), { wrapper });
// Act: Use `act` to wrap state updates.
act(() => {
result.current.fetchNextFlyersPage();
});
// Assert
expect(mockFetchNextPage).toHaveBeenCalledTimes(1);
});
it('should call refetchFlyers when the context function is invoked', () => {
// Arrange
mockedUseInfiniteQuery.mockReturnValue({ data: [], isLoading: false, error: null, hasNextPage: false, isRefetching: false, isFetchingNextPage: false, fetchNextPage: mockFetchNextPage, refetch: mockRefetch });
const { result } = renderHook(() => useFlyers(), { wrapper });
// Act
act(() => { result.current.refetchFlyers(); });
// Assert
expect(mockRefetch).toHaveBeenCalledTimes(1);
});
});