diff --git a/.claude/settings.local.json b/.claude/settings.local.json index faaaee7..dfb4aa0 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -45,7 +45,16 @@ "Bash(powershell.exe -Command \"echo ''List all podman containers'' | claude --print\")", "Bash(powershell.exe -Command \"echo ''List my repositories on gitea.projectium.com using gitea-projectium MCP'' | claude --print\")", "Bash(powershell.exe -Command \"echo ''List my repositories on gitea.projectium.com using gitea-projectium MCP'' | claude --print --allowedTools ''mcp__gitea-projectium__*''\")", - "Bash(powershell.exe -Command \"echo ''Fetch the homepage of https://gitea.projectium.com and summarize it'' | claude --print --allowedTools ''mcp__fetch__*''\")" + "Bash(powershell.exe -Command \"echo ''Fetch the homepage of https://gitea.projectium.com and summarize it'' | claude --print --allowedTools ''mcp__fetch__*''\")", + "Bash(dir \"C:\\\\Users\\\\games3\\\\.claude\")", + "Bash(dir:*)", + "Bash(D:nodejsnpx.cmd -y @modelcontextprotocol/server-fetch --help)", + "Bash(cmd /c \"dir /o-d C:\\\\Users\\\\games3\\\\.claude\\\\debug 2>nul | head -10\")", + "mcp__memory__read_graph", + "mcp__memory__create_entities", + "mcp__memory__search_nodes", + "mcp__memory__delete_entities", + "mcp__sequential-thinking__sequentialthinking" ] } } diff --git a/src/hooks/useFlyerItems.test.ts b/src/hooks/useFlyerItems.test.ts index d8d9851..11e243e 100644 --- a/src/hooks/useFlyerItems.test.ts +++ b/src/hooks/useFlyerItems.test.ts @@ -2,14 +2,13 @@ import { renderHook } from '@testing-library/react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { useFlyerItems } from './useFlyerItems'; -import { useApiOnMount } from './useApiOnMount'; -import * as apiClient from '../services/apiClient'; +import * as useFlyerItemsQueryModule from './queries/useFlyerItemsQuery'; import { createMockFlyer, createMockFlyerItem } from '../tests/utils/mockFactories'; -// Mock the underlying useApiOnMount hook to isolate the useFlyerItems hook's logic. -vi.mock('./useApiOnMount'); +// Mock the underlying query hook to isolate the useFlyerItems hook's logic. +vi.mock('./queries/useFlyerItemsQuery'); -const mockedUseApiOnMount = vi.mocked(useApiOnMount); +const mockedUseFlyerItemsQuery = vi.mocked(useFlyerItemsQueryModule.useFlyerItemsQuery); describe('useFlyerItems Hook', () => { const mockFlyer = createMockFlyer({ @@ -39,19 +38,16 @@ describe('useFlyerItems Hook', () => { ]; beforeEach(() => { - // Clear mock history before each test vi.clearAllMocks(); }); - it('should return initial state and not call useApiOnMount when flyer is null', () => { - // Arrange: Mock the return value of the inner hook. - mockedUseApiOnMount.mockReturnValue({ - data: null, - loading: false, + it('should return initial state when flyer is null', () => { + // Arrange: Mock the return value of the query hook. + mockedUseFlyerItemsQuery.mockReturnValue({ + data: undefined, + isLoading: false, error: null, - isRefetching: false, - reset: vi.fn(), - }); + } as ReturnType); // Act: Render the hook with a null flyer. const { result } = renderHook(() => useFlyerItems(null)); @@ -60,57 +56,41 @@ describe('useFlyerItems Hook', () => { expect(result.current.flyerItems).toEqual([]); expect(result.current.isLoading).toBe(false); expect(result.current.error).toBeNull(); - // Assert: Check that useApiOnMount was called with `enabled: false`. - expect(mockedUseApiOnMount).toHaveBeenCalledWith( - expect.any(Function), // the wrapped fetcher function - [null], // dependencies array - { enabled: false }, // options object - undefined, // flyer_id - ); + // Assert: Check that useFlyerItemsQuery was called with undefined flyerId. + expect(mockedUseFlyerItemsQuery).toHaveBeenCalledWith(undefined); }); - it('should call useApiOnMount with enabled: true when a flyer is provided', () => { - mockedUseApiOnMount.mockReturnValue({ - data: null, - loading: true, + it('should call useFlyerItemsQuery with flyerId when a flyer is provided', () => { + mockedUseFlyerItemsQuery.mockReturnValue({ + data: undefined, + isLoading: true, error: null, - isRefetching: false, - reset: vi.fn(), - }); + } as ReturnType); renderHook(() => useFlyerItems(mockFlyer)); - // Assert: Check that useApiOnMount was called with the correct parameters. - expect(mockedUseApiOnMount).toHaveBeenCalledWith( - expect.any(Function), - [mockFlyer], - { enabled: true }, - mockFlyer.flyer_id, - ); + // Assert: Check that useFlyerItemsQuery was called with the correct flyerId. + expect(mockedUseFlyerItemsQuery).toHaveBeenCalledWith(123); }); - it('should return isLoading: true when the inner hook is loading', () => { - mockedUseApiOnMount.mockReturnValue({ - data: null, - loading: true, + it('should return isLoading: true when the query is loading', () => { + mockedUseFlyerItemsQuery.mockReturnValue({ + data: undefined, + isLoading: true, error: null, - isRefetching: false, - reset: vi.fn(), - }); + } as ReturnType); const { result } = renderHook(() => useFlyerItems(mockFlyer)); expect(result.current.isLoading).toBe(true); }); - it('should return flyerItems when the inner hook provides data', () => { - mockedUseApiOnMount.mockReturnValue({ - data: { items: mockFlyerItems }, - loading: false, + it('should return flyerItems when the query provides data', () => { + mockedUseFlyerItemsQuery.mockReturnValue({ + data: mockFlyerItems, + isLoading: false, error: null, - isRefetching: false, - reset: vi.fn(), - }); + } as ReturnType); const { result } = renderHook(() => useFlyerItems(mockFlyer)); @@ -119,15 +99,13 @@ describe('useFlyerItems Hook', () => { expect(result.current.error).toBeNull(); }); - it('should return an error when the inner hook returns an error', () => { + it('should return an error when the query returns an error', () => { const mockError = new Error('Failed to fetch'); - mockedUseApiOnMount.mockReturnValue({ - data: null, - loading: false, + mockedUseFlyerItemsQuery.mockReturnValue({ + data: undefined, + isLoading: false, error: mockError, - isRefetching: false, - reset: vi.fn(), - }); + } as ReturnType); const { result } = renderHook(() => useFlyerItems(mockFlyer)); @@ -135,46 +113,4 @@ describe('useFlyerItems Hook', () => { expect(result.current.flyerItems).toEqual([]); expect(result.current.error).toEqual(mockError); }); - - describe('wrappedFetcher behavior', () => { - it('should reject if called with undefined flyerId', async () => { - // We need to trigger the hook to get access to the internal wrappedFetcher - mockedUseApiOnMount.mockReturnValue({ - data: null, - loading: false, - error: null, - isRefetching: false, - reset: vi.fn(), - }); - renderHook(() => useFlyerItems(mockFlyer)); - - // The first argument passed to useApiOnMount is the wrappedFetcher function - const wrappedFetcher = mockedUseApiOnMount.mock.calls[0][0]; - - // Verify the fetcher rejects when no ID is passed (which shouldn't happen in normal flow due to 'enabled') - await expect(wrappedFetcher(undefined)).rejects.toThrow( - 'Cannot fetch items for an undefined flyer ID.', - ); - }); - - it('should call apiClient.fetchFlyerItems when called with a valid ID', async () => { - mockedUseApiOnMount.mockReturnValue({ - data: null, - loading: false, - error: null, - isRefetching: false, - reset: vi.fn(), - }); - renderHook(() => useFlyerItems(mockFlyer)); - - const wrappedFetcher = mockedUseApiOnMount.mock.calls[0][0]; - const mockResponse = new Response(); - const mockedApiClient = vi.mocked(apiClient); - mockedApiClient.fetchFlyerItems.mockResolvedValue(mockResponse); - const response = await wrappedFetcher(123); - - expect(mockedApiClient.fetchFlyerItems).toHaveBeenCalledWith(123); - expect(response).toBe(mockResponse); - }); - }); });