Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
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<never>(() => undefined)
|
|
})
|
|
const hook = renderHook(() => useAsyncResource(load, { retries: 0 }))
|
|
|
|
hook.unmount()
|
|
|
|
expect(receivedSignal?.aborted).toBe(true)
|
|
})
|
|
})
|