import { act, renderHook, waitFor } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' import { clearAsyncResourceCache, invalidateAsyncResource, useAsyncResource } from '@/hooks/useAsyncResource' describe('useAsyncResource', () => { it('reuses fresh cached data and supports explicit invalidation', async () => { const key = 'test:cached-resource' const load = vi.fn().mockResolvedValue({ value: 1 }) const first = renderHook(() => useAsyncResource(load, { cacheKey: key })) await waitFor(() => { expect(first.result.current.data).toEqual({ value: 1 }) }) first.unmount() const second = renderHook(() => useAsyncResource(load, { cacheKey: key })) await waitFor(() => { expect(second.result.current.isLoading).toBe(false) }) expect(load).toHaveBeenCalledTimes(1) invalidateAsyncResource(key) await act(async () => { await second.result.current.refetch() }) expect(load).toHaveBeenCalledTimes(2) }) it('clearAsyncResourceCache drops all keys so a later mount refetches', async () => { const key = 'test:clear-all' const load = vi.fn().mockResolvedValue({ value: 1 }) const first = renderHook(() => useAsyncResource(load, { cacheKey: key })) await waitFor(() => { expect(first.result.current.data).toEqual({ value: 1 }) }) first.unmount() clearAsyncResourceCache() const second = renderHook(() => useAsyncResource(load, { cacheKey: key })) await waitFor(() => { expect(second.result.current.data).toEqual({ value: 1 }) }) expect(load).toHaveBeenCalledTimes(2) }) it('aborts an in-flight request on unmount', () => { let receivedSignal: AbortSignal | undefined const load = vi.fn((signal: AbortSignal) => { receivedSignal = signal return new Promise(() => undefined) }) const hook = renderHook(() => useAsyncResource(load, { retries: 0 })) hook.unmount() expect(receivedSignal?.aborted).toBe(true) }) })