From 342c29b337adee0ffd2eafa925656ba398519626 Mon Sep 17 00:00:00 2001 From: chosule <89799325+chosule@users.noreply.github.com> Date: Wed, 28 Jan 2026 00:46:53 +0900 Subject: [PATCH 01/10] fix: preserve infinite query behavior during SSR hydration (#8825) --- .../src/__tests__/hydration.test.tsx | 73 +++++++++++++++++++ packages/query-core/src/hydration.ts | 62 ++++++++++++---- 2 files changed, 120 insertions(+), 15 deletions(-) diff --git a/packages/query-core/src/__tests__/hydration.test.tsx b/packages/query-core/src/__tests__/hydration.test.tsx index 8bb79ec6e9b..167481b6dac 100644 --- a/packages/query-core/src/__tests__/hydration.test.tsx +++ b/packages/query-core/src/__tests__/hydration.test.tsx @@ -1385,4 +1385,77 @@ describe('dehydration and rehydration', () => { // error and test will fail await originalPromise }) + + test('should preserve queryType for infinite queries during hydration', async () => { + const queryCache = new QueryCache() + const queryClient = new QueryClient({ queryCache }) + + await vi.waitFor(() => + queryClient.prefetchInfiniteQuery({ + queryKey: ['infinite'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ + items: [`page-${pageParam}`], + nextCursor: pageParam + 1, + })), + initialPageParam: 0, + getNextPageParam: ( + lastPage: { items: Array; nextCursor: number }, + ) => lastPage.nextCursor, + }), + ) + + const dehydrated = dehydrate(queryClient) + + const infiniteQueryState = dehydrated.queries.find( + (q) => q.queryKey[0] === 'infinite', + ) + expect(infiniteQueryState?.queryType).toBe('infiniteQuery') + + const hydrationCache = new QueryCache() + const hydrationClient = new QueryClient({ queryCache: hydrationCache }) + hydrate(hydrationClient, dehydrated) + + const hydratedQuery = hydrationCache.find({ queryKey: ['infinite'] }) + expect(hydratedQuery?.state.data).toBeDefined() + expect(hydratedQuery?.state.data).toHaveProperty('pages') + expect(hydratedQuery?.state.data).toHaveProperty('pageParams') + expect((hydratedQuery?.state.data as any).pages).toHaveLength(1) + }) + + test('should attach infiniteQueryBehavior during hydration', async () => { + const queryCache = new QueryCache() + const queryClient = new QueryClient({ queryCache }) + + await vi.waitFor(() => + queryClient.prefetchInfiniteQuery({ + queryKey: ['infinite-with-behavior'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ data: `page-${pageParam}`, next: pageParam + 1 })), + initialPageParam: 0, + getNextPageParam: (lastPage: { data: string; next: number }) => + lastPage.next, + }), + ) + + const dehydrated = dehydrate(queryClient) + + const hydrationCache = new QueryCache() + const hydrationClient = new QueryClient({ queryCache: hydrationCache }) + hydrate(hydrationClient, dehydrated) + + const result = await vi.waitFor(() => + hydrationClient.fetchInfiniteQuery({ + queryKey: ['infinite-with-behavior'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ data: `page-${pageParam}`, next: pageParam + 1 })), + initialPageParam: 0, + getNextPageParam: (lastPage: { data: string; next: number }) => + lastPage.next, + }), + ) + + expect(result.pages).toHaveLength(1) + expect(result.pageParams).toHaveLength(1) + }) }) diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index c75d8ee332c..644e9a1f9dd 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -13,6 +13,7 @@ import type { import type { QueryClient } from './queryClient' import type { Query, QueryState } from './query' import type { Mutation, MutationState } from './mutation' +import { infiniteQueryBehavior } from './infiniteQueryBehavior' // TYPES type TransformerFn = (data: any) => any @@ -52,6 +53,7 @@ interface DehydratedQuery { // without it which we need to handle for backwards compatibility. // This should be changed to required in the future. dehydratedAt?: number + queryType?: 'query' | 'infiniteQuery' } export interface DehydratedState { @@ -70,6 +72,11 @@ function dehydrateMutation(mutation: Mutation): DehydratedMutation { } } +function isInfiniteQuery(query: Query): boolean { + const options = query.options as any + return 'initialPageParam' in options +} + // Most config is not dehydrated but instead meant to configure again when // consuming the de/rehydrated data, typically with useQuery on the client. // Sometimes it might make sense to prefetch data on the server and include @@ -113,6 +120,7 @@ function dehydrateQuery( }, queryKey: query.queryKey, queryHash: query.queryHash, + queryType: isInfiniteQuery(query) ? 'infiniteQuery' : 'query', ...(query.state.status === 'pending' && { promise: dehydratePromise(), }), @@ -209,7 +217,15 @@ export function hydrate( }) queries.forEach( - ({ queryKey, state, queryHash, meta, promise, dehydratedAt }) => { + ({ + queryKey, + state, + queryHash, + meta, + promise, + dehydratedAt, + queryType, + }) => { const syncData = promise ? tryResolveSync(promise) : undefined const rawData = state.data === undefined ? syncData?.data : state.data const data = rawData === undefined ? rawData : deserializeData(rawData) @@ -239,16 +255,21 @@ export function hydrate( }) } } else { + const queryOptions: any = { + ...client.getDefaultOptions().hydrate?.queries, + ...options?.defaultOptions?.queries, + queryKey, + queryHash, + meta, + } + + if (queryType === 'infiniteQuery') { + queryOptions.behavior = infiniteQueryBehavior(undefined) + } // Restore query query = queryCache.build( client, - { - ...client.getDefaultOptions().hydrate?.queries, - ...options?.defaultOptions?.queries, - queryKey, - queryHash, - meta, - }, + queryOptions, // Reset fetch status to idle to avoid // query being stuck in fetching state upon hydration { @@ -272,13 +293,24 @@ export function hydrate( // which will re-use the passed `initialPromise` // Note that we need to call these even when data was synchronously // available, as we still need to set up the retryer - query - .fetch(undefined, { - // RSC transformed promises are not thenable - initialPromise: Promise.resolve(promise).then(deserializeData), - }) - // Avoid unhandled promise rejections - .catch(noop) + + const isRejectedThenable = + promise && + typeof promise === 'object' && + 'status' in promise && + (promise as any).status === 'rejected' + + if (!isRejectedThenable) { + query + .fetch(undefined, { + // RSC transformed promises are not thenable + initialPromise: Promise.resolve(promise).then((resolvedData) => { + return deserializeData(resolvedData) + }), + }) + // Avoid unhandled promise rejections + .catch(noop) + } } }, ) From 630450d3e660303b54506fe57ee968309eab9d8d Mon Sep 17 00:00:00 2001 From: chosule <89799325+chosule@users.noreply.github.com> Date: Wed, 28 Jan 2026 01:03:20 +0900 Subject: [PATCH 02/10] chore: add changeset for #8825 --- .changeset/stupid-seals-live.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/stupid-seals-live.md diff --git a/.changeset/stupid-seals-live.md b/.changeset/stupid-seals-live.md new file mode 100644 index 00000000000..e7441349695 --- /dev/null +++ b/.changeset/stupid-seals-live.md @@ -0,0 +1,5 @@ +--- +'@tanstack/query-core': patch +--- + +fix: preserve infinite query behavior during SSR hydration (#8825) From 2c68c02a28bf8eba53e95ddaa6ecd28de3936ed9 Mon Sep 17 00:00:00 2001 From: chosule <89799325+chosule@users.noreply.github.com> Date: Fri, 30 Jan 2026 22:19:56 +0900 Subject: [PATCH 03/10] refactor: apply review feedback - Remove isRejectedThenable check - Inline behavior assignment --- packages/query-core/src/hydration.ts | 33 ++++++++++------------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 644e9a1f9dd..71f2dc143fe 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -11,7 +11,7 @@ import type { QueryOptions, } from './types' import type { QueryClient } from './queryClient' -import type { Query, QueryState } from './query' +import type { Query, QueryBehavior, QueryState } from './query' import type { Mutation, MutationState } from './mutation' import { infiniteQueryBehavior } from './infiniteQueryBehavior' @@ -261,11 +261,11 @@ export function hydrate( queryKey, queryHash, meta, + behavior: queryType === 'infiniteQuery' + ? (infiniteQueryBehavior() as QueryBehavior) + : undefined, } - if (queryType === 'infiniteQuery') { - queryOptions.behavior = infiniteQueryBehavior(undefined) - } // Restore query query = queryCache.build( client, @@ -293,24 +293,13 @@ export function hydrate( // which will re-use the passed `initialPromise` // Note that we need to call these even when data was synchronously // available, as we still need to set up the retryer - - const isRejectedThenable = - promise && - typeof promise === 'object' && - 'status' in promise && - (promise as any).status === 'rejected' - - if (!isRejectedThenable) { - query - .fetch(undefined, { - // RSC transformed promises are not thenable - initialPromise: Promise.resolve(promise).then((resolvedData) => { - return deserializeData(resolvedData) - }), - }) - // Avoid unhandled promise rejections - .catch(noop) - } + query + .fetch(undefined, { + // RSC transformed promises are not thenable + initialPromise: Promise.resolve(promise).then(deserializeData), + }) + // Avoid unhandled promise rejections + .catch(noop) } }, ) From 8ed64b547664fb62ff48888b8fede18788ba03b4 Mon Sep 17 00:00:00 2001 From: chosule <89799325+chosule@users.noreply.github.com> Date: Tue, 24 Mar 2026 21:40:22 +0900 Subject: [PATCH 04/10] refactor: remove unnecessary `any` type assertions --- packages/query-core/src/hydration.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 71f2dc143fe..0209da20225 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -73,7 +73,7 @@ function dehydrateMutation(mutation: Mutation): DehydratedMutation { } function isInfiniteQuery(query: Query): boolean { - const options = query.options as any + const options = query.options return 'initialPageParam' in options } @@ -255,14 +255,14 @@ export function hydrate( }) } } else { - const queryOptions: any = { + const queryOptions = { ...client.getDefaultOptions().hydrate?.queries, ...options?.defaultOptions?.queries, queryKey, queryHash, meta, behavior: queryType === 'infiniteQuery' - ? (infiniteQueryBehavior() as QueryBehavior) + ? (infiniteQueryBehavior() as QueryBehavior) : undefined, } From 5091434662afd05427d7fa3d12eb4482364b6ebe Mon Sep 17 00:00:00 2001 From: kimchosule Date: Tue, 14 Apr 2026 22:29:59 +0900 Subject: [PATCH 05/10] refactor: store query type in Query instead of injecting behavior - Add a type field to Query, set from the _type marker - In Query.fetch(), apply infiniteQueryBehavior automatically when type === 'infiniteQuery' - Remove direct behavior injection from infiniteQueryObserver, fetchInfiniteQuery, ensureInfiniteQueryData, and hydrate() - In hydrate(), pass the _type marker instead of behavior to fix a regression where user-provided hydrate defaultOptions.queries.behavior could be overwritten - Add regression tests for the SSR -> dehydrate -> hydrate -> refetch flow --- .../src/__tests__/hydration.test.tsx | 158 ++++++++++++++++++ .../__tests__/infiniteQueryObserver.test.tsx | 3 +- packages/query-core/src/hydration.ts | 14 +- .../query-core/src/infiniteQueryObserver.ts | 10 +- packages/query-core/src/query.ts | 15 +- packages/query-core/src/queryClient.ts | 15 +- packages/query-core/src/types.ts | 1 + 7 files changed, 182 insertions(+), 34 deletions(-) diff --git a/packages/query-core/src/__tests__/hydration.test.tsx b/packages/query-core/src/__tests__/hydration.test.tsx index 167481b6dac..a1f827fe536 100644 --- a/packages/query-core/src/__tests__/hydration.test.tsx +++ b/packages/query-core/src/__tests__/hydration.test.tsx @@ -1458,4 +1458,162 @@ describe('dehydration and rehydration', () => { expect(result.pages).toHaveLength(1) expect(result.pageParams).toHaveLength(1) }) + + test('should restore infinite query type through dehydrate and hydrate cycle', async () => { + const serverClient = new QueryClient({ queryCache: new QueryCache() }) + + await vi.waitFor(() => + serverClient.prefetchInfiniteQuery({ + queryKey: ['infinite-type-restore'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ items: [`item-${pageParam}`], next: (pageParam as number) + 1 })), + initialPageParam: 0, + getNextPageParam: (lastPage: { items: Array; next: number }) => + lastPage.next, + }), + ) + + const dehydrated = dehydrate(serverClient) + + const dehydratedQuery = dehydrated.queries.find( + (q) => q.queryKey[0] === 'infinite-type-restore', + ) + expect(dehydratedQuery?.queryType).toBe('infiniteQuery') + + const clientCache = new QueryCache() + const clientClient = new QueryClient({ queryCache: clientCache }) + hydrate(clientClient, dehydrated) + + const hydratedQuery = clientCache.find({ queryKey: ['infinite-type-restore'] }) + expect(hydratedQuery?.type).toBe('infiniteQuery') + }) + + test('should preserve pages structure when refetching infinite query after hydration', async () => { + const serverClient = new QueryClient({ queryCache: new QueryCache() }) + + await vi.waitFor(() => + serverClient.prefetchInfiniteQuery({ + queryKey: ['refetch'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ + items: [`page-${pageParam}`], + next: (pageParam as number) + 1, + })), + initialPageParam: 0, + getNextPageParam: (lastPage: { items: Array; next: number }) => + lastPage.next, + }), + ) + + const dehydrated = dehydrate(serverClient) + + const clientCache = new QueryCache() + const clientClient = new QueryClient({ queryCache: clientCache }) + hydrate(clientClient, dehydrated) + + const beforeRefetch = clientClient.getQueryData<{ + pages: Array<{ items: Array; next: number }> + pageParams: Array + }>(['refetch']) + expect(beforeRefetch?.pages).toHaveLength(1) + expect(beforeRefetch?.pageParams).toHaveLength(1) + + const result = await vi.waitFor(() => + clientClient.fetchInfiniteQuery({ + queryKey: ['refetch'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ + items: [`page-${pageParam}`], + next: (pageParam as number) + 1, + })), + initialPageParam: 0, + getNextPageParam: (lastPage: { items: Array; next: number }) => + lastPage.next, + }), + ) + + expect(result).toHaveProperty('pages') + expect(result).toHaveProperty('pageParams') + expect(Array.isArray(result.pages)).toBe(true) + expect(result.pages).toHaveLength(1) + expect(result.pages[0]).toHaveProperty('items') + }) + + test('should retain infinite query type after subsequent setOptions calls', async () => { + const serverClient = new QueryClient({ queryCache: new QueryCache() }) + + await vi.waitFor(() => + serverClient.prefetchInfiniteQuery({ + queryKey: ['infinite-setoptions-guard'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ data: `p${pageParam}`, next: (pageParam as number) + 1 })), + initialPageParam: 0, + getNextPageParam: (lastPage: { data: string; next: number }) => + lastPage.next, + }), + ) + + const dehydrated = dehydrate(serverClient) + + const clientCache = new QueryCache() + const clientClient = new QueryClient({ queryCache: clientCache }) + hydrate(clientClient, dehydrated) + + const query = clientCache.find({ queryKey: ['infinite-setoptions-guard'] })! + expect(query.type).toBe('infiniteQuery') + + query.setOptions({ queryKey: ['infinite-setoptions-guard'] }) + expect(query.type).toBe('infiniteQuery') + }) + + test('should restore all pages when refetching multi-page infinite query after hydration', async () => { + const serverClient = new QueryClient({ queryCache: new QueryCache() }) + + await vi.waitFor(() => + serverClient.prefetchInfiniteQuery({ + queryKey: ['infinite-multipage-restore'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ + items: [`item-${pageParam}`], + next: (pageParam as number) + 1, + })), + initialPageParam: 0, + pages: 2, + getNextPageParam: (lastPage: { items: Array; next: number }) => + lastPage.next, + }), + ) + + const dehydrated = dehydrate(serverClient) + + const clientCache = new QueryCache() + const clientClient = new QueryClient({ queryCache: clientCache }) + hydrate(clientClient, dehydrated) + + const beforeRefetch = clientClient.getQueryData<{ + pages: Array + pageParams: Array + }>(['infinite-multipage-restore']) + expect(beforeRefetch?.pages).toHaveLength(2) + + const result = await vi.waitFor(() => + clientClient.fetchInfiniteQuery({ + queryKey: ['infinite-multipage-restore'], + queryFn: async ({ pageParam }) => + sleep(0).then(() => ({ + items: [`item-${pageParam}`], + next: (pageParam as number) + 1, + })), + initialPageParam: 0, + pages: 2, + getNextPageParam: (lastPage: { items: Array; next: number }) => + lastPage.next, + }), + ) + + expect(result.pages).toHaveLength(2) + expect(result.pageParams).toHaveLength(2) + expect(result.pages[0]).toHaveProperty('items') + expect(result.pages[1]).toHaveProperty('items') + }) }) diff --git a/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx b/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx index 1a72d81c987..18436e9445d 100644 --- a/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx +++ b/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx @@ -235,8 +235,7 @@ describe('InfiniteQueryObserver', () => { const result = observer.getOptimisticResult(options) - expect(options.behavior).toBeDefined() - expect(options.behavior?.onFetch).toBeDefined() + expect(options._type).toBe('infiniteQuery') expect(result).toMatchObject({ data: undefined, diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 0209da20225..91d6b662aba 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -11,9 +11,8 @@ import type { QueryOptions, } from './types' import type { QueryClient } from './queryClient' -import type { Query, QueryBehavior, QueryState } from './query' +import type { Query, QueryState } from './query' import type { Mutation, MutationState } from './mutation' -import { infiniteQueryBehavior } from './infiniteQueryBehavior' // TYPES type TransformerFn = (data: any) => any @@ -72,11 +71,6 @@ function dehydrateMutation(mutation: Mutation): DehydratedMutation { } } -function isInfiniteQuery(query: Query): boolean { - const options = query.options - return 'initialPageParam' in options -} - // Most config is not dehydrated but instead meant to configure again when // consuming the de/rehydrated data, typically with useQuery on the client. // Sometimes it might make sense to prefetch data on the server and include @@ -120,7 +114,7 @@ function dehydrateQuery( }, queryKey: query.queryKey, queryHash: query.queryHash, - queryType: isInfiniteQuery(query) ? 'infiniteQuery' : 'query', + queryType: query.type, ...(query.state.status === 'pending' && { promise: dehydratePromise(), }), @@ -261,9 +255,7 @@ export function hydrate( queryKey, queryHash, meta, - behavior: queryType === 'infiniteQuery' - ? (infiniteQueryBehavior() as QueryBehavior) - : undefined, + _type: queryType === 'infiniteQuery' ? ('infiniteQuery' as const) : undefined, } // Restore query diff --git a/packages/query-core/src/infiniteQueryObserver.ts b/packages/query-core/src/infiniteQueryObserver.ts index 1499b138169..12231e55ffe 100644 --- a/packages/query-core/src/infiniteQueryObserver.ts +++ b/packages/query-core/src/infiniteQueryObserver.ts @@ -1,9 +1,5 @@ import { QueryObserver } from './queryObserver' -import { - hasNextPage, - hasPreviousPage, - infiniteQueryBehavior, -} from './infiniteQueryBehavior' +import { hasNextPage, hasPreviousPage } from './infiniteQueryBehavior' import type { Subscribable } from './subscribable' import type { DefaultError, @@ -95,7 +91,7 @@ export class InfiniteQueryObserver< ): void { super.setOptions({ ...options, - behavior: infiniteQueryBehavior(), + _type: 'infiniteQuery', }) } @@ -108,7 +104,7 @@ export class InfiniteQueryObserver< TPageParam >, ): InfiniteQueryObserverResult { - options.behavior = infiniteQueryBehavior() + options._type = 'infiniteQuery' return super.getOptimisticResult(options) as InfiniteQueryObserverResult< TData, TError diff --git a/packages/query-core/src/query.ts b/packages/query-core/src/query.ts index 7dfaa587721..ec5e6005f2c 100644 --- a/packages/query-core/src/query.ts +++ b/packages/query-core/src/query.ts @@ -10,6 +10,7 @@ import { import { notifyManager } from './notifyManager' import { CancelledError, canFetch, createRetryer } from './retryer' import { Removable } from './removable' +import { infiniteQueryBehavior } from './infiniteQueryBehavior' import type { QueryCache } from './queryCache' import type { QueryClient } from './queryClient' import type { @@ -166,6 +167,7 @@ export class Query< queryHash: string options!: QueryOptions state: QueryState + type: 'query' | 'infiniteQuery' #initialState: QueryState #revertState?: QueryState @@ -181,6 +183,7 @@ export class Query< this.#abortSignalConsumed = false this.#defaultOptions = config.defaultOptions + this.type = 'query' this.setOptions(config.options) this.observers = [] this.#client = config.client @@ -204,6 +207,10 @@ export class Query< ): void { this.options = { ...this.#defaultOptions, ...options } + if (options?._type) { + this.type = options._type + } + this.updateGcTime(this.options.gcTime) // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition @@ -510,7 +517,13 @@ export class Query< const context = createFetchContext() - this.options.behavior?.onFetch(context, this as unknown as Query) + const behavior = + this.type === 'infiniteQuery' + ? (infiniteQueryBehavior( + (this.options as { pages?: number }).pages, + ) as QueryBehavior) + : this.options.behavior + behavior?.onFetch(context, this as unknown as Query) // Store state in case the current fetch needs to be reverted this.#revertState = this.state diff --git a/packages/query-core/src/queryClient.ts b/packages/query-core/src/queryClient.ts index 80cc36668aa..b27cec045c1 100644 --- a/packages/query-core/src/queryClient.ts +++ b/packages/query-core/src/queryClient.ts @@ -12,7 +12,6 @@ import { MutationCache } from './mutationCache' import { focusManager } from './focusManager' import { onlineManager } from './onlineManager' import { notifyManager } from './notifyManager' -import { infiniteQueryBehavior } from './infiniteQueryBehavior' import type { CancelOptions, DefaultError, @@ -395,12 +394,7 @@ export class QueryClient { TPageParam >, ): Promise> { - options.behavior = infiniteQueryBehavior< - TQueryFnData, - TError, - TData, - TPageParam - >(options.pages) + options._type = 'infiniteQuery' return this.fetchQuery(options as any) } @@ -437,12 +431,7 @@ export class QueryClient { TPageParam >, ): Promise> { - options.behavior = infiniteQueryBehavior< - TQueryFnData, - TError, - TData, - TPageParam - >(options.pages) + options._type = 'infiniteQuery' return this.ensureQueryData(options as any) } diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts index 4f3f4caed20..adf38360dad 100644 --- a/packages/query-core/src/types.ts +++ b/packages/query-core/src/types.ts @@ -266,6 +266,7 @@ export interface QueryOptions< | boolean | ((oldData: unknown | undefined, newData: unknown) => unknown) _defaulted?: boolean + _type?: 'infiniteQuery' /** * Additional payload to be stored on each query. * Use this property to pass information that can be used in other places. From 53fc381cc19c282d85077d1d3d031af469e2ebe5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:36:41 +0000 Subject: [PATCH 06/10] ci: apply automated fixes --- .../src/__tests__/hydration.test.tsx | 31 ++++++++++++++----- packages/query-core/src/hydration.ts | 5 ++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/query-core/src/__tests__/hydration.test.tsx b/packages/query-core/src/__tests__/hydration.test.tsx index a1f827fe536..cc973454f5c 100644 --- a/packages/query-core/src/__tests__/hydration.test.tsx +++ b/packages/query-core/src/__tests__/hydration.test.tsx @@ -1399,9 +1399,10 @@ describe('dehydration and rehydration', () => { nextCursor: pageParam + 1, })), initialPageParam: 0, - getNextPageParam: ( - lastPage: { items: Array; nextCursor: number }, - ) => lastPage.nextCursor, + getNextPageParam: (lastPage: { + items: Array + nextCursor: number + }) => lastPage.nextCursor, }), ) @@ -1431,7 +1432,10 @@ describe('dehydration and rehydration', () => { queryClient.prefetchInfiniteQuery({ queryKey: ['infinite-with-behavior'], queryFn: async ({ pageParam }) => - sleep(0).then(() => ({ data: `page-${pageParam}`, next: pageParam + 1 })), + sleep(0).then(() => ({ + data: `page-${pageParam}`, + next: pageParam + 1, + })), initialPageParam: 0, getNextPageParam: (lastPage: { data: string; next: number }) => lastPage.next, @@ -1448,7 +1452,10 @@ describe('dehydration and rehydration', () => { hydrationClient.fetchInfiniteQuery({ queryKey: ['infinite-with-behavior'], queryFn: async ({ pageParam }) => - sleep(0).then(() => ({ data: `page-${pageParam}`, next: pageParam + 1 })), + sleep(0).then(() => ({ + data: `page-${pageParam}`, + next: pageParam + 1, + })), initialPageParam: 0, getNextPageParam: (lastPage: { data: string; next: number }) => lastPage.next, @@ -1466,7 +1473,10 @@ describe('dehydration and rehydration', () => { serverClient.prefetchInfiniteQuery({ queryKey: ['infinite-type-restore'], queryFn: async ({ pageParam }) => - sleep(0).then(() => ({ items: [`item-${pageParam}`], next: (pageParam as number) + 1 })), + sleep(0).then(() => ({ + items: [`item-${pageParam}`], + next: (pageParam as number) + 1, + })), initialPageParam: 0, getNextPageParam: (lastPage: { items: Array; next: number }) => lastPage.next, @@ -1484,7 +1494,9 @@ describe('dehydration and rehydration', () => { const clientClient = new QueryClient({ queryCache: clientCache }) hydrate(clientClient, dehydrated) - const hydratedQuery = clientCache.find({ queryKey: ['infinite-type-restore'] }) + const hydratedQuery = clientCache.find({ + queryKey: ['infinite-type-restore'], + }) expect(hydratedQuery?.type).toBe('infiniteQuery') }) @@ -1546,7 +1558,10 @@ describe('dehydration and rehydration', () => { serverClient.prefetchInfiniteQuery({ queryKey: ['infinite-setoptions-guard'], queryFn: async ({ pageParam }) => - sleep(0).then(() => ({ data: `p${pageParam}`, next: (pageParam as number) + 1 })), + sleep(0).then(() => ({ + data: `p${pageParam}`, + next: (pageParam as number) + 1, + })), initialPageParam: 0, getNextPageParam: (lastPage: { data: string; next: number }) => lastPage.next, diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 91d6b662aba..674efdc171b 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -255,7 +255,10 @@ export function hydrate( queryKey, queryHash, meta, - _type: queryType === 'infiniteQuery' ? ('infiniteQuery' as const) : undefined, + _type: + queryType === 'infiniteQuery' + ? ('infiniteQuery' as const) + : undefined, } // Restore query From d77fc5acf30f6a0449c09f7b9762aecd2169a04c Mon Sep 17 00:00:00 2001 From: TkDodo Date: Sat, 18 Apr 2026 19:01:09 +0200 Subject: [PATCH 07/10] ref: use optional type: 'infinite' everywhere --- .../src/__tests__/hydration.test.tsx | 22 ++++++------ .../__tests__/infiniteQueryObserver.test.tsx | 2 +- packages/query-core/src/hydration.ts | 35 ++++++------------- .../query-core/src/infiniteQueryObserver.ts | 8 ++--- packages/query-core/src/query.ts | 11 +++--- packages/query-core/src/queryClient.ts | 4 +-- packages/query-core/src/types.ts | 2 +- 7 files changed, 36 insertions(+), 48 deletions(-) diff --git a/packages/query-core/src/__tests__/hydration.test.tsx b/packages/query-core/src/__tests__/hydration.test.tsx index cc973454f5c..ec92f5eb44d 100644 --- a/packages/query-core/src/__tests__/hydration.test.tsx +++ b/packages/query-core/src/__tests__/hydration.test.tsx @@ -1411,7 +1411,7 @@ describe('dehydration and rehydration', () => { const infiniteQueryState = dehydrated.queries.find( (q) => q.queryKey[0] === 'infinite', ) - expect(infiniteQueryState?.queryType).toBe('infiniteQuery') + expect(infiniteQueryState?.type).toBe('infinite') const hydrationCache = new QueryCache() const hydrationClient = new QueryClient({ queryCache: hydrationCache }) @@ -1475,7 +1475,7 @@ describe('dehydration and rehydration', () => { queryFn: async ({ pageParam }) => sleep(0).then(() => ({ items: [`item-${pageParam}`], - next: (pageParam as number) + 1, + next: pageParam + 1, })), initialPageParam: 0, getNextPageParam: (lastPage: { items: Array; next: number }) => @@ -1488,7 +1488,7 @@ describe('dehydration and rehydration', () => { const dehydratedQuery = dehydrated.queries.find( (q) => q.queryKey[0] === 'infinite-type-restore', ) - expect(dehydratedQuery?.queryType).toBe('infiniteQuery') + expect(dehydratedQuery?.type).toBe('infinite') const clientCache = new QueryCache() const clientClient = new QueryClient({ queryCache: clientCache }) @@ -1497,7 +1497,7 @@ describe('dehydration and rehydration', () => { const hydratedQuery = clientCache.find({ queryKey: ['infinite-type-restore'], }) - expect(hydratedQuery?.type).toBe('infiniteQuery') + expect(hydratedQuery?.type).toBe('infinite') }) test('should preserve pages structure when refetching infinite query after hydration', async () => { @@ -1509,7 +1509,7 @@ describe('dehydration and rehydration', () => { queryFn: async ({ pageParam }) => sleep(0).then(() => ({ items: [`page-${pageParam}`], - next: (pageParam as number) + 1, + next: pageParam + 1, })), initialPageParam: 0, getNextPageParam: (lastPage: { items: Array; next: number }) => @@ -1536,7 +1536,7 @@ describe('dehydration and rehydration', () => { queryFn: async ({ pageParam }) => sleep(0).then(() => ({ items: [`page-${pageParam}`], - next: (pageParam as number) + 1, + next: pageParam + 1, })), initialPageParam: 0, getNextPageParam: (lastPage: { items: Array; next: number }) => @@ -1560,7 +1560,7 @@ describe('dehydration and rehydration', () => { queryFn: async ({ pageParam }) => sleep(0).then(() => ({ data: `p${pageParam}`, - next: (pageParam as number) + 1, + next: pageParam + 1, })), initialPageParam: 0, getNextPageParam: (lastPage: { data: string; next: number }) => @@ -1575,10 +1575,10 @@ describe('dehydration and rehydration', () => { hydrate(clientClient, dehydrated) const query = clientCache.find({ queryKey: ['infinite-setoptions-guard'] })! - expect(query.type).toBe('infiniteQuery') + expect(query.type).toBe('infinite') query.setOptions({ queryKey: ['infinite-setoptions-guard'] }) - expect(query.type).toBe('infiniteQuery') + expect(query.type).toBe('infinite') }) test('should restore all pages when refetching multi-page infinite query after hydration', async () => { @@ -1590,7 +1590,7 @@ describe('dehydration and rehydration', () => { queryFn: async ({ pageParam }) => sleep(0).then(() => ({ items: [`item-${pageParam}`], - next: (pageParam as number) + 1, + next: pageParam + 1, })), initialPageParam: 0, pages: 2, @@ -1617,7 +1617,7 @@ describe('dehydration and rehydration', () => { queryFn: async ({ pageParam }) => sleep(0).then(() => ({ items: [`item-${pageParam}`], - next: (pageParam as number) + 1, + next: pageParam + 1, })), initialPageParam: 0, pages: 2, diff --git a/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx b/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx index 18436e9445d..e26d507a259 100644 --- a/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx +++ b/packages/query-core/src/__tests__/infiniteQueryObserver.test.tsx @@ -235,7 +235,7 @@ describe('InfiniteQueryObserver', () => { const result = observer.getOptimisticResult(options) - expect(options._type).toBe('infiniteQuery') + expect(options._type).toBe('infinite') expect(result).toMatchObject({ data: undefined, diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 674efdc171b..05eea72623f 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -48,11 +48,11 @@ interface DehydratedQuery { state: QueryState promise?: Promise meta?: QueryMeta + type?: 'infinite' // This is only optional because older versions of Query might have dehydrated // without it which we need to handle for backwards compatibility. // This should be changed to required in the future. dehydratedAt?: number - queryType?: 'query' | 'infiniteQuery' } export interface DehydratedState { @@ -114,7 +114,7 @@ function dehydrateQuery( }, queryKey: query.queryKey, queryHash: query.queryHash, - queryType: query.type, + type: query.type, ...(query.state.status === 'pending' && { promise: dehydratePromise(), }), @@ -211,15 +211,7 @@ export function hydrate( }) queries.forEach( - ({ - queryKey, - state, - queryHash, - meta, - promise, - dehydratedAt, - queryType, - }) => { + ({ queryKey, state, queryHash, meta, promise, dehydratedAt, type }) => { const syncData = promise ? tryResolveSync(promise) : undefined const rawData = state.data === undefined ? syncData?.data : state.data const data = rawData === undefined ? rawData : deserializeData(rawData) @@ -249,22 +241,17 @@ export function hydrate( }) } } else { - const queryOptions = { - ...client.getDefaultOptions().hydrate?.queries, - ...options?.defaultOptions?.queries, - queryKey, - queryHash, - meta, - _type: - queryType === 'infiniteQuery' - ? ('infiniteQuery' as const) - : undefined, - } - // Restore query query = queryCache.build( client, - queryOptions, + { + ...client.getDefaultOptions().hydrate?.queries, + ...options?.defaultOptions?.queries, + queryKey, + queryHash, + meta, + _type: type, + }, // Reset fetch status to idle to avoid // query being stuck in fetching state upon hydration { diff --git a/packages/query-core/src/infiniteQueryObserver.ts b/packages/query-core/src/infiniteQueryObserver.ts index 12231e55ffe..1cdd32a8859 100644 --- a/packages/query-core/src/infiniteQueryObserver.ts +++ b/packages/query-core/src/infiniteQueryObserver.ts @@ -89,10 +89,8 @@ export class InfiniteQueryObserver< TPageParam >, ): void { - super.setOptions({ - ...options, - _type: 'infiniteQuery', - }) + options._type = 'infinite' + super.setOptions(options) } getOptimisticResult( @@ -104,7 +102,7 @@ export class InfiniteQueryObserver< TPageParam >, ): InfiniteQueryObserverResult { - options._type = 'infiniteQuery' + options._type = 'infinite' return super.getOptimisticResult(options) as InfiniteQueryObserverResult< TData, TError diff --git a/packages/query-core/src/query.ts b/packages/query-core/src/query.ts index ec5e6005f2c..95376c00fd9 100644 --- a/packages/query-core/src/query.ts +++ b/packages/query-core/src/query.ts @@ -167,7 +167,7 @@ export class Query< queryHash: string options!: QueryOptions state: QueryState - type: 'query' | 'infiniteQuery' + #type?: 'infinite' #initialState: QueryState #revertState?: QueryState @@ -183,7 +183,6 @@ export class Query< this.#abortSignalConsumed = false this.#defaultOptions = config.defaultOptions - this.type = 'query' this.setOptions(config.options) this.observers = [] this.#client = config.client @@ -198,6 +197,10 @@ export class Query< return this.options.meta } + get type() { + return this.#type + } + get promise(): Promise | undefined { return this.#retryer?.promise } @@ -208,7 +211,7 @@ export class Query< this.options = { ...this.#defaultOptions, ...options } if (options?._type) { - this.type = options._type + this.#type = options._type } this.updateGcTime(this.options.gcTime) @@ -518,7 +521,7 @@ export class Query< const context = createFetchContext() const behavior = - this.type === 'infiniteQuery' + this.#type === 'infinite' ? (infiniteQueryBehavior( (this.options as { pages?: number }).pages, ) as QueryBehavior) diff --git a/packages/query-core/src/queryClient.ts b/packages/query-core/src/queryClient.ts index b27cec045c1..f448a068f2f 100644 --- a/packages/query-core/src/queryClient.ts +++ b/packages/query-core/src/queryClient.ts @@ -394,7 +394,7 @@ export class QueryClient { TPageParam >, ): Promise> { - options._type = 'infiniteQuery' + options._type = 'infinite' return this.fetchQuery(options as any) } @@ -431,7 +431,7 @@ export class QueryClient { TPageParam >, ): Promise> { - options._type = 'infiniteQuery' + options._type = 'infinite' return this.ensureQueryData(options as any) } diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts index adf38360dad..140f6bf6325 100644 --- a/packages/query-core/src/types.ts +++ b/packages/query-core/src/types.ts @@ -266,7 +266,7 @@ export interface QueryOptions< | boolean | ((oldData: unknown | undefined, newData: unknown) => unknown) _defaulted?: boolean - _type?: 'infiniteQuery' + _type?: 'infinite' /** * Additional payload to be stored on each query. * Use this property to pass information that can be used in other places. From f8270cfc417c2708d434fa9e592366090e406df7 Mon Sep 17 00:00:00 2001 From: TkDodo Date: Sat, 18 Apr 2026 19:10:40 +0200 Subject: [PATCH 08/10] fix: don't send full queries into queryClient methods --- packages/query-devtools/src/Devtools.tsx | 19 +++++++++++++++---- packages/vue-query/src/devtools/devtools.ts | 5 ++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/query-devtools/src/Devtools.tsx b/packages/query-devtools/src/Devtools.tsx index ed8eed4534e..62b531a8ff3 100644 --- a/packages/query-devtools/src/Devtools.tsx +++ b/packages/query-devtools/src/Devtools.tsx @@ -2098,7 +2098,10 @@ const QueryDetails = () => { type: 'INVALIDATE', queryHash: activeQuery()?.queryHash, }) - queryClient.invalidateQueries(activeQuery()) + queryClient.invalidateQueries({ + queryKey: activeQuery()?.queryKey, + exact: true, + }) }} disabled={queryStatus() === 'pending'} > @@ -2123,7 +2126,10 @@ const QueryDetails = () => { type: 'RESET', queryHash: activeQuery()?.queryHash, }) - queryClient.resetQueries(activeQuery()) + queryClient.resetQueries({ + queryKey: activeQuery()?.queryKey, + exact: true, + }) }} disabled={queryStatus() === 'pending'} > @@ -2148,7 +2154,10 @@ const QueryDetails = () => { type: 'REMOVE', queryHash: activeQuery()?.queryHash, }) - queryClient.removeQueries(activeQuery()) + queryClient.removeQueries({ + queryKey: activeQuery()?.queryKey, + exact: true, + }) setSelectedQueryHash(null) }} disabled={statusLabel() === 'fetching'} @@ -2228,7 +2237,9 @@ const QueryDetails = () => { type: 'RESTORE_ERROR', queryHash: activeQuery()?.queryHash, }) - queryClient.resetQueries(activeQuery()) + queryClient.resetQueries({ + queryKey: activeQuery()?.queryKey, + }) } }} disabled={queryStatus() === 'pending'} diff --git a/packages/vue-query/src/devtools/devtools.ts b/packages/vue-query/src/devtools/devtools.ts index beff5658414..42dfc05d734 100644 --- a/packages/vue-query/src/devtools/devtools.ts +++ b/packages/vue-query/src/devtools/devtools.ts @@ -90,7 +90,10 @@ export function setupDevtools(app: any, queryClient: QueryClient) { tooltip: 'Invalidate', action: (queryHash: string) => { const query = queryCache.get(queryHash) as Query - queryClient.invalidateQueries(query) + queryClient.invalidateQueries({ + queryKey: query.queryKey, + exact: true, + }) }, }, { From e197f3304da856b74d63e9f9f16e753d29098793 Mon Sep 17 00:00:00 2001 From: TkDodo Date: Sat, 18 Apr 2026 19:22:06 +0200 Subject: [PATCH 09/10] fix: let's stick with queryType as the public name --- .../query-core/src/__tests__/hydration.test.tsx | 10 +++++----- packages/query-core/src/hydration.ts | 16 ++++++++++++---- packages/query-core/src/query.ts | 10 +++++----- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/packages/query-core/src/__tests__/hydration.test.tsx b/packages/query-core/src/__tests__/hydration.test.tsx index ec92f5eb44d..ef138c2bf8d 100644 --- a/packages/query-core/src/__tests__/hydration.test.tsx +++ b/packages/query-core/src/__tests__/hydration.test.tsx @@ -1411,7 +1411,7 @@ describe('dehydration and rehydration', () => { const infiniteQueryState = dehydrated.queries.find( (q) => q.queryKey[0] === 'infinite', ) - expect(infiniteQueryState?.type).toBe('infinite') + expect(infiniteQueryState?.queryType).toBe('infinite') const hydrationCache = new QueryCache() const hydrationClient = new QueryClient({ queryCache: hydrationCache }) @@ -1488,7 +1488,7 @@ describe('dehydration and rehydration', () => { const dehydratedQuery = dehydrated.queries.find( (q) => q.queryKey[0] === 'infinite-type-restore', ) - expect(dehydratedQuery?.type).toBe('infinite') + expect(dehydratedQuery?.queryType).toBe('infinite') const clientCache = new QueryCache() const clientClient = new QueryClient({ queryCache: clientCache }) @@ -1497,7 +1497,7 @@ describe('dehydration and rehydration', () => { const hydratedQuery = clientCache.find({ queryKey: ['infinite-type-restore'], }) - expect(hydratedQuery?.type).toBe('infinite') + expect(hydratedQuery?.queryType).toBe('infinite') }) test('should preserve pages structure when refetching infinite query after hydration', async () => { @@ -1575,10 +1575,10 @@ describe('dehydration and rehydration', () => { hydrate(clientClient, dehydrated) const query = clientCache.find({ queryKey: ['infinite-setoptions-guard'] })! - expect(query.type).toBe('infinite') + expect(query.queryType).toBe('infinite') query.setOptions({ queryKey: ['infinite-setoptions-guard'] }) - expect(query.type).toBe('infinite') + expect(query.queryType).toBe('infinite') }) test('should restore all pages when refetching multi-page infinite query after hydration', async () => { diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 05eea72623f..3ba12d4f499 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -48,7 +48,7 @@ interface DehydratedQuery { state: QueryState promise?: Promise meta?: QueryMeta - type?: 'infinite' + queryType?: 'infinite' // This is only optional because older versions of Query might have dehydrated // without it which we need to handle for backwards compatibility. // This should be changed to required in the future. @@ -114,11 +114,11 @@ function dehydrateQuery( }, queryKey: query.queryKey, queryHash: query.queryHash, - type: query.type, ...(query.state.status === 'pending' && { promise: dehydratePromise(), }), ...(query.meta && { meta: query.meta }), + ...(query.queryType && { queryType: query.queryType }), } } @@ -211,7 +211,15 @@ export function hydrate( }) queries.forEach( - ({ queryKey, state, queryHash, meta, promise, dehydratedAt, type }) => { + ({ + queryKey, + state, + queryHash, + meta, + promise, + dehydratedAt, + queryType, + }) => { const syncData = promise ? tryResolveSync(promise) : undefined const rawData = state.data === undefined ? syncData?.data : state.data const data = rawData === undefined ? rawData : deserializeData(rawData) @@ -250,7 +258,7 @@ export function hydrate( queryKey, queryHash, meta, - _type: type, + _type: queryType, }, // Reset fetch status to idle to avoid // query being stuck in fetching state upon hydration diff --git a/packages/query-core/src/query.ts b/packages/query-core/src/query.ts index 95376c00fd9..d7af64d86ec 100644 --- a/packages/query-core/src/query.ts +++ b/packages/query-core/src/query.ts @@ -167,7 +167,7 @@ export class Query< queryHash: string options!: QueryOptions state: QueryState - #type?: 'infinite' + #queryType?: 'infinite' #initialState: QueryState #revertState?: QueryState @@ -197,8 +197,8 @@ export class Query< return this.options.meta } - get type() { - return this.#type + get queryType() { + return this.#queryType } get promise(): Promise | undefined { @@ -211,7 +211,7 @@ export class Query< this.options = { ...this.#defaultOptions, ...options } if (options?._type) { - this.#type = options._type + this.#queryType = options._type } this.updateGcTime(this.options.gcTime) @@ -521,7 +521,7 @@ export class Query< const context = createFetchContext() const behavior = - this.#type === 'infinite' + this.#queryType === 'infinite' ? (infiniteQueryBehavior( (this.options as { pages?: number }).pages, ) as QueryBehavior) From fe6f21c5366cabb0d79d7031e7c2962964aca2d2 Mon Sep 17 00:00:00 2001 From: TkDodo Date: Sat, 25 Apr 2026 10:50:48 +0200 Subject: [PATCH 10/10] fix: test -> it --- packages/query-core/src/__tests__/hydration.test.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/query-core/src/__tests__/hydration.test.tsx b/packages/query-core/src/__tests__/hydration.test.tsx index 95522c57bda..c64cb10da53 100644 --- a/packages/query-core/src/__tests__/hydration.test.tsx +++ b/packages/query-core/src/__tests__/hydration.test.tsx @@ -1386,7 +1386,7 @@ describe('dehydration and rehydration', () => { await originalPromise }) - test('should preserve queryType for infinite queries during hydration', async () => { + it('should preserve queryType for infinite queries during hydration', async () => { const queryCache = new QueryCache() const queryClient = new QueryClient({ queryCache }) @@ -1424,7 +1424,7 @@ describe('dehydration and rehydration', () => { expect((hydratedQuery?.state.data as any).pages).toHaveLength(1) }) - test('should attach infiniteQueryBehavior during hydration', async () => { + it('should attach infiniteQueryBehavior during hydration', async () => { const queryCache = new QueryCache() const queryClient = new QueryClient({ queryCache }) @@ -1466,7 +1466,7 @@ describe('dehydration and rehydration', () => { expect(result.pageParams).toHaveLength(1) }) - test('should restore infinite query type through dehydrate and hydrate cycle', async () => { + it('should restore infinite query type through dehydrate and hydrate cycle', async () => { const serverClient = new QueryClient({ queryCache: new QueryCache() }) await vi.waitFor(() => @@ -1500,7 +1500,7 @@ describe('dehydration and rehydration', () => { expect(hydratedQuery?.queryType).toBe('infinite') }) - test('should preserve pages structure when refetching infinite query after hydration', async () => { + it('should preserve pages structure when refetching infinite query after hydration', async () => { const serverClient = new QueryClient({ queryCache: new QueryCache() }) await vi.waitFor(() => @@ -1551,7 +1551,7 @@ describe('dehydration and rehydration', () => { expect(result.pages[0]).toHaveProperty('items') }) - test('should retain infinite query type after subsequent setOptions calls', async () => { + it('should retain infinite query type after subsequent setOptions calls', async () => { const serverClient = new QueryClient({ queryCache: new QueryCache() }) await vi.waitFor(() => @@ -1581,7 +1581,7 @@ describe('dehydration and rehydration', () => { expect(query.queryType).toBe('infinite') }) - test('should restore all pages when refetching multi-page infinite query after hydration', async () => { + it('should restore all pages when refetching multi-page infinite query after hydration', async () => { const serverClient = new QueryClient({ queryCache: new QueryCache() }) await vi.waitFor(() =>