From b548ea7c61107d01a5523f5c9f7320bb3f9b5436 Mon Sep 17 00:00:00 2001 From: grzdev Date: Sun, 6 Sep 2026 01:30:05 +0100 Subject: [PATCH] fix(vue-query-devtools): update client when prop changes --- .changeset/quiet-vue-clients.md | 5 ++ .../src/__tests__/client.test.ts | 81 +++++++++++++++++++ packages/vue-query-devtools/src/devtools.vue | 1 + .../vue-query-devtools/src/devtoolsPanel.vue | 1 + 4 files changed, 88 insertions(+) create mode 100644 .changeset/quiet-vue-clients.md create mode 100644 packages/vue-query-devtools/src/__tests__/client.test.ts diff --git a/.changeset/quiet-vue-clients.md b/.changeset/quiet-vue-clients.md new file mode 100644 index 00000000000..754f2522059 --- /dev/null +++ b/.changeset/quiet-vue-clients.md @@ -0,0 +1,5 @@ +--- +"@tanstack/vue-query-devtools": patch +--- + +Update floating and embedded devtools when the client prop changes, preserving the initially resolved client as the fallback when the override is removed. diff --git a/packages/vue-query-devtools/src/__tests__/client.test.ts b/packages/vue-query-devtools/src/__tests__/client.test.ts new file mode 100644 index 00000000000..07c71065263 --- /dev/null +++ b/packages/vue-query-devtools/src/__tests__/client.test.ts @@ -0,0 +1,81 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import { createApp, h, nextTick, shallowRef } from 'vue' +import { QueryClient, VueQueryPlugin } from '@tanstack/vue-query' +import Devtools from '../devtools.vue' +import DevtoolsPanel from '../devtoolsPanel.vue' +import type { App } from 'vue' + +const { setClient, mount, unmount } = vi.hoisted(() => ({ + setClient: vi.fn(), + mount: vi.fn(), + unmount: vi.fn(), +})) + +vi.mock('@tanstack/query-devtools', () => { + class MockDevtools { + setClient = setClient + mount = mount + unmount = unmount + setButtonPosition = vi.fn() + setPosition = vi.fn() + setInitialIsOpen = vi.fn() + setErrorTypes = vi.fn() + setTheme = vi.fn() + setOnClose = vi.fn() + } + return { + TanstackQueryDevtools: MockDevtools, + TanstackQueryDevtoolsPanel: MockDevtools, + } +}) + +describe.each([ + ['floating', Devtools], + ['embedded', DevtoolsPanel], +] as const)('%s devtools client', (_, component) => { + let app: App | undefined + let container: HTMLDivElement | undefined + + afterEach(() => { + app?.unmount() + container?.remove() + vi.clearAllMocks() + }) + + it('switches explicit clients without remounting or requiring a provider', async () => { + const first = new QueryClient() + const second = new QueryClient() + const client = shallowRef(first) + container = document.createElement('div') + app = createApp(() => h(component, { client: client.value })) + app.mount(container) + + expect(setClient).toHaveBeenLastCalledWith(first) + client.value = second + await nextTick() + + expect(setClient).toHaveBeenLastCalledWith(second) + expect(mount).toHaveBeenCalledTimes(1) + expect(unmount).not.toHaveBeenCalled() + }) + + it('returns to the initial context client after an override is removed', async () => { + const contextClient = new QueryClient() + const override = new QueryClient() + const client = shallowRef() + container = document.createElement('div') + app = createApp(() => h(component, { client: client.value })) + app.use(VueQueryPlugin, { queryClient: contextClient }) + app.mount(container) + + expect(setClient).toHaveBeenLastCalledWith(contextClient) + client.value = override + await nextTick() + expect(setClient).toHaveBeenLastCalledWith(override) + + client.value = undefined + await nextTick() + expect(setClient).toHaveBeenLastCalledWith(contextClient) + expect(mount).toHaveBeenCalledTimes(1) + }) +}) diff --git a/packages/vue-query-devtools/src/devtools.vue b/packages/vue-query-devtools/src/devtools.vue index a46b7adbac0..7e8743e24fd 100644 --- a/packages/vue-query-devtools/src/devtools.vue +++ b/packages/vue-query-devtools/src/devtools.vue @@ -24,6 +24,7 @@ const devtools = new TanstackQueryDevtools({ }) watchEffect(() => { + devtools.setClient(props.client || client) devtools.setButtonPosition(props.buttonPosition || 'bottom-right') devtools.setPosition(props.position || 'bottom') devtools.setInitialIsOpen(props.initialIsOpen) diff --git a/packages/vue-query-devtools/src/devtoolsPanel.vue b/packages/vue-query-devtools/src/devtoolsPanel.vue index 80884daa6ec..c2cd542bc01 100644 --- a/packages/vue-query-devtools/src/devtoolsPanel.vue +++ b/packages/vue-query-devtools/src/devtoolsPanel.vue @@ -31,6 +31,7 @@ const devtools = new TanstackQueryDevtoolsPanel({ }) watchEffect(() => { + devtools.setClient(props.client || client) devtools.setOnClose(props.onClose ?? (() => {})) devtools.setErrorTypes(props.errorTypes || []) devtools.setTheme(props.theme)