snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
autofix.ci / autofix (push) Failing after 4s
Release / Release (push) Has been skipped
GitHub Actions Security Analysis / Run zizmor (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-16 01:13:08 +05:00
commit 3a013ccdfe
3570 changed files with 490194 additions and 0 deletions

View File

@@ -0,0 +1,329 @@
import { queryKey, sleep } from '@tanstack/query-test-utils'
import { act, fireEvent } from '@testing-library/preact'
import type { VNode } from 'preact'
import { Suspense } from 'preact/compat'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
QueryCache,
QueryClient,
noop,
usePrefetchQuery,
useQueryErrorResetBoundary,
useSuspenseQuery,
} from '..'
import { ErrorBoundary } from './ErrorBoundary'
import { renderWithClient } from './utils'
describe('usePrefetchQuery', () => {
let queryCache: QueryCache
let queryClient: QueryClient
beforeEach(() => {
vi.useFakeTimers()
queryCache = new QueryCache()
queryClient = new QueryClient({ queryCache })
})
afterEach(() => {
queryClient.clear()
vi.useRealTimers()
})
it('should prefetch query if query state does not exist', async () => {
const queryOpts = {
queryKey: queryKey(),
queryFn: vi.fn(() => sleep(10).then(() => 'prefetchQuery')),
}
const componentQueryOpts = {
...queryOpts,
queryFn: () => sleep(10).then(() => 'useSuspenseQuery'),
}
function Page() {
const state = useSuspenseQuery(componentQueryOpts)
return <div>data: {String(state.data)}</div>
}
function App() {
usePrefetchQuery(queryOpts)
return (
<Suspense fallback="Loading...">
<Page />
</Suspense>
)
}
const rendered = renderWithClient(queryClient, <App />)
expect(rendered.getByText('Loading...')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('data: prefetchQuery')).toBeInTheDocument()
expect(queryOpts.queryFn).toHaveBeenCalledTimes(1)
})
it('should not prefetch query if query state exists', async () => {
const queryOpts = {
queryKey: queryKey(),
queryFn: vi.fn(() =>
sleep(10).then(() => 'The usePrefetchQuery hook is smart!'),
),
}
function Page() {
const state = useSuspenseQuery(queryOpts)
return <div>data: {String(state.data)}</div>
}
function App() {
usePrefetchQuery(queryOpts)
return (
<Suspense fallback="Loading...">
<Page />
</Suspense>
)
}
void queryClient.query(queryOpts).catch(noop)
await vi.advanceTimersByTimeAsync(10)
queryOpts.queryFn.mockClear()
const rendered = renderWithClient(queryClient, <App />)
expect(rendered.queryByText('fetching: true')).not.toBeInTheDocument()
expect(
rendered.getByText('data: The usePrefetchQuery hook is smart!'),
).toBeInTheDocument()
expect(queryOpts.queryFn).not.toHaveBeenCalled()
})
it('should let errors fall through and not refetch failed queries', async () => {
const consoleMock = vi.spyOn(console, 'error')
consoleMock.mockImplementation(() => undefined)
const queryFn = vi.fn(() => sleep(10).then(() => 'Not an error'))
const queryOpts = {
queryKey: queryKey(),
queryFn,
}
queryFn.mockImplementationOnce(() =>
sleep(10).then(() => {
throw new Error('Oops! Server error!')
}),
)
function Page() {
const state = useSuspenseQuery(queryOpts)
return <div>data: {String(state.data)}</div>
}
function App() {
usePrefetchQuery(queryOpts)
return (
<ErrorBoundary fallbackRender={() => <div>Oops!</div>}>
<Suspense fallback="Loading...">
<Page />
</Suspense>
</ErrorBoundary>
)
}
void queryClient.query(queryOpts).catch(noop)
await vi.advanceTimersByTimeAsync(10)
queryFn.mockClear()
const rendered = renderWithClient(queryClient, <App />)
expect(rendered.getByText('Oops!')).toBeInTheDocument()
expect(rendered.queryByText('data: Not an error')).not.toBeInTheDocument()
expect(queryOpts.queryFn).not.toHaveBeenCalled()
consoleMock.mockRestore()
})
it('should not create an endless loop when using inside a suspense boundary', async () => {
const queryFn = vi.fn(() => sleep(10).then(() => 'prefetchedQuery'))
const queryOpts = {
queryKey: queryKey(),
queryFn,
}
function Prefetch({ children }: { children: VNode }) {
usePrefetchQuery(queryOpts)
return <>{children}</>
}
function Page() {
const state = useSuspenseQuery(queryOpts)
return <div>data: {String(state.data)}</div>
}
function App() {
return (
<Suspense fallback={<></>}>
<Prefetch>
<Page />
</Prefetch>
</Suspense>
)
}
const rendered = renderWithClient(queryClient, <App />)
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('data: prefetchedQuery')).toBeInTheDocument()
expect(queryOpts.queryFn).toHaveBeenCalledTimes(1)
})
it('should be able to recover from errors and try fetching again', async () => {
const consoleMock = vi.spyOn(console, 'error')
consoleMock.mockImplementation(() => undefined)
const queryFn = vi.fn(() =>
sleep(10).then(() => 'This is fine :dog: :fire:'),
)
const queryOpts = {
queryKey: queryKey(),
queryFn,
}
queryFn.mockImplementationOnce(() =>
sleep(10).then(() => {
throw new Error('Oops! Server error!')
}),
)
function Page() {
const state = useSuspenseQuery(queryOpts)
return <div>data: {String(state.data)}</div>
}
function App() {
const { reset } = useQueryErrorResetBoundary()
usePrefetchQuery(queryOpts)
return (
<ErrorBoundary
onReset={reset}
fallbackRender={({ resetErrorBoundary }) => (
<div>
<div>Oops!</div>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
)}
>
<Suspense fallback="Loading...">
<Page />
</Suspense>
</ErrorBoundary>
)
}
void queryClient.query(queryOpts).catch(noop)
await vi.advanceTimersByTimeAsync(10)
queryFn.mockClear()
const rendered = renderWithClient(queryClient, <App />)
expect(rendered.getByText('Oops!')).toBeInTheDocument()
fireEvent.click(rendered.getByText('Try again'))
await vi.advanceTimersByTimeAsync(10)
expect(
rendered.getByText('data: This is fine :dog: :fire:'),
).toBeInTheDocument()
expect(queryOpts.queryFn).toHaveBeenCalledTimes(1)
consoleMock.mockRestore()
})
it('should not create a suspense waterfall if prefetch is fired', async () => {
const firstQueryOpts = {
queryKey: queryKey(),
queryFn: vi.fn(() => sleep(10).then(() => 'Prefetch is nice!')),
}
const secondQueryOpts = {
queryKey: queryKey(),
queryFn: vi.fn(() => sleep(10).then(() => 'Prefetch is really nice!!')),
}
const thirdQueryOpts = {
queryKey: queryKey(),
queryFn: vi.fn(() =>
sleep(10).then(() => 'Prefetch does not create waterfalls!!'),
),
}
const Fallback = vi.fn().mockImplementation(() => <div>Loading...</div>)
function FirstQuery({ children }: { children?: VNode }) {
const state = useSuspenseQuery(firstQueryOpts)
return (
<div>
<div>data: {String(state.data)}</div>
{children}
</div>
)
}
function SecondQuery({ children }: { children?: VNode }) {
const state = useSuspenseQuery(secondQueryOpts)
return (
<div>
<div>data: {String(state.data)}</div>
{children}
</div>
)
}
function ThirdQuery() {
const state = useSuspenseQuery(thirdQueryOpts)
return <div>data: {String(state.data)}</div>
}
function App() {
usePrefetchQuery(firstQueryOpts)
usePrefetchQuery(secondQueryOpts)
usePrefetchQuery(thirdQueryOpts)
return (
<Suspense fallback={<Fallback />}>
<FirstQuery>
<SecondQuery>
<ThirdQuery />
</SecondQuery>
</FirstQuery>
</Suspense>
)
}
const rendered = renderWithClient(queryClient, <App />)
expect(
queryClient.getQueryState(firstQueryOpts.queryKey)?.fetchStatus,
).toBe('fetching')
expect(
queryClient.getQueryState(secondQueryOpts.queryKey)?.fetchStatus,
).toBe('fetching')
expect(
queryClient.getQueryState(thirdQueryOpts.queryKey)?.fetchStatus,
).toBe('fetching')
expect(rendered.getByText('Loading...')).toBeInTheDocument()
await act(async () => {
await vi.advanceTimersByTimeAsync(10)
})
expect(rendered.getByText('data: Prefetch is nice!')).toBeInTheDocument()
expect(
rendered.getByText('data: Prefetch is really nice!!'),
).toBeInTheDocument()
expect(
rendered.getByText('data: Prefetch does not create waterfalls!!'),
).toBeInTheDocument()
expect(Fallback).toHaveBeenCalledTimes(1)
expect(firstQueryOpts.queryFn).toHaveBeenCalledTimes(1)
expect(secondQueryOpts.queryFn).toHaveBeenCalledTimes(1)
expect(thirdQueryOpts.queryFn).toHaveBeenCalledTimes(1)
})
})