snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
30
packages/svelte-query/tests/createInfiniteQuery/Base.svelte
Normal file
30
packages/svelte-query/tests/createInfiniteQuery/Base.svelte
Normal file
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte'
|
||||
import { queryKey, sleep } from '@tanstack/query-test-utils'
|
||||
import { createInfiniteQuery } from '../../src/index.js'
|
||||
import { setQueryClientContext } from '../../src/context.js'
|
||||
import type { QueryClient, QueryObserverResult } from '@tanstack/query-core'
|
||||
|
||||
type Props = {
|
||||
queryClient: QueryClient
|
||||
states: { value: Array<QueryObserverResult> }
|
||||
}
|
||||
|
||||
let { queryClient, states }: Props = $props()
|
||||
|
||||
setQueryClientContext(queryClient)
|
||||
|
||||
const query = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => sleep(10).then(() => pageParam),
|
||||
getNextPageParam: (lastPage) => lastPage + 1,
|
||||
initialPageParam: 0,
|
||||
}))
|
||||
|
||||
$effect(() => {
|
||||
// @ts-expect-error
|
||||
states.value = [...untrack(() => states.value), $state.snapshot(query)]
|
||||
})
|
||||
</script>
|
||||
|
||||
<div>Status: {query.status}</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
<script lang="ts">
|
||||
import { QueryClient } from '@tanstack/query-core'
|
||||
import { createInfiniteQuery } from '../../src/index.js'
|
||||
import { setQueryClientContext } from '../../src/context.js'
|
||||
import { sleep } from '@tanstack/query-test-utils'
|
||||
|
||||
type Props = {
|
||||
queryClient: QueryClient
|
||||
}
|
||||
|
||||
let { queryClient }: Props = $props()
|
||||
|
||||
const queryKey = ['test']
|
||||
|
||||
let firstPage = $state(0)
|
||||
|
||||
setQueryClientContext(queryClient)
|
||||
|
||||
const query = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey,
|
||||
queryFn: ({ pageParam }) => sleep(10).then(() => pageParam),
|
||||
getNextPageParam: (lastPage) => lastPage + 1,
|
||||
initialPageParam: firstPage,
|
||||
}))
|
||||
</script>
|
||||
|
||||
<button
|
||||
onclick={() => {
|
||||
queryClient.setQueryData(queryKey, {
|
||||
pages: [7, 8],
|
||||
pageParams: [7, 8],
|
||||
})
|
||||
firstPage = 7
|
||||
}}
|
||||
>
|
||||
setPages
|
||||
</button>
|
||||
|
||||
<div>Data: {JSON.stringify(query.data)}</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte'
|
||||
import { createInfiniteQuery } from '../../src/index.js'
|
||||
import { setQueryClientContext } from '../../src/context.js'
|
||||
import type { QueryClient, QueryObserverResult } from '@tanstack/query-core'
|
||||
import { queryKey, sleep } from '@tanstack/query-test-utils'
|
||||
|
||||
type Props = {
|
||||
queryClient: QueryClient
|
||||
states: { value: Array<QueryObserverResult> }
|
||||
}
|
||||
|
||||
let { queryClient, states }: Props = $props()
|
||||
|
||||
setQueryClientContext(queryClient)
|
||||
|
||||
const query = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => sleep(10).then(() => pageParam),
|
||||
getNextPageParam: (lastPage) => lastPage + 1,
|
||||
initialPageParam: 0,
|
||||
initialData: { pages: [0], pageParams: [0] },
|
||||
}))
|
||||
|
||||
$effect(() => {
|
||||
// @ts-expect-error
|
||||
states.value = [...untrack(() => states.value), $state.snapshot(query)]
|
||||
})
|
||||
</script>
|
||||
|
||||
<div>Status: {query.status}</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte'
|
||||
import { createInfiniteQuery } from '../../src/index.js'
|
||||
import { setQueryClientContext } from '../../src/context.js'
|
||||
import type { QueryClient, QueryObserverResult } from '@tanstack/query-core'
|
||||
import { queryKey, sleep } from '@tanstack/query-test-utils'
|
||||
|
||||
type Props = {
|
||||
queryClient: QueryClient
|
||||
states: { value: Array<QueryObserverResult> }
|
||||
}
|
||||
|
||||
let { queryClient, states }: Props = $props()
|
||||
|
||||
setQueryClientContext(queryClient)
|
||||
|
||||
const query = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: () => sleep(10).then(() => ({ count: 1 })),
|
||||
select: (data) => ({
|
||||
pages: data.pages.map((x) => `count: ${x.count}`),
|
||||
pageParams: data.pageParams,
|
||||
}),
|
||||
getNextPageParam: () => undefined,
|
||||
initialPageParam: 0,
|
||||
}))
|
||||
|
||||
$effect(() => {
|
||||
// @ts-expect-error
|
||||
states.value = [...untrack(() => states.value), $state.snapshot(query)]
|
||||
})
|
||||
</script>
|
||||
|
||||
<div>{query.data?.pages.join(',')}</div>
|
||||
@@ -0,0 +1,174 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { fireEvent, render } from '@testing-library/svelte'
|
||||
import { QueryClient } from '@tanstack/query-core'
|
||||
import { ref } from '../utils.svelte.js'
|
||||
import Base from './Base.svelte'
|
||||
import Select from './Select.svelte'
|
||||
import ChangeClient from './ChangeClient.svelte'
|
||||
import InitialData from './InitialData.svelte'
|
||||
import type { QueryObserverResult } from '@tanstack/query-core'
|
||||
|
||||
describe('createInfiniteQuery', () => {
|
||||
let queryClient: QueryClient
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
queryClient = new QueryClient()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
queryClient.clear()
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('should return the correct states for a successful query', async () => {
|
||||
let states = ref<Array<QueryObserverResult>>([])
|
||||
|
||||
const rendered = render(Base, {
|
||||
props: {
|
||||
queryClient,
|
||||
states,
|
||||
},
|
||||
})
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(rendered.getByText('Status: success')).toBeInTheDocument()
|
||||
|
||||
expect(states.value).toHaveLength(2)
|
||||
|
||||
expect(states.value[0]).toEqual({
|
||||
data: undefined,
|
||||
dataUpdatedAt: 0,
|
||||
error: null,
|
||||
errorUpdatedAt: 0,
|
||||
failureCount: 0,
|
||||
failureReason: null,
|
||||
errorUpdateCount: 0,
|
||||
fetchNextPage: expect.any(Function),
|
||||
fetchPreviousPage: expect.any(Function),
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
isError: false,
|
||||
isFetched: false,
|
||||
isFetchedAfterMount: false,
|
||||
isFetching: true,
|
||||
isPaused: false,
|
||||
isFetchNextPageError: false,
|
||||
isFetchingNextPage: false,
|
||||
isFetchPreviousPageError: false,
|
||||
isFetchingPreviousPage: false,
|
||||
isLoading: true,
|
||||
isPending: true,
|
||||
isInitialLoading: true,
|
||||
isLoadingError: false,
|
||||
isPlaceholderData: false,
|
||||
isRefetchError: false,
|
||||
isRefetching: false,
|
||||
isStale: true,
|
||||
isSuccess: false,
|
||||
isEnabled: true,
|
||||
refetch: expect.any(Function),
|
||||
status: 'pending',
|
||||
fetchStatus: 'fetching',
|
||||
})
|
||||
|
||||
expect(states.value[1]).toEqual({
|
||||
data: { pages: [0], pageParams: [0] },
|
||||
dataUpdatedAt: expect.any(Number),
|
||||
error: null,
|
||||
errorUpdatedAt: 0,
|
||||
failureCount: 0,
|
||||
failureReason: null,
|
||||
errorUpdateCount: 0,
|
||||
fetchNextPage: expect.any(Function),
|
||||
fetchPreviousPage: expect.any(Function),
|
||||
hasNextPage: true,
|
||||
hasPreviousPage: false,
|
||||
isError: false,
|
||||
isFetched: true,
|
||||
isFetchedAfterMount: true,
|
||||
isFetching: false,
|
||||
isPaused: false,
|
||||
isFetchNextPageError: false,
|
||||
isFetchingNextPage: false,
|
||||
isFetchPreviousPageError: false,
|
||||
isFetchingPreviousPage: false,
|
||||
isLoading: false,
|
||||
isPending: false,
|
||||
isInitialLoading: false,
|
||||
isLoadingError: false,
|
||||
isPlaceholderData: false,
|
||||
isRefetchError: false,
|
||||
isRefetching: false,
|
||||
isStale: true,
|
||||
isSuccess: true,
|
||||
isEnabled: true,
|
||||
refetch: expect.any(Function),
|
||||
status: 'success',
|
||||
fetchStatus: 'idle',
|
||||
})
|
||||
})
|
||||
|
||||
it('should render with initialData and no pending state', async () => {
|
||||
let states = ref<Array<QueryObserverResult>>([])
|
||||
|
||||
const rendered = render(InitialData, {
|
||||
props: {
|
||||
queryClient,
|
||||
states,
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('Status: success')).toBeInTheDocument()
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
|
||||
expect(states.value.every((state) => state.status === 'success')).toBe(true)
|
||||
expect(states.value[0]?.data).toEqual({ pages: [0], pageParams: [0] })
|
||||
})
|
||||
|
||||
it('should be able to select a part of the data', async () => {
|
||||
let states = ref<Array<QueryObserverResult>>([])
|
||||
|
||||
const rendered = render(Select, {
|
||||
props: {
|
||||
queryClient,
|
||||
states,
|
||||
},
|
||||
})
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(rendered.getByText('count: 1')).toBeInTheDocument()
|
||||
|
||||
expect(states.value).toHaveLength(2)
|
||||
|
||||
expect(states.value[0]).toMatchObject({
|
||||
data: undefined,
|
||||
isSuccess: false,
|
||||
})
|
||||
|
||||
expect(states.value[1]).toMatchObject({
|
||||
data: { pages: ['count: 1'] },
|
||||
isSuccess: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('should be able to set new pages with the query client', async () => {
|
||||
const rendered = render(ChangeClient, {
|
||||
props: {
|
||||
queryClient,
|
||||
},
|
||||
})
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(
|
||||
rendered.getByText('Data: {"pages":[0],"pageParams":[0]}'),
|
||||
).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /setPages/i }))
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(
|
||||
rendered.getByText('Data: {"pages":[7,8],"pageParams":[7,8]}'),
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,227 @@
|
||||
import { describe, expectTypeOf, it } from 'vitest'
|
||||
import { QueryClient } from '@tanstack/query-core'
|
||||
import { queryKey } from '@tanstack/query-test-utils'
|
||||
import { createInfiniteQuery, infiniteQueryOptions } from '../../src/index.js'
|
||||
import type { InfiniteData } from '@tanstack/query-core'
|
||||
|
||||
describe('createInfiniteQuery', () => {
|
||||
describe('pageParam', () => {
|
||||
it('initialPageParam should define type of param passed to queryFunctionContext', () => {
|
||||
createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
expectTypeOf(pageParam).toEqualTypeOf<number>()
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
}))
|
||||
})
|
||||
|
||||
it('direction should be passed to queryFn of createInfiniteQuery', () => {
|
||||
createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ direction }) => {
|
||||
expectTypeOf(direction).toEqualTypeOf<'forward' | 'backward'>()
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
}))
|
||||
})
|
||||
|
||||
it('initialPageParam should define type of param passed to queryFunctionContext for fetchInfiniteQuery', () => {
|
||||
const queryClient = new QueryClient()
|
||||
// grandfathered direct test
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
queryClient.fetchInfiniteQuery({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
expectTypeOf(pageParam).toEqualTypeOf<number>()
|
||||
},
|
||||
initialPageParam: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it('initialPageParam should define type of param passed to queryFunctionContext for prefetchInfiniteQuery', () => {
|
||||
const queryClient = new QueryClient()
|
||||
// grandfathered direct test
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
queryClient.prefetchInfiniteQuery({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
expectTypeOf(pageParam).toEqualTypeOf<number>()
|
||||
},
|
||||
initialPageParam: 1,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('initialData', () => {
|
||||
it('TData should always be defined when initialData is provided', () => {
|
||||
const { data } = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return pageParam * 5
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
initialData: { pages: [5], pageParams: [1] },
|
||||
}))
|
||||
|
||||
// TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now
|
||||
expectTypeOf(data).toEqualTypeOf<InfiniteData<number, unknown>>()
|
||||
})
|
||||
|
||||
it('TData should always be defined when initialData is provided through infiniteQueryOptions', () => {
|
||||
const options = infiniteQueryOptions({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }: { pageParam: number }) => {
|
||||
return pageParam * 5
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
initialData: { pages: [5], pageParams: [1] },
|
||||
})
|
||||
const { data } = createInfiniteQuery(() => options)
|
||||
|
||||
// known issue: type of pageParams is unknown when returned from createInfiniteQuery
|
||||
expectTypeOf(data).toEqualTypeOf<InfiniteData<number, unknown>>()
|
||||
})
|
||||
|
||||
it('TData should have undefined in the union when initialData is NOT provided', () => {
|
||||
const { data } = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return pageParam * 5
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
}))
|
||||
|
||||
expectTypeOf(data).toEqualTypeOf<
|
||||
InfiniteData<number, unknown> | undefined
|
||||
>()
|
||||
})
|
||||
})
|
||||
|
||||
describe('select', () => {
|
||||
it('should still return paginated data if no select result', () => {
|
||||
const infiniteQuery = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return pageParam * 5
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
}))
|
||||
|
||||
// TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now
|
||||
expectTypeOf(infiniteQuery.data).toEqualTypeOf<
|
||||
InfiniteData<number, unknown> | undefined
|
||||
>()
|
||||
})
|
||||
|
||||
it('should be able to transform data to arbitrary result', () => {
|
||||
const infiniteQuery = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return pageParam * 5
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
select: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<InfiniteData<number, number>>()
|
||||
return 'selected' as const
|
||||
},
|
||||
}))
|
||||
|
||||
expectTypeOf(infiniteQuery.data).toEqualTypeOf<'selected' | undefined>()
|
||||
})
|
||||
})
|
||||
|
||||
describe('getNextPageParam / getPreviousPageParam', () => {
|
||||
it('should get typed params', () => {
|
||||
const infiniteQuery = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return String(pageParam)
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: (
|
||||
lastPage,
|
||||
allPages,
|
||||
lastPageParam,
|
||||
allPageParams,
|
||||
) => {
|
||||
expectTypeOf(lastPage).toEqualTypeOf<string>()
|
||||
expectTypeOf(allPages).toEqualTypeOf<Array<string>>()
|
||||
expectTypeOf(lastPageParam).toEqualTypeOf<number>()
|
||||
expectTypeOf(allPageParams).toEqualTypeOf<Array<number>>()
|
||||
return undefined
|
||||
},
|
||||
getPreviousPageParam: (
|
||||
firstPage,
|
||||
allPages,
|
||||
firstPageParam,
|
||||
allPageParams,
|
||||
) => {
|
||||
expectTypeOf(firstPage).toEqualTypeOf<string>()
|
||||
expectTypeOf(allPages).toEqualTypeOf<Array<string>>()
|
||||
expectTypeOf(firstPageParam).toEqualTypeOf<number>()
|
||||
expectTypeOf(allPageParams).toEqualTypeOf<Array<number>>()
|
||||
return undefined
|
||||
},
|
||||
}))
|
||||
|
||||
// TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now
|
||||
expectTypeOf(infiniteQuery.data).toEqualTypeOf<
|
||||
InfiniteData<string, unknown> | undefined
|
||||
>()
|
||||
})
|
||||
})
|
||||
|
||||
describe('error booleans', () => {
|
||||
it('should not be permanently `false`', () => {
|
||||
const {
|
||||
isFetchNextPageError,
|
||||
isFetchPreviousPageError,
|
||||
isLoadingError,
|
||||
isRefetchError,
|
||||
} = createInfiniteQuery(() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return pageParam * 5
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
}))
|
||||
|
||||
expectTypeOf(isFetchNextPageError).toEqualTypeOf<boolean>()
|
||||
expectTypeOf(isFetchPreviousPageError).toEqualTypeOf<boolean>()
|
||||
expectTypeOf(isLoadingError).toEqualTypeOf<boolean>()
|
||||
expectTypeOf(isRefetchError).toEqualTypeOf<boolean>()
|
||||
})
|
||||
})
|
||||
|
||||
describe('queryClient', () => {
|
||||
it('should accept queryClient as second argument', () => {
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
const infiniteQuery = createInfiniteQuery(
|
||||
() => ({
|
||||
queryKey: queryKey(),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return pageParam * 5
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: () => undefined,
|
||||
}),
|
||||
() => queryClient,
|
||||
)
|
||||
|
||||
// TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now
|
||||
expectTypeOf(infiniteQuery.data).toEqualTypeOf<
|
||||
InfiniteData<number, unknown> | undefined
|
||||
>()
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user