From 11751a0618bfee7a0bd80427ea13a567c5bc9128 Mon Sep 17 00:00:00 2001 From: devchangjun Date: Mon, 13 Jul 2026 00:50:56 +0900 Subject: [PATCH 1/4] Protect restored custom-hash queries in devtools Exercise the full dehydrate, hydrate, and query-row rendering path for a per-query custom queryKeyHashFn. This locks the queryHash lookup behavior introduced by #10750 and covers the persistence failure reported in #6958. Constraint: The runtime lookup fix already shipped in #10750 Rejected: Reapply queryCache.get changes | current main already contains the implementation Confidence: high Scope-risk: narrow Tested: query-devtools 246 tests; ESLint; TypeScript current; Prettier Related: TanStack/query#6958 --- .../src/__tests__/Devtools.test.tsx | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/query-devtools/src/__tests__/Devtools.test.tsx b/packages/query-devtools/src/__tests__/Devtools.test.tsx index 5ed22c7181..5189ff9e9d 100644 --- a/packages/query-devtools/src/__tests__/Devtools.test.tsx +++ b/packages/query-devtools/src/__tests__/Devtools.test.tsx @@ -1,5 +1,11 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { QueryClient, QueryObserver, onlineManager } from '@tanstack/query-core' +import { + QueryClient, + QueryObserver, + dehydrate, + hydrate, + onlineManager, +} from '@tanstack/query-core' import { fireEvent, render } from '@solidjs/testing-library' import { createLocalStorage } from '@solid-primitives/storage' import { Devtools } from '../Devtools' @@ -235,6 +241,25 @@ describe('Devtools', () => { }) describe('query list', () => { + it('should render a hydrated query with a custom hash function', async () => { + await queryClient.fetchQuery({ + queryKey: ['posts'], + queryFn: () => [{ id: 1 }], + queryKeyHashFn: () => 'custom-posts-hash', + }) + const dehydratedState = dehydrate(queryClient) + + queryClient.clear() + queryClient = new QueryClient() + hydrate(queryClient, dehydratedState) + + const rendered = renderDevtools({ initialIsOpen: true }) + + expect( + rendered.getByLabelText(/Query key custom-posts-hash/), + ).toBeInTheDocument() + }) + it('should render a row for each query in the cache', () => { queryClient.setQueryData(['posts'], [{ id: 1 }]) queryClient.setQueryData(['users', 'me'], { id: 'u1' }) From be1c0f030e35381e9e5be655a3685896eb48a37d Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Mon, 27 Jul 2026 01:19:09 +0900 Subject: [PATCH 2/4] test(query-devtools/Devtools): use 'advanceTimersByTimeAsync' for consistency and remove redundant 'clear' --- packages/query-devtools/src/__tests__/Devtools.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/query-devtools/src/__tests__/Devtools.test.tsx b/packages/query-devtools/src/__tests__/Devtools.test.tsx index 5189ff9e9d..0d4738e7b2 100644 --- a/packages/query-devtools/src/__tests__/Devtools.test.tsx +++ b/packages/query-devtools/src/__tests__/Devtools.test.tsx @@ -242,14 +242,14 @@ describe('Devtools', () => { describe('query list', () => { it('should render a hydrated query with a custom hash function', async () => { - await queryClient.fetchQuery({ + queryClient.fetchQuery({ queryKey: ['posts'], queryFn: () => [{ id: 1 }], queryKeyHashFn: () => 'custom-posts-hash', }) + await vi.advanceTimersByTimeAsync(0) const dehydratedState = dehydrate(queryClient) - queryClient.clear() queryClient = new QueryClient() hydrate(queryClient, dehydratedState) From 9c54f6f6c8a9213e42f739f41945437b2b75309e Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Mon, 27 Jul 2026 01:21:33 +0900 Subject: [PATCH 3/4] test(query-devtools/Devtools): move custom-hash hydration test to the end of 'query list' --- .../src/__tests__/Devtools.test.tsx | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/query-devtools/src/__tests__/Devtools.test.tsx b/packages/query-devtools/src/__tests__/Devtools.test.tsx index 0d4738e7b2..3b3064d78f 100644 --- a/packages/query-devtools/src/__tests__/Devtools.test.tsx +++ b/packages/query-devtools/src/__tests__/Devtools.test.tsx @@ -241,25 +241,6 @@ describe('Devtools', () => { }) describe('query list', () => { - it('should render a hydrated query with a custom hash function', async () => { - queryClient.fetchQuery({ - queryKey: ['posts'], - queryFn: () => [{ id: 1 }], - queryKeyHashFn: () => 'custom-posts-hash', - }) - await vi.advanceTimersByTimeAsync(0) - const dehydratedState = dehydrate(queryClient) - - queryClient = new QueryClient() - hydrate(queryClient, dehydratedState) - - const rendered = renderDevtools({ initialIsOpen: true }) - - expect( - rendered.getByLabelText(/Query key custom-posts-hash/), - ).toBeInTheDocument() - }) - it('should render a row for each query in the cache', () => { queryClient.setQueryData(['posts'], [{ id: 1 }]) queryClient.setQueryData(['users', 'me'], { id: 'u1' }) @@ -335,6 +316,25 @@ describe('Devtools', () => { window.removeEventListener('@tanstack/query-devtools-event', listener) } }) + + it('should render a hydrated query with a custom hash function', async () => { + queryClient.fetchQuery({ + queryKey: ['posts'], + queryFn: () => [{ id: 1 }], + queryKeyHashFn: () => 'custom-posts-hash', + }) + await vi.advanceTimersByTimeAsync(0) + const dehydratedState = dehydrate(queryClient) + + queryClient = new QueryClient() + hydrate(queryClient, dehydratedState) + + const rendered = renderDevtools({ initialIsOpen: true }) + + expect( + rendered.getByLabelText(/Query key custom-posts-hash/), + ).toBeInTheDocument() + }) }) describe('view toggle', () => { From 7f10573d246ab9dd400c23fc6ae572aafc692a74 Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Mon, 27 Jul 2026 01:22:40 +0900 Subject: [PATCH 4/4] test(query-devtools/Devtools): align custom-hash test title with the 'when X' convention --- packages/query-devtools/src/__tests__/Devtools.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/query-devtools/src/__tests__/Devtools.test.tsx b/packages/query-devtools/src/__tests__/Devtools.test.tsx index 3b3064d78f..f73024502c 100644 --- a/packages/query-devtools/src/__tests__/Devtools.test.tsx +++ b/packages/query-devtools/src/__tests__/Devtools.test.tsx @@ -317,7 +317,7 @@ describe('Devtools', () => { } }) - it('should render a hydrated query with a custom hash function', async () => { + it('should render a query row when a hydrated query uses a custom hash function', async () => { queryClient.fetchQuery({ queryKey: ['posts'], queryFn: () => [{ id: 1 }],