// @vitest-environment jsdom import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' import type { PropsWithChildren } from 'react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { CloudAlbumStatsResponse } from '~/universal/types/cloudAlbum' vi.mock('@/adapters/cloud-album', () => ({ cloudAlbumAdapter: { getStats: vi.fn() } })) vi.mock('@/queries/query-client', () => ({ rendererQueryClient: { invalidateQueries: vi.fn() } })) import { cloudAlbumAdapter } from '@/adapters/cloud-album' import { rendererQueryClient } from '@/queries/query-client' import { invalidateCloudAlbumStatsQuery, PicGoCloudAlbumStatsQueryKeys, useCloudAlbumStatsQuery } from '@/queries/picgo-cloud-album-stats' const SAMPLE_STATS: CloudAlbumStatsResponse = { total: 12, types: [ { type: 'picgo-cloud', count: 8 }, { type: 'github', count: 4 } ] } const buildWrapper = () => { const client = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0 } } }) const Wrapper = ({ children }: PropsWithChildren) => ( {children} ) return { client, Wrapper } } describe('useCloudAlbumStatsQuery', () => { beforeEach(() => { vi.clearAllMocks() }) afterEach(() => { vi.clearAllMocks() }) it('returns parsed stats when adapter resolves with success', async () => { vi.mocked(cloudAlbumAdapter.getStats).mockResolvedValue({ success: true, data: SAMPLE_STATS } as unknown as Awaited>) const { Wrapper } = buildWrapper() const { result } = renderHook(() => useCloudAlbumStatsQuery(), { wrapper: Wrapper }) await waitFor(() => { expect(result.current.isSuccess).toBe(true) }) expect(cloudAlbumAdapter.getStats).toHaveBeenCalledOnce() expect(result.current.data).toEqual(SAMPLE_STATS) }) it('surfaces error state when adapter resolves with success: false', async () => { vi.mocked(cloudAlbumAdapter.getStats).mockResolvedValue({ success: false, error: 'stats-fetch-failed' } as unknown as Awaited>) const { Wrapper } = buildWrapper() const { result } = renderHook(() => useCloudAlbumStatsQuery(), { wrapper: Wrapper }) await waitFor(() => { expect(result.current.isError).toBe(true) }) expect(result.current.error).toBeInstanceOf(Error) expect((result.current.error as Error).message).toBe('stats-fetch-failed') }) it('does not call adapter when enabled is false', async () => { const { Wrapper } = buildWrapper() const { result } = renderHook(() => useCloudAlbumStatsQuery({ enabled: false }), { wrapper: Wrapper }) // give react-query a microtask to schedule (it shouldn't) await Promise.resolve() expect(cloudAlbumAdapter.getStats).not.toHaveBeenCalled() expect(result.current.fetchStatus).toBe('idle') }) it('calls adapter when enabled is omitted (default true)', async () => { vi.mocked(cloudAlbumAdapter.getStats).mockResolvedValue({ success: true, data: SAMPLE_STATS } as unknown as Awaited>) const { Wrapper } = buildWrapper() renderHook(() => useCloudAlbumStatsQuery(), { wrapper: Wrapper }) await waitFor(() => { expect(cloudAlbumAdapter.getStats).toHaveBeenCalledOnce() }) }) }) describe('invalidateCloudAlbumStatsQuery', () => { beforeEach(() => { vi.clearAllMocks() }) it('invalidates the canonical stats query key', async () => { vi.mocked(rendererQueryClient.invalidateQueries).mockResolvedValue(undefined) await invalidateCloudAlbumStatsQuery() expect(rendererQueryClient.invalidateQueries).toHaveBeenCalledOnce() expect(rendererQueryClient.invalidateQueries).toHaveBeenCalledWith({ queryKey: PicGoCloudAlbumStatsQueryKeys.stats }) }) })